mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into hadicharara/added-support-for-rtl-layouts
This commit is contained in:
commit
104ad71ea7
128 changed files with 1242 additions and 1454 deletions
|
@ -19,25 +19,14 @@ function isTv() {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (isWeb0s()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return isWeb0s();
|
||||
}
|
||||
|
||||
function isWeb0s() {
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
|
||||
if (userAgent.indexOf('netcast') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (userAgent.indexOf('web0s') !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return userAgent.indexOf('netcast') !== -1
|
||||
|| userAgent.indexOf('web0s') !== -1;
|
||||
}
|
||||
|
||||
function isMobile(userAgent) {
|
||||
|
@ -84,11 +73,7 @@ function hasKeyboard(browser) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!browser.tv;
|
||||
}
|
||||
|
||||
function iOSversion() {
|
||||
|
@ -324,11 +309,9 @@ if (browser.mobile || browser.tv) {
|
|||
browser.slow = true;
|
||||
}
|
||||
|
||||
if (typeof document !== 'undefined') {
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0)) {
|
||||
browser.touch = true;
|
||||
}
|
||||
/* eslint-disable-next-line compat/compat */
|
||||
if (typeof document !== 'undefined' && ('ontouchstart' in window) || (navigator.maxTouchPoints > 0)) {
|
||||
browser.touch = true;
|
||||
}
|
||||
|
||||
browser.keyboard = hasKeyboard(browser);
|
||||
|
|
|
@ -53,12 +53,8 @@ import browser from './browser';
|
|||
}
|
||||
|
||||
const media = document.createElement('video');
|
||||
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
|
||||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!(media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
|
||||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, ''));
|
||||
}
|
||||
|
||||
function canPlayHlsWithMSE() {
|
||||
|
@ -110,7 +106,7 @@ import browser from './browser';
|
|||
function canPlayAudioFormat(format) {
|
||||
let typeString;
|
||||
|
||||
if (format === 'flac') {
|
||||
if (format === 'flac' || format === 'asf') {
|
||||
if (browser.tizen || browser.web0s || browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
|
@ -118,10 +114,6 @@ import browser from './browser';
|
|||
if (browser.tizen || browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'asf') {
|
||||
if (browser.tizen || browser.web0s || browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
} else if (format === 'opus') {
|
||||
if (browser.web0s) {
|
||||
// canPlayType lies about OPUS support
|
||||
|
@ -163,17 +155,11 @@ import browser from './browser';
|
|||
return true;
|
||||
}
|
||||
|
||||
if (browser.edgeUwp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!browser.edgeUwp;
|
||||
}
|
||||
|
||||
function testCanPlayAv1(videoTestElement) {
|
||||
if (browser.tizenVersion >= 5.5) {
|
||||
return true;
|
||||
} else if (browser.web0sVersion >= 5) {
|
||||
if (browser.tizenVersion >= 5.5 || browser.web0sVersion >= 5) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -199,6 +185,7 @@ import browser from './browser';
|
|||
|
||||
switch (container) {
|
||||
case 'asf':
|
||||
case 'wmv':
|
||||
supported = browser.tizen || browser.web0s || browser.edgeUwp;
|
||||
videoAudioCodecs = [];
|
||||
break;
|
||||
|
@ -241,10 +228,6 @@ import browser from './browser';
|
|||
videoCodecs.push('mpeg2video');
|
||||
}
|
||||
break;
|
||||
case 'wmv':
|
||||
supported = browser.tizen || browser.web0s || browser.edgeUwp;
|
||||
videoAudioCodecs = [];
|
||||
break;
|
||||
case 'ts':
|
||||
supported = testCanPlayTs();
|
||||
videoCodecs.push('h264');
|
||||
|
@ -822,12 +805,12 @@ import browser from './browser';
|
|||
maxH264Level = 52;
|
||||
}
|
||||
|
||||
if (browser.tizen ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
|
||||
if ((browser.tizen ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, ''))
|
||||
// These tests are passing in safari, but playback is failing
|
||||
if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) {
|
||||
h264Profiles += '|high 10';
|
||||
}
|
||||
&& !browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile
|
||||
) {
|
||||
h264Profiles += '|high 10';
|
||||
}
|
||||
|
||||
let maxHevcLevel = 120;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { af, arDZ, be, bg, bn, ca, cs, cy, da, de, el, enGB, enUS, eo, es, et, faIR, fi, fr, frCA, gl, he, hi, hr, hu, id, is, it, ja, kk, ko, lt, lv, ms, nb,
|
||||
import { af, arDZ, be, bg, bn, ca, cs, cy, da, de, el, enGB, enUS, eo, es, et, eu, faIR, fi, fr, frCA, gl, he, hi, hr, hu, id, is, it, ja, kk, ko, lt, lv, ms, nb,
|
||||
nl, nn, pl, ptBR, pt, ro, ru, sk, sl, sv, ta, th, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale';
|
||||
import globalize from './globalize';
|
||||
|
||||
|
@ -22,6 +22,7 @@ const dateLocales = (locale) => ({
|
|||
'es-do': es,
|
||||
'es-mx': es,
|
||||
'et': et,
|
||||
'eu': eu,
|
||||
'fa': faIR,
|
||||
'fi': fi,
|
||||
'fr': fr,
|
||||
|
@ -67,9 +68,14 @@ export function getLocale() {
|
|||
return dateLocales(globalize.getCurrentLocale()) || dateLocales(globalize.getCurrentLocale().replace(/-.*/, '')) || enUS;
|
||||
}
|
||||
|
||||
export const localeWithSuffix = { addSuffix: true, locale: getLocale() };
|
||||
export function getLocaleWithSuffix() {
|
||||
return {
|
||||
addSuffix: true,
|
||||
locale: getLocale()
|
||||
};
|
||||
}
|
||||
|
||||
export default {
|
||||
getLocale: getLocale,
|
||||
localeWithSuffix: localeWithSuffix
|
||||
getLocaleWithSuffix
|
||||
};
|
||||
|
|
|
@ -183,9 +183,9 @@
|
|||
width = height * (16.0 / 9.0);
|
||||
}
|
||||
|
||||
return standardWidths.sort(function (a, b) {
|
||||
return Math.abs(width - a) - Math.abs(width - b);
|
||||
})[0];
|
||||
standardWidths.sort((a, b) => Math.abs(width - a) - Math.abs(width - b));
|
||||
|
||||
return standardWidths[0];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -215,19 +215,7 @@ import { getParameterByName } from '../utils/url.ts';
|
|||
}
|
||||
}
|
||||
|
||||
function onNodeOpen(event, data) {
|
||||
const page = $(this).parents('.page')[0];
|
||||
const node = data.node;
|
||||
if (node.children) {
|
||||
loadNodesToLoad(page, node);
|
||||
}
|
||||
if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) {
|
||||
node.li_attr.loadedFromServer = true;
|
||||
$.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
function onNodeLoad(event, data) {
|
||||
function onNodeOpen(_, data) {
|
||||
const page = $(this).parents('.page')[0];
|
||||
const node = data.node;
|
||||
if (node.children) {
|
||||
|
@ -254,7 +242,13 @@ import { getParameterByName } from '../utils/url.ts';
|
|||
variant: 'large'
|
||||
}
|
||||
}
|
||||
}).off('select_node.jstree', onNodeSelect).on('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).on('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad).on('load_node.jstree', onNodeLoad);
|
||||
})
|
||||
.off('select_node.jstree', onNodeSelect)
|
||||
.on('select_node.jstree', onNodeSelect)
|
||||
.off('open_node.jstree', onNodeOpen)
|
||||
.on('open_node.jstree', onNodeOpen)
|
||||
.off('load_node.jstree', onNodeOpen)
|
||||
.on('load_node.jstree', onNodeOpen);
|
||||
}
|
||||
|
||||
function loadNodesToLoad(page, node) {
|
||||
|
@ -327,7 +321,10 @@ import { getParameterByName } from '../utils/url.ts';
|
|||
});
|
||||
}).on('pagebeforehide', '.metadataEditorPage', function () {
|
||||
const page = this;
|
||||
$('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad);
|
||||
$('.libraryTree', page)
|
||||
.off('select_node.jstree', onNodeSelect)
|
||||
.off('open_node.jstree', onNodeOpen)
|
||||
.off('load_node.jstree', onNodeOpen);
|
||||
});
|
||||
let itemId;
|
||||
window.MetadataEditor = {
|
||||
|
|
|
@ -168,12 +168,7 @@ function throttle(key) {
|
|||
const time = times[key] || 0;
|
||||
const now = new Date().getTime();
|
||||
|
||||
if ((now - time) >= 200) {
|
||||
//times[key] = now;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return (now - time) >= 200;
|
||||
}
|
||||
|
||||
function resetThrottle(key) {
|
||||
|
@ -187,11 +182,7 @@ function allowInput() {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (appHost.getWindowState() === 'Minimized') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return appHost.getWindowState() !== 'Minimized';
|
||||
}
|
||||
|
||||
function raiseEvent(name, key, keyCode) {
|
||||
|
|
|
@ -1,57 +1,63 @@
|
|||
const BASE_DEVICE_IMAGE_URL = 'assets/img/devices/';
|
||||
|
||||
function getWebDeviceIcon(browser) {
|
||||
switch (browser) {
|
||||
case 'Opera':
|
||||
case 'Opera TV':
|
||||
case 'Opera Android':
|
||||
return BASE_DEVICE_IMAGE_URL + 'opera.svg';
|
||||
case 'Chrome':
|
||||
case 'Chrome Android':
|
||||
return BASE_DEVICE_IMAGE_URL + 'chrome.svg';
|
||||
case 'Firefox':
|
||||
case 'Firefox Android':
|
||||
return BASE_DEVICE_IMAGE_URL + 'firefox.svg';
|
||||
case 'Safari':
|
||||
case 'Safari iPad':
|
||||
case 'Safari iPhone':
|
||||
return BASE_DEVICE_IMAGE_URL + 'safari.svg';
|
||||
case 'Edge Chromium':
|
||||
case 'Edge Chromium Android':
|
||||
case 'Edge Chromium iPad':
|
||||
case 'Edge Chromium iPhone':
|
||||
return BASE_DEVICE_IMAGE_URL + 'edgechromium.svg';
|
||||
case 'Edge':
|
||||
return BASE_DEVICE_IMAGE_URL + 'edge.svg';
|
||||
case 'Internet Explorer':
|
||||
return BASE_DEVICE_IMAGE_URL + 'msie.svg';
|
||||
default:
|
||||
return BASE_DEVICE_IMAGE_URL + 'html5.svg';
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getDeviceIcon(device) {
|
||||
const baseUrl = 'assets/img/devices/';
|
||||
switch (device.AppName || device.Client) {
|
||||
case 'Samsung Smart TV':
|
||||
return baseUrl + 'samsung.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'samsung.svg';
|
||||
case 'Xbox One':
|
||||
return baseUrl + 'xbox.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'xbox.svg';
|
||||
case 'Sony PS4':
|
||||
return baseUrl + 'playstation.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'playstation.svg';
|
||||
case 'Kodi':
|
||||
case 'Kodi JellyCon':
|
||||
return baseUrl + 'kodi.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'kodi.svg';
|
||||
case 'Jellyfin Android':
|
||||
case 'AndroidTV':
|
||||
case 'Android TV':
|
||||
return baseUrl + 'android.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'android.svg';
|
||||
case 'Jellyfin Mobile (iOS)':
|
||||
case 'Jellyfin Mobile (iPadOS)':
|
||||
case 'Jellyfin iOS':
|
||||
case 'Infuse':
|
||||
return baseUrl + 'apple.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'apple.svg';
|
||||
case 'Home Assistant':
|
||||
return BASE_DEVICE_IMAGE_URL + 'home-assistant.svg';
|
||||
case 'Jellyfin Web':
|
||||
switch (device.Name || device.DeviceName) {
|
||||
case 'Opera':
|
||||
case 'Opera TV':
|
||||
case 'Opera Android':
|
||||
return baseUrl + 'opera.svg';
|
||||
case 'Chrome':
|
||||
case 'Chrome Android':
|
||||
return baseUrl + 'chrome.svg';
|
||||
case 'Firefox':
|
||||
case 'Firefox Android':
|
||||
return baseUrl + 'firefox.svg';
|
||||
case 'Safari':
|
||||
case 'Safari iPad':
|
||||
case 'Safari iPhone':
|
||||
return baseUrl + 'safari.svg';
|
||||
case 'Edge Chromium':
|
||||
case 'Edge Chromium Android':
|
||||
case 'Edge Chromium iPad':
|
||||
case 'Edge Chromium iPhone':
|
||||
return baseUrl + 'edgechromium.svg';
|
||||
case 'Edge':
|
||||
return baseUrl + 'edge.svg';
|
||||
case 'Internet Explorer':
|
||||
return baseUrl + 'msie.svg';
|
||||
default:
|
||||
return baseUrl + 'html5.svg';
|
||||
}
|
||||
return getWebDeviceIcon(device.Name || device.DeviceName);
|
||||
default:
|
||||
return baseUrl + 'other.svg';
|
||||
return BASE_DEVICE_IMAGE_URL + 'other.svg';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,10 +68,8 @@ export function showLayoutMenu (button, currentLayout, views) {
|
|||
cancelable: false
|
||||
}));
|
||||
|
||||
if (!dispatchEvent) {
|
||||
if (window.$) {
|
||||
$(button).trigger('layoutchange', [id]);
|
||||
}
|
||||
if (!dispatchEvent && window.$) {
|
||||
$(button).trigger('layoutchange', [id]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -117,7 +115,8 @@ export function getQueryPagingHtml (options) {
|
|||
html += '</div>';
|
||||
}
|
||||
|
||||
return html += '</div>';
|
||||
html += '</div>';
|
||||
return html;
|
||||
}
|
||||
|
||||
export function showSortMenu (options) {
|
||||
|
|
|
@ -9,7 +9,8 @@ import viewManager from '../components/viewManager/viewManager';
|
|||
import { appRouter } from '../components/appRouter';
|
||||
import { appHost } from '../components/apphost';
|
||||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import groupSelectionMenu from '../components/syncPlay/ui/groupSelectionMenu';
|
||||
import { pluginManager } from '../components/pluginManager';
|
||||
import groupSelectionMenu from '../plugins/syncPlay/ui/groupSelectionMenu';
|
||||
import browser from './browser';
|
||||
import globalize from './globalize';
|
||||
import imageHelper from './imagehelper';
|
||||
|
@ -154,8 +155,14 @@ import '../assets/css/flexstyles.scss';
|
|||
|
||||
const policy = user.Policy ? user.Policy : user.localUser.Policy;
|
||||
|
||||
const apiClient = getCurrentApiClient();
|
||||
if (headerSyncButton && policy?.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) {
|
||||
if (
|
||||
// Button is present
|
||||
headerSyncButton
|
||||
// SyncPlay plugin is loaded
|
||||
&& pluginManager.plugins.filter(plugin => plugin.id === 'syncplay').length > 0
|
||||
// SyncPlay enabled for user
|
||||
&& policy?.SyncPlayAccess !== 'None'
|
||||
) {
|
||||
headerSyncButton.classList.remove('hide');
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -88,12 +88,10 @@ import dom from '../scripts/dom';
|
|||
function onPointerEnter(e) {
|
||||
const pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse');
|
||||
|
||||
if (pointerType === 'mouse') {
|
||||
if (!isMouseIdle) {
|
||||
const parent = focusManager.focusableParent(e.target);
|
||||
if (parent) {
|
||||
focusManager.focus(parent);
|
||||
}
|
||||
if (pointerType === 'mouse' && !isMouseIdle) {
|
||||
const parent = focusManager.focusableParent(e.target);
|
||||
if (parent) {
|
||||
focusManager.focus(parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +105,7 @@ import dom from '../scripts/dom';
|
|||
return false;
|
||||
}
|
||||
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!browser.tv;
|
||||
}
|
||||
|
||||
function onMouseInterval() {
|
||||
|
|
|
@ -56,7 +56,8 @@ export default function (urls) {
|
|||
urls.forEach(function (url) {
|
||||
// the download init has to be sequential for firefox if the urls are not on the same domain
|
||||
if (browser.firefox && !sameDomain(url)) {
|
||||
return setTimeout(download.bind(null, url), 100 * ++delay);
|
||||
setTimeout(download.bind(null, url), 100 * ++delay);
|
||||
return;
|
||||
}
|
||||
|
||||
download(url);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { playbackManager } from '../components/playback/playbackmanager';
|
||||
import SyncPlay from '../components/syncPlay/core';
|
||||
import SyncPlay from '../plugins/syncPlay/core';
|
||||
import { Events } from 'jellyfin-apiclient';
|
||||
import inputManager from '../scripts/inputManager';
|
||||
import focusManager from '../components/focusManager';
|
||||
|
@ -123,16 +123,11 @@ function processGeneralCommand(cmd, apiClient) {
|
|||
displayMessage(cmd);
|
||||
break;
|
||||
case 'ToggleOsd':
|
||||
// todo
|
||||
break;
|
||||
case 'ToggleContextMenu':
|
||||
// todo
|
||||
break;
|
||||
case 'SendKey':
|
||||
// todo
|
||||
break;
|
||||
case 'SendString':
|
||||
// todo
|
||||
focusManager.sendText(cmd.Arguments.String);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -43,7 +43,9 @@ export default {
|
|||
*/
|
||||
downloadFiles(items) {
|
||||
if (window.NativeShell?.downloadFile) {
|
||||
items.forEach(item => window.NativeShell.downloadFile(item));
|
||||
items.forEach(item => {
|
||||
window.NativeShell.downloadFile(item);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue