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

Merge branch 'master' into master

This commit is contained in:
Gabriel Gavrilov 2024-08-13 12:11:39 -06:00 committed by GitHub
commit 7810ff464b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 55 additions and 68 deletions

View file

@ -12,7 +12,7 @@ import { playbackManager } from 'components/playback/playbackmanager';
import React, { FC, useCallback, useState } from 'react';
import { Link } from 'react-router-dom';
import { enable, isEnabled, supported } from 'scripts/autocast';
import { enable, isEnabled } from 'scripts/autocast';
import globalize from 'scripts/globalize';
interface RemotePlayActiveMenuProps extends MenuProps {
@ -43,11 +43,10 @@ const RemotePlayActiveMenu: FC<RemotePlayActiveMenuProps> = ({
}, [ isDisplayMirrorEnabled, setIsDisplayMirrorEnabled ]);
const [ isAutoCastEnabled, setIsAutoCastEnabled ] = useState(isEnabled());
const isAutoCastSupported = supported();
const toggleAutoCast = useCallback(() => {
enable(!isAutoCastEnabled);
setIsAutoCastEnabled(!isAutoCastEnabled);
}, [ isAutoCastEnabled, setIsAutoCastEnabled ]);
}, [ isAutoCastEnabled ]);
const remotePlayerName = playerInfo?.deviceName || playerInfo?.name;
@ -117,7 +116,6 @@ const RemotePlayActiveMenu: FC<RemotePlayActiveMenuProps> = ({
</MenuItem>
)}
{isAutoCastSupported && (
<MenuItem onClick={toggleAutoCast}>
{isAutoCastEnabled && (
<ListItemIcon>
@ -128,9 +126,8 @@ const RemotePlayActiveMenu: FC<RemotePlayActiveMenuProps> = ({
{globalize.translate('EnableAutoCast')}
</ListItemText>
</MenuItem>
)}
{(isDisplayMirrorSupported || isAutoCastSupported) && <Divider />}
<Divider />
<MenuItem
component={Link}

View file

@ -1,5 +1,5 @@
import React from 'react';
import { RouteObject, redirect } from 'react-router-dom';
import { Navigate, RouteObject } from 'react-router-dom';
import { REDIRECTS } from 'apps/dashboard/routes/_redirects';
import ConnectionRequired from 'components/ConnectionRequired';
@ -35,7 +35,7 @@ export const EXPERIMENTAL_APP_ROUTES: RouteObject[] = [
},
/* Public routes */
{ index: true, loader: () => redirect('/home.html') },
{ index: true, element: <Navigate replace to='/home.html' /> },
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)
]
},

View file

@ -1,4 +1,4 @@
import { RouteObject, redirect } from 'react-router-dom';
import { Navigate, RouteObject } from 'react-router-dom';
import React from 'react';
import ConnectionRequired from 'components/ConnectionRequired';
@ -30,7 +30,7 @@ export const STABLE_APP_ROUTES: RouteObject[] = [
},
/* Public routes */
{ index: true, loader: () => redirect('/home.html') },
{ index: true, element: <Navigate replace to='/home.html' /> },
...LEGACY_PUBLIC_ROUTES.map(toViewManagerPageRoute)
]
},

View file

