1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/components/apphost.js

440 lines
14 KiB
JavaScript
Raw Normal View History

2020-05-04 12:44:12 +02:00
define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) {
'use strict';
2018-10-23 00:48:22 +03:00
function getBaseProfileOptions(item) {
var disableHlsVideoAudioCodecs = [];
2019-03-17 21:52:56 +00:00
if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) {
if (browser.edge || browser.msie) {
2020-05-04 12:44:12 +02:00
disableHlsVideoAudioCodecs.push('mp3');
2019-03-17 21:52:56 +00:00
}
2020-05-04 12:44:12 +02:00
disableHlsVideoAudioCodecs.push('ac3');
disableHlsVideoAudioCodecs.push('eac3');
disableHlsVideoAudioCodecs.push('opus');
2018-10-23 00:48:22 +03:00
}
2019-03-17 21:52:56 +00:00
return {
enableMkvProgressive: false,
disableHlsVideoAudioCodecs: disableHlsVideoAudioCodecs
};
2018-10-23 00:48:22 +03:00
}
function getDeviceProfileForWindowsUwp(item) {
2019-03-17 21:52:56 +00:00
return new Promise(function (resolve, reject) {
2020-05-04 12:44:12 +02:00
require(['browserdeviceprofile', 'environments/windows-uwp/mediacaps'], function (profileBuilder, uwpMediaCaps) {
2018-10-23 00:48:22 +03:00
var profileOptions = getBaseProfileOptions(item);
2019-03-17 21:52:56 +00:00
profileOptions.supportsDts = uwpMediaCaps.supportsDTS();
profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby();
profileOptions.audioChannels = uwpMediaCaps.getAudioChannels();
resolve(profileBuilder(profileOptions));
});
});
2018-10-23 00:48:22 +03:00
}
function getDeviceProfile(item, options) {
2019-03-17 21:52:56 +00:00
options = options || {};
if (self.Windows) {
return getDeviceProfileForWindowsUwp(item);
}
2019-03-17 23:23:45 +00:00
return new Promise(function (resolve) {
2020-05-04 12:44:12 +02:00
require(['browserdeviceprofile'], function (profileBuilder) {
2019-03-17 23:23:45 +00:00
var profile;
if (window.NativeShell) {
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
} else {
var builderOpts = getBaseProfileOptions(item);
2020-05-04 12:44:12 +02:00
builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin'));
profile = profileBuilder(builderOpts);
2019-03-17 21:52:56 +00:00
}
resolve(profile);
});
});
2018-10-23 00:48:22 +03:00
}
function escapeRegExp(str) {
2020-05-04 12:44:12 +02:00
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
2018-10-23 00:48:22 +03:00
}
function replaceAll(originalString, strReplace, strWith) {
2019-03-17 21:52:56 +00:00
var strReplace2 = escapeRegExp(strReplace);
2020-05-04 12:44:12 +02:00
var reg = new RegExp(strReplace2, 'ig');
2019-03-17 21:52:56 +00:00
return originalString.replace(reg, strWith);
2018-10-23 00:48:22 +03:00
}
function generateDeviceId() {
var keys = [];
2019-03-17 21:52:56 +00:00
if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) {
2020-05-04 12:44:12 +02:00
var result = replaceAll(btoa(keys.join('|')), '=', '1');
2019-03-17 21:52:56 +00:00
return Promise.resolve(result);
2018-10-23 00:48:22 +03:00
}
2019-03-17 21:52:56 +00:00
return Promise.resolve(new Date().getTime());
2018-10-23 00:48:22 +03:00
}
function getDeviceId() {
2020-05-04 12:44:12 +02:00
var key = '_deviceId2';
2019-03-17 21:52:56 +00:00
var deviceId = appSettings.get(key);
if (deviceId) {
return Promise.resolve(deviceId);
}
return generateDeviceId().then(function (deviceId) {
appSettings.set(key, deviceId);
return deviceId;
});
2018-10-23 00:48:22 +03:00
}
function getDeviceName() {
var deviceName;
2020-05-04 12:44:12 +02:00
deviceName = browser.tizen ? 'Samsung Smart TV' : browser.web0s ? 'LG Smart TV' : browser.operaTv ? 'Opera TV' : browser.xboxOne ? 'Xbox One' : browser.ps4 ? 'Sony PS4' : browser.chrome ? 'Chrome' : browser.edge ? 'Edge' : browser.firefox ? 'Firefox' : browser.msie ? 'Internet Explorer' : browser.opera ? 'Opera' : browser.safari ? 'Safari' : 'Web Browser';
2019-03-17 21:52:56 +00:00
if (browser.ipad) {
2020-05-04 12:44:12 +02:00
deviceName += ' iPad';
2019-03-17 21:52:56 +00:00
} else {
if (browser.iphone) {
2020-05-04 12:44:12 +02:00
deviceName += ' iPhone';
2019-03-17 21:52:56 +00:00
} else {
if (browser.android) {
2020-05-04 12:44:12 +02:00
deviceName += ' Android';
2019-03-17 21:52:56 +00:00
}
}
}
return deviceName;
2018-10-23 00:48:22 +03:00
}
function supportsVoiceInput() {
2019-03-17 21:52:56 +00:00
if (!browser.tv) {
return window.SpeechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition || window.oSpeechRecognition || window.msSpeechRecognition;
}
return false;
2018-10-23 00:48:22 +03:00
}
function supportsFullscreen() {
2019-03-17 21:52:56 +00:00
if (browser.tv) {
return false;
}
2018-10-23 00:48:22 +03:00
var element = document.documentElement;
2020-05-04 12:44:12 +02:00
return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen;
2018-10-23 00:48:22 +03:00
}
function getSyncProfile() {
2019-03-17 23:23:45 +00:00
return new Promise(function (resolve) {
2020-05-04 12:44:12 +02:00
require(['browserdeviceprofile', 'appSettings'], function (profileBuilder, appSettings) {
2019-03-17 23:23:45 +00:00
var profile;
if (window.NativeShell) {
profile = window.NativeShell.AppHost.getSyncProfile(profileBuilder, appSettings);
} else {
profile = profileBuilder();
profile.MaxStaticMusicBitrate = appSettings.maxStaticMusicBitrate();
}
2019-03-17 21:52:56 +00:00
resolve(profile);
});
});
2018-10-23 00:48:22 +03:00
}
function getDefaultLayout() {
2020-05-04 12:44:12 +02:00
return 'desktop';
2018-10-23 00:48:22 +03:00
}
function supportsHtmlMediaAutoplay() {
2019-03-17 21:52:56 +00:00
if (browser.edgeUwp || browser.tizen || browser.web0s || browser.orsay || browser.operaTv || browser.ps4 || browser.xboxOne) {
return true;
}
if (browser.mobile) {
return false;
}
2020-01-24 18:45:37 +09:00
return true;
2018-10-23 00:48:22 +03:00
}
function supportsCue() {
2018-10-23 00:48:22 +03:00
try {
2020-05-04 12:44:12 +02:00
var video = document.createElement('video');
var style = document.createElement('style');
2020-05-04 12:44:12 +02:00
style.textContent = 'video::cue {background: inherit}';
2019-03-17 21:52:56 +00:00
document.body.appendChild(style);
document.body.appendChild(video);
2020-05-04 12:44:12 +02:00
var cue = window.getComputedStyle(video, '::cue').background;
2019-03-17 21:52:56 +00:00
document.body.removeChild(style);
document.body.removeChild(video);
2019-03-17 21:52:56 +00:00
return !!cue.length;
2018-10-23 00:48:22 +03:00
} catch (err) {
2020-05-04 12:44:12 +02:00
console.error('error detecting cue support: ' + err);
2019-03-17 21:52:56 +00:00
return false;
2018-10-23 00:48:22 +03:00
}
}
function onAppVisible() {
2019-01-24 22:26:24 +09:00
if (isHidden) {
isHidden = false;
2020-05-04 12:44:12 +02:00
console.debug('triggering app resume event');
events.trigger(appHost, 'resume');
2019-01-24 22:26:24 +09:00
}
2018-10-23 00:48:22 +03:00
}
function onAppHidden() {
2019-01-24 22:26:24 +09:00
if (!isHidden) {
isHidden = true;
2020-05-04 12:44:12 +02:00
console.debug('app is hidden');
2019-01-24 22:26:24 +09:00
}
2018-10-23 00:48:22 +03:00
}
2019-03-17 21:52:56 +00:00
var supportedFeatures = function () {
var features = [];
2019-03-17 21:52:56 +00:00
if (navigator.share) {
2020-05-04 12:44:12 +02:00
features.push('sharing');
2019-03-17 21:52:56 +00:00
}
if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) {
2020-05-04 12:44:12 +02:00
features.push('filedownload');
2019-03-17 21:52:56 +00:00
}
if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) {
2020-05-04 12:44:12 +02:00
features.push('exit');
2019-03-17 21:52:56 +00:00
} else {
2020-05-04 12:44:12 +02:00
features.push('exitmenu');
features.push('plugins');
2019-03-17 21:52:56 +00:00
}
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) {
2020-05-04 12:44:12 +02:00
features.push('externallinks');
features.push('externalpremium');
2019-03-17 21:52:56 +00:00
}
if (!browser.operaTv) {
2020-05-04 12:44:12 +02:00
features.push('externallinkdisplay');
2019-03-17 21:52:56 +00:00
}
if (supportsVoiceInput()) {
2020-05-04 12:44:12 +02:00
features.push('voiceinput');
2019-03-17 21:52:56 +00:00
}
if (supportsHtmlMediaAutoplay()) {
2020-05-04 12:44:12 +02:00
features.push('htmlaudioautoplay');
features.push('htmlvideoautoplay');
2019-03-17 21:52:56 +00:00
}
if (browser.edgeUwp) {
2020-05-04 12:44:12 +02:00
features.push('sync');
2019-03-17 21:52:56 +00:00
}
if (supportsFullscreen()) {
2020-05-04 12:44:12 +02:00
features.push('fullscreenchange');
2019-03-17 21:52:56 +00:00
}
if (browser.chrome || browser.edge && !browser.slow) {
if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) {
2020-05-04 12:44:12 +02:00
features.push('imageanalysis');
2019-03-17 21:52:56 +00:00
}
}
if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) {
2020-05-04 12:44:12 +02:00
features.push('physicalvolumecontrol');
2019-03-17 21:52:56 +00:00
}
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
2020-05-04 12:44:12 +02:00
features.push('remotecontrol');
2019-03-17 21:52:56 +00:00
}
if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) {
2020-05-04 12:44:12 +02:00
features.push('remotevideo');
2019-03-17 21:52:56 +00:00
}
2020-05-04 12:44:12 +02:00
features.push('displaylanguage');
features.push('otherapppromotions');
features.push('displaymode');
features.push('targetblank');
features.push('screensaver');
2019-03-17 21:52:56 +00:00
2020-04-02 03:51:22 +09:00
webSettings.enableMultiServer().then(enabled => {
2020-05-04 12:44:12 +02:00
if (enabled) features.push('multiserver');
});
2020-02-16 12:17:13 +09:00
2020-03-26 17:22:57 +03:00
if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) {
2020-05-04 12:44:12 +02:00
features.push('subtitleappearancesettings');
2019-03-17 21:52:56 +00:00
}
2020-03-26 17:22:57 +03:00
if (!browser.orsay) {
2020-05-04 12:44:12 +02:00
features.push('subtitleburnsettings');
2019-03-17 21:52:56 +00:00
}
if (!browser.tv && !browser.ps4 && !browser.xboxOne) {
2020-05-04 12:44:12 +02:00
features.push('fileinput');
2019-03-17 21:52:56 +00:00
}
if (browser.chrome) {
2020-05-04 12:44:12 +02:00
features.push('chromecast');
2019-03-17 21:52:56 +00:00
}
return features;
}();
2019-03-17 21:52:56 +00:00
2020-01-21 12:51:33 +03:00
/**
* Do exit according to platform
*/
function doExit() {
try {
if (window.NativeShell) {
window.NativeShell.AppHost.exit();
} else if (browser.tizen) {
tizen.application.getCurrentApplication().exit();
} else if (browser.web0s) {
webOS.platformBack();
} else {
window.close();
}
} catch (err) {
2020-05-04 12:44:12 +02:00
console.error('error closing application: ' + err);
2020-01-21 12:51:33 +03:00
}
}
var exitPromise;
/**
* Ask user for exit
*/
function askForExit() {
2020-02-26 00:19:04 -05:00
if (exitPromise) {
2020-01-21 12:51:33 +03:00
return;
}
2020-05-04 12:44:12 +02:00
require(['actionsheet'], function (actionsheet) {
2020-01-21 12:51:33 +03:00
exitPromise = actionsheet.show({
2020-05-04 12:44:12 +02:00
title: globalize.translate('MessageConfirmAppExit'),
2020-01-21 14:04:26 +03:00
items: [
2020-05-04 12:44:12 +02:00
{id: 'yes', name: globalize.translate('Yes')},
{id: 'no', name: globalize.translate('No')}
2020-01-21 14:04:26 +03:00
]
}).then(function (value) {
2020-05-04 12:44:12 +02:00
if (value === 'yes') {
2020-01-21 14:04:26 +03:00
doExit();
}
}).finally(function () {
exitPromise = null;
});
2020-01-21 12:51:33 +03:00
});
}
var deviceId;
var deviceName;
2020-05-04 12:44:12 +02:00
var appName = 'Jellyfin Web';
var appVersion = '10.6.0';
var appHost = {
2019-03-17 21:52:56 +00:00
getWindowState: function () {
2020-05-04 12:44:12 +02:00
return document.windowState || 'Normal';
},
2019-03-17 21:52:56 +00:00
setWindowState: function (state) {
2020-05-04 12:44:12 +02:00
alert('setWindowState is not supported and should not be called');
},
2019-03-17 21:52:56 +00:00
exit: function () {
2020-01-21 12:51:33 +03:00
if (!!window.appMode && browser.tizen) {
askForExit();
2019-03-17 21:52:56 +00:00
} else {
2020-01-21 12:51:33 +03:00
doExit();
2019-03-17 21:52:56 +00:00
}
},
2019-03-17 21:52:56 +00:00
supports: function (command) {
2019-03-17 23:23:45 +00:00
if (window.NativeShell) {
return window.NativeShell.AppHost.supports(command);
}
2019-03-17 21:52:56 +00:00
return -1 !== supportedFeatures.indexOf(command.toLowerCase());
},
preferVisualCards: browser.android || browser.chrome,
2020-05-04 12:44:12 +02:00
moreIcon: browser.android ? 'more_vert' : 'more_horiz',
getSyncProfile: getSyncProfile,
2019-03-17 23:23:45 +00:00
getDefaultLayout: function () {
if (window.NativeShell) {
return window.NativeShell.AppHost.getDefaultLayout();
}
return getDefaultLayout();
2019-03-17 23:23:45 +00:00
},
getDeviceProfile: getDeviceProfile,
2019-03-17 21:52:56 +00:00
init: function () {
2019-03-17 23:23:45 +00:00
if (window.NativeShell) {
return window.NativeShell.AppHost.init();
}
2019-03-17 21:52:56 +00:00
deviceName = getDeviceName();
getDeviceId().then(function (id) {
deviceId = id;
});
},
2019-03-17 21:52:56 +00:00
deviceName: function () {
2019-03-17 23:23:45 +00:00
return window.NativeShell ? window.NativeShell.AppHost.deviceName() : deviceName;
},
2019-03-17 21:52:56 +00:00
deviceId: function () {
2019-03-17 23:23:45 +00:00
return window.NativeShell ? window.NativeShell.AppHost.deviceId() : deviceId;
},
2019-03-17 21:52:56 +00:00
appName: function () {
return window.NativeShell ? window.NativeShell.AppHost.appName() : appName;
},
2019-03-17 21:52:56 +00:00
appVersion: function () {
2019-03-17 23:23:45 +00:00
return window.NativeShell ? window.NativeShell.AppHost.appVersion() : appVersion;
},
2019-03-17 21:52:56 +00:00
getPushTokenInfo: function () {
return {};
},
2019-03-17 21:52:56 +00:00
setThemeColor: function (color) {
2020-05-04 12:44:12 +02:00
var metaThemeColor = document.querySelector('meta[name=theme-color]');
2019-03-17 21:52:56 +00:00
if (metaThemeColor) {
2020-05-04 12:44:12 +02:00
metaThemeColor.setAttribute('content', color);
2019-03-17 21:52:56 +00:00
}
},
2019-03-17 21:52:56 +00:00
setUserScalable: function (scalable) {
if (!browser.tv) {
2020-05-04 12:44:12 +02:00
var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
document.querySelector('meta[name=viewport]').setAttribute('content', att);
2018-10-23 00:48:22 +03:00
}
}
};
var isHidden = false;
var hidden;
var visibilityChange;
2019-03-17 21:52:56 +00:00
2020-05-04 12:44:12 +02:00
if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */
hidden = 'hidden';
visibilityChange = 'visibilitychange';
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden';
visibilityChange = 'webkitvisibilitychange';
2019-03-17 21:52:56 +00:00
}
document.addEventListener(visibilityChange, function () {
/* eslint-disable-next-line compat/compat */
if (document[hidden]) {
onAppHidden();
} else {
onAppVisible();
}
}, false);
2019-03-17 21:52:56 +00:00
2019-01-24 22:26:24 +09:00
if (self.addEventListener) {
2020-05-04 12:44:12 +02:00
self.addEventListener('focus', onAppVisible);
self.addEventListener('blur', onAppHidden);
2019-01-24 22:26:24 +09:00
}
2019-03-17 21:52:56 +00:00
return appHost;
});