123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- const viewdata = JSON.parse(window.atob("@@data@@"));
- const features = [
- "filedownload",
- "displaylanguage",
- "htmlaudioautoplay",
- "htmlvideoautoplay",
- "externallinks",
- "clientsettings",
- "multiserver",
- "exitmenu",
- "remotecontrol",
- "fullscreenchange",
- "filedownload",
- "remotevideo",
- "displaymode",
- "screensaver",
- "fileinput"
- ];
- const plugins = [
- 'mpvVideoPlayer',
- 'mpvAudioPlayer',
- 'jmpInputPlugin',
- 'jmpUpdatePlugin',
- 'jellyscrubPlugin',
- 'skipIntroPlugin'
- ];
- function loadScript(src) {
- return new Promise((resolve, reject) => {
- const s = document.createElement('script');
- s.src = src;
- s.onload = resolve;
- s.onerror = reject;
- document.head.appendChild(s);
- });
- }
- // Add plugin loaders
- for (const plugin of plugins) {
- window[plugin] = async () => {
- await loadScript(`${viewdata.scriptPath}${plugin}.js`);
- return window["_" + plugin];
- };
- }
- window.NativeShell = {
- openUrl(url, target) {
- window.api.system.openExternalUrl(url);
- },
- downloadFile(downloadInfo) {
- window.api.system.openExternalUrl(downloadInfo.url);
- },
- openClientSettings() {
- showSettingsModal();
- },
- getPlugins() {
- return plugins;
- }
- };
- function getDeviceProfile() {
- const CodecProfiles = [
- {
- 'Type': 'Video',
- 'Conditions': [
- {
- 'Condition': 'NotEquals',
- 'Property': 'VideoRangeType',
- 'Value': 'DOVI'
- }
- ]
- }
- ];
- if (viewdata.force_transcode_hdr) {
- CodecProfiles.push({
- 'Type': 'Video',
- 'Conditions': [
- {
- 'Condition': 'Equals',
- 'Property': 'VideoRangeType',
- 'Value': 'SDR'
- }
- ]
- });
- }
- return {
- 'Name': 'Jellyfin Media Player',
- 'MaxStaticBitrate': 1000000000,
- 'MusicStreamingTranscodingBitrate': 1280000,
- 'TimelineOffsetSeconds': 5,
- 'TranscodingProfiles': [
- {'Type': 'Audio'},
- {
- 'Container': 'ts',
- 'Type': 'Video',
- 'Protocol': 'hls',
- 'AudioCodec': 'aac,mp3,ac3,opus,flac,vorbis',
- 'VideoCodec': viewdata.allow_transcode_to_hevc
- ? 'h264,h265,hevc,mpeg4,mpeg2video'
- : 'h264,mpeg4,mpeg2video',
- 'MaxAudioChannels': '6'
- },
- {'Container': 'jpeg', 'Type': 'Photo'}
- ],
- 'DirectPlayProfiles': [{'Type': 'Video'}, {'Type': 'Audio'}, {'Type': 'Photo'}],
- 'ResponseProfiles': [],
- 'ContainerProfiles': [],
- CodecProfiles,
- 'SubtitleProfiles': [
- {'Format': 'srt', 'Method': 'External'},
- {'Format': 'srt', 'Method': 'Embed'},
- {'Format': 'ass', 'Method': 'External'},
- {'Format': 'ass', 'Method': 'Embed'},
- {'Format': 'sub', 'Method': 'Embed'},
- {'Format': 'sub', 'Method': 'External'},
- {'Format': 'ssa', 'Method': 'Embed'},
- {'Format': 'ssa', 'Method': 'External'},
- {'Format': 'smi', 'Method': 'Embed'},
- {'Format': 'smi', 'Method': 'External'},
- {'Format': 'pgssub', 'Method': 'Embed'},
- {'Format': 'dvdsub', 'Method': 'Embed'},
- {'Format': 'dvbsub', 'Method': 'Embed'},
- {'Format': 'pgs', 'Method': 'Embed'}
- ]
- };
- }
- async function createApi() {
- await loadScript('qrc:///qtwebchannel/qwebchannel.js');
- const channel = await new Promise((resolve) => {
- /*global QWebChannel */
- new QWebChannel(window.qt.webChannelTransport, resolve);
- });
- return channel.objects;
- }
- window.NativeShell.AppHost = {
- init() {
- window.apiPromise = createApi();
- (async () => {
- window.api = await window.apiPromise;
- })();
- },
- getDefaultLayout() {
- return viewdata.mode;
- },
- supports(command) {
- return features.includes(command.toLowerCase());
- },
- getDeviceProfile,
- getSyncProfile: getDeviceProfile,
- appName() {
- return "Jellyfin Media Player";
- },
- appVersion() {
- return navigator.userAgent.split(" ")[1];
- },
- deviceName() {
- return viewdata.deviceName;
- },
- exit() {
- window.api.system.exit();
- }
- };
- async function showSettingsModal() {
- let settings = await new Promise(resolve => {
- window.api.settings.settingDescriptions(resolve);
- });
- const modalContainer = document.createElement("div");
- modalContainer.className = "dialogContainer";
- modalContainer.style.backgroundColor = "rgba(0,0,0,0.5)";
- modalContainer.addEventListener("click", e => {
- if (e.target == modalContainer) {
- modalContainer.remove();
- }
- });
- document.body.appendChild(modalContainer);
- const modalContainer2 = document.createElement("div");
- modalContainer2.className = "focuscontainer dialog dialog-fixedSize dialog-small formDialog opened";
- modalContainer.appendChild(modalContainer2);
- const modalHeader = document.createElement("div");
- modalHeader.className = "formDialogHeader";
- modalContainer2.appendChild(modalHeader);
- const title = document.createElement("h3");
- title.className = "formDialogHeaderTitle";
- title.textContent = "Jellyfin Media Player Settings";
- modalHeader.appendChild(title);
-
- const modalContents = document.createElement("div");
- modalContents.className = "formDialogContent smoothScrollY";
- modalContents.style.paddingTop = "2em";
- modalContents.style.marginBottom = "6.2em";
- modalContainer2.appendChild(modalContents);
-
- for (let section of settings) {
- const group = document.createElement("fieldset");
- group.className = "editItemMetadataForm editMetadataForm dialog-content-centered";
- group.style.border = 0;
- group.style.outline = 0;
- modalContents.appendChild(group);
- const createSection = async (clear) => {
- if (clear) {
- group.innerHTML = "";
- }
- const values = await new Promise(resolve => {
- window.api.settings.allValues(section.key, resolve);
- });
- const legend = document.createElement("legend");
- const legendHeader = document.createElement("h2");
- legendHeader.textContent = section.key;
- legendHeader.style.textTransform = "capitalize";
- legend.appendChild(legendHeader);
- if (section.key == "plugins") {
- const legendSubHeader = document.createElement("h4");
- legendSubHeader.textContent = "Plugins are UNOFFICIAL and require a restart to take effect.";
- legend.appendChild(legendSubHeader);
- }
- group.appendChild(legend);
- for (const setting of section.settings) {
- const label = document.createElement("label");
- label.className = "inputContainer";
- label.style.marginBottom = "1.8em";
- label.style.display = "block";
- label.style.textTransform = "capitalize";
- if (setting.options) {
- const safeValues = {};
- const control = document.createElement("select");
- control.className = "emby-select-withcolor emby-select";
- for (const option of setting.options) {
- safeValues[String(option.value)] = option.value;
- const opt = document.createElement("option");
- opt.value = option.value;
- opt.selected = option.value == values[setting.key];
- let optionName = option.title;
- const swTest = `${section.key}.${setting.key}.`;
- const swTest2 = `${section.key}.`;
- if (optionName.startsWith(swTest)) {
- optionName = optionName.substring(swTest.length);
- } else if (optionName.startsWith(swTest2)) {
- optionName = optionName.substring(swTest2.length);
- }
- opt.appendChild(document.createTextNode(optionName));
- control.appendChild(opt);
- }
- control.addEventListener("change", async (e) => {
- await new Promise(resolve => {
- window.api.settings.setValue(section.key, setting.key, safeValues[e.target.value], resolve);
- });
- if (setting.key == "devicetype") {
- section = (await new Promise(resolve => {
- window.api.settings.settingDescriptions(resolve);
- })).filter(x => x.key == section.key)[0];
- createSection(true);
- }
- });
- const labelText = document.createElement('label');
- labelText.className = "inputLabel";
- labelText.textContent = setting.key + ": ";
- label.appendChild(labelText);
- label.appendChild(control);
- } else {
- const control = document.createElement("input");
- control.type = "checkbox";
- control.checked = values[setting.key];
- control.addEventListener("change", e => {
- window.api.settings.setValue(section.key, setting.key, e.target.checked);
- });
- label.appendChild(control);
- label.appendChild(document.createTextNode(" " + setting.key));
- }
- group.appendChild(label);
- }
- };
- createSection();
- }
- const closeContainer = document.createElement("div");
- closeContainer.className = "formDialogFooter";
- modalContents.appendChild(closeContainer);
- const close = document.createElement("button");
- close.className = "raised button-cancel block btnCancel formDialogFooterItem emby-button";
- close.textContent = "Close"
- close.addEventListener("click", () => {
- modalContainer.remove();
- });
- closeContainer.appendChild(close);
- }
|