@ -83,7 +83,7 @@ const ConnectionRequired: FunctionComponent<ConnectionRequiredProps> = ({
if (firstConnection.State === ConnectionState.ServerSignIn) {
// Verify the wizard is complete
try {
const infoResponse = await fetch(`${firstConnection.ApiClient.serverAddress()}/System/Info/Public`);
const infoResponse = await fetch(`${firstConnection.ApiClient.serverAddress()}/System/Info/Public`, { cache: 'no-cache' });
if (!infoResponse.ok) {
throw new Error('Public system info request failed');
}

View file

@ -6,7 +6,7 @@ import { pluginManager } from '../pluginManager';
import { appRouter } from '../router/appRouter';
import globalize from '../../scripts/globalize';
import { appHost } from '../apphost';
import { enable, isEnabled, supported } from '../../scripts/autocast';
import { enable, isEnabled } from '../../scripts/autocast';
import '../../elements/emby-checkbox/emby-checkbox';
import '../../elements/emby-button/emby-button';
import dialog from '../dialog/dialog';
@ -200,13 +200,11 @@ function showActivePlayerMenuInternal(playerInfo) {
html += '</div>';
if (supported()) {
html += '<div><label class="checkboxContainer">';
const checkedHtmlAC = isEnabled() ? ' checked' : '';
html += '<input type="checkbox" is="emby-checkbox" class="chkAutoCast"' + checkedHtmlAC + '/>';
html += '<span>' + globalize.translate('EnableAutoCast') + '</span>';
html += '</label></div>';
}
html += '<div style="margin-top:1em;display:flex;justify-content: flex-end;">';

View file

@ -387,7 +387,7 @@ class AppRouter {
if (firstResult) {
if (firstResult.State === ConnectionState.ServerSignIn) {
const url = firstResult.ApiClient.serverAddress() + '/System/Info/Public';
fetch(url).then(response => {
fetch(url, { cache: 'no-cache' }).then(response => {
if (!response.ok) return Promise.reject(new Error('fetch failed'));
return response.json();
}).then(data => {

View file

@ -23,7 +23,7 @@ export const getSystemInfoQuery = (
api?: Api
) => queryOptions({
queryKey: [ 'SystemInfo' ],
queryFn: ({ signal }) => fetchSystemInfo(api, { signal }),
queryFn: ({ signal }) => fetchSystemInfo(api, { signal, headers: { 'Cache-Control': 'no-cache' } }),
// Allow for query reuse in legacy javascript.
staleTime: 1000, // 1 second
enabled: !!api

View file

@ -24,6 +24,7 @@ import packageManager from './components/packageManager';
import './components/playback/displayMirrorManager.ts';
import { appRouter } from './components/router/appRouter';
import './elements/emby-button/emby-button';
import { initialize as initializeAutoCast } from 'scripts/autocast';
import './scripts/autoThemes';
import './components/themeMediaPlayer';
import { pageClassOn, serverAddress } from './utils/dashboard';
@ -79,6 +80,8 @@ build: ${__JF_BUILD_VERSION__}`);
}).then(() => {
console.debug('initAfterDependencies promises resolved');
initializeAutoCast(ServerConnections.currentApiClient());
loadCoreDictionary().then(function () {
onGlobalizeInit();
});

View file

@ -7,6 +7,7 @@ import ServerConnections from '../../components/ServerConnections';
import Screenfull from 'screenfull';
import TableOfContents from './tableOfContents';
import { translateHtml } from '../../scripts/globalize';
import browser from 'scripts/browser';
import * as userSettings from '../../scripts/settings/userSettings';
import TouchHelper from 'scripts/touchHelper';
import { PluginType } from '../../types/plugin.ts';
@ -45,6 +46,7 @@ export class BookPlayer {
this.previous = this.previous.bind(this);
this.next = this.next.bind(this);
this.onWindowKeyUp = this.onWindowKeyUp.bind(this);
this.addSwipeGestures = this.addSwipeGestures.bind(this);
}
play(options) {
@ -155,6 +157,12 @@ export class BookPlayer {
}
}
addSwipeGestures(element) {
this.touchHelper = new TouchHelper(element);
Events.on(this.touchHelper, 'swipeleft', () => this.next());
Events.on(this.touchHelper, 'swiperight', () => this.previous());
}
onDialogClosed() {
this.stop();
}
@ -179,10 +187,12 @@ export class BookPlayer {
document.addEventListener('keyup', this.onWindowKeyUp);
this.rendition?.on('keyup', this.onWindowKeyUp);
if (browser.safari) {
const player = document.getElementById('bookPlayerContainer');
this.touchHelper = new TouchHelper(player);
Events.on(this.touchHelper, 'swipeleft', () => this.next());
Events.on(this.touchHelper, 'swiperight', () => this.previous());
this.addSwipeGestures(player);
} else {
this.rendition?.on('rendered', (e, i) => this.addSwipeGestures(i.document.documentElement));
}
}
unbindMediaElementEvents() {
@ -207,6 +217,10 @@ export class BookPlayer {
document.removeEventListener('keyup', this.onWindowKeyUp);
this.rendition?.off('keyup', this.onWindowKeyUp);
if (!browser.safari) {
this.rendition?.off('rendered', (e, i) => this.addSwipeGestures(i.document.documentElement));
}
this.touchHelper?.destroy();
}

View file

@ -1,14 +1,7 @@
import { playbackManager } from '../components/playback/playbackmanager';
import ServerConnections from '../components/ServerConnections';
import Events from '../utils/events.ts';
export function supported() {
return typeof(Storage) !== 'undefined';
}
export function enable(enabled) {
if (!supported()) return;
if (enabled) {
const currentPlayerInfo = playbackManager.getPlayerInfo();
@ -21,8 +14,6 @@ export function enable(enabled) {
}
export function isEnabled() {
if (!supported()) return false;
const playerId = localStorage.getItem('autocastPlayerId');
const currentPlayerInfo = playbackManager.getPlayerInfo();
@ -42,12 +33,10 @@ function onOpen() {
});
}
try {
const apiClient = ServerConnections.currentApiClient();
if (apiClient && supported()) {
export function initialize(apiClient) {
if (apiClient) {
Events.on(apiClient, 'websocketopen', onOpen);
} else {
console.warn('[autoCast] cannot initialize missing apiClient');
}
} catch (ex) {
console.warn('Could not get current apiClient', ex);
}

View file

@ -27,19 +27,11 @@ function fallback(urls) {
})();
}
function sameDomain(url) {
const a = document.createElement('a');
a.href = url;
return window.location.hostname === a.hostname && window.location.protocol === a.protocol;
}
function download(url) {
const a = document.createElement('a');
a.download = '';
a.href = url;
// firefox doesn't support `a.click()`...
a.dispatchEvent(new MouseEvent('click'));
a.click();
}
export default function (urls) {
@ -47,19 +39,13 @@ export default function (urls) {
throw new Error('`urls` required');
}
if (typeof document.createElement('a').download === 'undefined') {
if (typeof document.createElement('a').download === 'undefined' || browser.iOS) {
return fallback(urls);
}
let delay = 0;
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)) {
setTimeout(download.bind(null, url), 100 * ++delay);
return;
}
download(url);
});
}

View file

@ -52,7 +52,7 @@ export async function serverAddress() {
console.debug('URL candidates:', urls);
const promises = urls.map(url => {
return fetch(`${url}/System/Info/Public`)
return fetch(`${url}/System/Info/Public`, { cache: 'no-cache' })
.then(async resp => {
if (!resp.ok) {
return;