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

Merge pull request #3976 from thornbill/syncplay-plugin

This commit is contained in:
Bill Thornton 2022-10-04 09:18:11 -04:00 committed by GitHub
commit b9f144ea1d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
29 changed files with 82 additions and 54 deletions

View file

@ -4,7 +4,7 @@ import globalize from '../../scripts/globalize';
import layoutManager from '../layoutManager'; import layoutManager from '../layoutManager';
import { playbackManager } from '../playback/playbackmanager'; import { playbackManager } from '../playback/playbackmanager';
import playMethodHelper from '../playback/playmethodhelper'; import playMethodHelper from '../playback/playmethodhelper';
import SyncPlay from '../../components/syncPlay/core'; import SyncPlay from '../../plugins/syncPlay/core';
import './playerstats.scss'; import './playerstats.scss';
import ServerConnections from '../ServerConnections'; import ServerConnections from '../ServerConnections';

View file

@ -4,7 +4,7 @@ import dialogHelper from '../dialogHelper/dialogHelper';
import loading from '../loading/loading'; import loading from '../loading/loading';
import layoutManager from '../layoutManager'; import layoutManager from '../layoutManager';
import { playbackManager } from '../playback/playbackmanager'; import { playbackManager } from '../playback/playbackmanager';
import SyncPlay from '../../components/syncPlay/core'; import SyncPlay from '../../plugins/syncPlay/core';
import * as userSettings from '../../scripts/settings/userSettings'; import * as userSettings from '../../scripts/settings/userSettings';
import { appRouter } from '../appRouter'; import { appRouter } from '../appRouter';
import globalize from '../../scripts/globalize'; import globalize from '../../scripts/globalize';

View file

@ -44,6 +44,7 @@
"pdfPlayer/plugin", "pdfPlayer/plugin",
"logoScreensaver/plugin", "logoScreensaver/plugin",
"sessionPlayer/plugin", "sessionPlayer/plugin",
"chromecastPlayer/plugin" "chromecastPlayer/plugin",
"syncPlay/plugin"
] ]
} }

View file

@ -1,6 +1,6 @@
import escapeHtml from 'escape-html'; import escapeHtml from 'escape-html';
import { playbackManager } from '../../../components/playback/playbackmanager'; import { playbackManager } from '../../../components/playback/playbackmanager';
import SyncPlay from '../../../components/syncPlay/core'; import SyncPlay from '../../../plugins/syncPlay/core';
import browser from '../../../scripts/browser'; import browser from '../../../scripts/browser';
import dom from '../../../scripts/dom'; import dom from '../../../scripts/dom';
import inputManager from '../../../scripts/inputManager'; import inputManager from '../../../scripts/inputManager';

View file

@ -35,11 +35,6 @@ import './legacy/domParserTextHtml';
import './legacy/focusPreventScroll'; import './legacy/focusPreventScroll';
import './legacy/htmlMediaElement'; import './legacy/htmlMediaElement';
import './legacy/vendorStyles'; import './legacy/vendorStyles';
import SyncPlay from './components/syncPlay/core';
import { playbackManager } from './components/playback/playbackmanager';
import SyncPlayNoActivePlayer from './components/syncPlay/ui/players/NoActivePlayer';
import SyncPlayHtmlVideoPlayer from './components/syncPlay/ui/players/HtmlVideoPlayer';
import SyncPlayHtmlAudioPlayer from './components/syncPlay/ui/players/HtmlAudioPlayer';
import { currentSettings } from './scripts/settings/userSettings'; import { currentSettings } from './scripts/settings/userSettings';
import taskButton from './scripts/taskbutton'; import taskButton from './scripts/taskbutton';
import { HistoryRouter } from './components/HistoryRouter.tsx'; import { HistoryRouter } from './components/HistoryRouter.tsx';
@ -102,10 +97,7 @@ function onGlobalizeInit() {
import('./assets/css/librarybrowser.scss'); import('./assets/css/librarybrowser.scss');
loadPlugins().then(function () { loadPlugins().then(onAppReady);
initSyncPlay();
onAppReady();
});
} }
function loadPlugins() { function loadPlugins() {
@ -137,27 +129,6 @@ function loadPlugins() {
}); });
} }
function initSyncPlay() {
// Register player wrappers.
SyncPlay.PlayerFactory.setDefaultWrapper(SyncPlayNoActivePlayer);
SyncPlay.PlayerFactory.registerWrapper(SyncPlayHtmlVideoPlayer);
SyncPlay.PlayerFactory.registerWrapper(SyncPlayHtmlAudioPlayer);
// Listen for player changes.
Events.on(playbackManager, 'playerchange', (event, newPlayer, newTarget, oldPlayer) => {
SyncPlay.Manager.onPlayerChange(newPlayer, newTarget, oldPlayer);
});
// Start SyncPlay.
const apiClient = ServerConnections.currentApiClient();
if (apiClient) SyncPlay.Manager.init(apiClient);
// FIXME: Multiple apiClients?
Events.on(ServerConnections, 'apiclientcreated', (e, newApiClient) => SyncPlay.Manager.init(newApiClient));
Events.on(ServerConnections, 'localusersignedin', () => SyncPlay.Manager.updateApiClient(ServerConnections.currentApiClient()));
Events.on(ServerConnections, 'localusersignedout', () => SyncPlay.Manager.updateApiClient(ServerConnections.currentApiClient()));
}
async function onAppReady() { async function onAppReady() {
console.debug('begin onAppReady'); console.debug('begin onAppReady');

View file

@ -9,7 +9,7 @@ import TimeSyncCore from './timeSync/TimeSyncCore';
import PlaybackCore from './PlaybackCore'; import PlaybackCore from './PlaybackCore';
import QueueCore from './QueueCore'; import QueueCore from './QueueCore';
import Controller from './Controller'; import Controller from './Controller';
import toast from '../../toast/toast'; import toast from '../../../components/toast/toast';
import globalize from '../../../scripts/globalize'; import globalize from '../../../scripts/globalize';
/** /**

View file

@ -4,7 +4,7 @@
*/ */
import globalize from '../../../scripts/globalize'; import globalize from '../../../scripts/globalize';
import toast from '../../toast/toast'; import toast from '../../../components/toast/toast';
import * as Helper from './Helper'; import * as Helper from './Helper';
/** /**

View file

@ -16,7 +16,7 @@ class PlayerFactory {
/** /**
* Registers a wrapper to the list of players that can be managed. * Registers a wrapper to the list of players that can be managed.
* @param {GenericPlayer} wrapperClass The wrapper to register. * @param {typeof GenericPlayer} wrapperClass The wrapper to register.
*/ */
registerWrapper(wrapperClass) { registerWrapper(wrapperClass) {
console.debug('SyncPlay WrapperFactory registerWrapper:', wrapperClass.type); console.debug('SyncPlay WrapperFactory registerWrapper:', wrapperClass.type);
@ -25,7 +25,7 @@ class PlayerFactory {
/** /**
* Sets the default player wrapper. * Sets the default player wrapper.
* @param {GenericPlayer} wrapperClass The wrapper. * @param {typeof GenericPlayer} wrapperClass The wrapper.
*/ */
setDefaultWrapper(wrapperClass) { setDefaultWrapper(wrapperClass) {
console.debug('SyncPlay WrapperFactory setDefaultWrapper:', wrapperClass.type); console.debug('SyncPlay WrapperFactory setDefaultWrapper:', wrapperClass.type);

View file

@ -0,0 +1,49 @@
import { Events } from 'jellyfin-apiclient';
import { playbackManager } from '../../components/playback/playbackmanager';
import ServerConnections from '../../components/ServerConnections';
import SyncPlay from './core';
import SyncPlayNoActivePlayer from './ui/players/NoActivePlayer';
import SyncPlayHtmlVideoPlayer from './ui/players/HtmlVideoPlayer';
import SyncPlayHtmlAudioPlayer from './ui/players/HtmlAudioPlayer';
class SyncPlayPlugin {
name: string;
id: string;
type: string;
priority: number;
constructor() {
this.name = 'SyncPlay Plugin';
this.id = 'syncplay';
// NOTE: This should probably be a "mediaplayer" so the playback manager can handle playback logic, but
// SyncPlay needs refactored so it does not have an independent playback manager.
this.type = 'syncplay';
this.priority = 1;
this.init();
}
init() {
// Register player wrappers.
SyncPlay.PlayerFactory.setDefaultWrapper(SyncPlayNoActivePlayer);
SyncPlay.PlayerFactory.registerWrapper(SyncPlayHtmlVideoPlayer);
SyncPlay.PlayerFactory.registerWrapper(SyncPlayHtmlAudioPlayer);
// Listen for player changes.
Events.on(playbackManager, 'playerchange', (_, newPlayer) => {
SyncPlay.Manager.onPlayerChange(newPlayer);
});
// Start SyncPlay.
const apiClient = ServerConnections.currentApiClient();
if (apiClient) SyncPlay.Manager.init(apiClient);
// FIXME: Multiple apiClients?
Events.on(ServerConnections, 'apiclientcreated', (_, newApiClient) => SyncPlay.Manager.init(newApiClient));
Events.on(ServerConnections, 'localusersignedin', () => SyncPlay.Manager.updateApiClient(ServerConnections.currentApiClient()));
Events.on(ServerConnections, 'localusersignedout', () => SyncPlay.Manager.updateApiClient(ServerConnections.currentApiClient()));
}
}
export default SyncPlayPlugin;

View file

@ -1,12 +1,12 @@
import { Events } from 'jellyfin-apiclient'; import { Events } from 'jellyfin-apiclient';
import SyncPlay from '../core'; import SyncPlay from '../core';
import SyncPlaySettingsEditor from './settings/SettingsEditor'; import SyncPlaySettingsEditor from './settings/SettingsEditor';
import loading from '../../loading/loading'; import loading from '../../../components/loading/loading';
import toast from '../../toast/toast'; import toast from '../../../components/toast/toast';
import actionsheet from '../../actionSheet/actionSheet'; import actionsheet from '../../../components/actionSheet/actionSheet';
import globalize from '../../../scripts/globalize'; import globalize from '../../../scripts/globalize';
import playbackPermissionManager from './playbackPermissionManager'; import playbackPermissionManager from './playbackPermissionManager';
import ServerConnections from '../../ServerConnections'; import ServerConnections from '../../../components/ServerConnections';
import './groupSelectionMenu.scss'; import './groupSelectionMenu.scss';
/** /**

View file

@ -1,4 +1,4 @@
import { appHost } from '../../apphost'; import { appHost } from '../../../components/apphost';
/** /**
* Creates an audio element that plays a silent sound. * Creates an audio element that plays a silent sound.

View file

@ -3,7 +3,7 @@
* @module components/syncPlay/ui/players/NoActivePlayer * @module components/syncPlay/ui/players/NoActivePlayer
*/ */
import { playbackManager } from '../../../playback/playbackmanager'; import { playbackManager } from '../../../../components/playback/playbackmanager';
import SyncPlay from '../../core'; import SyncPlay from '../../core';
import QueueManager from './QueueManager'; import QueueManager from './QueueManager';

View file

@ -6,10 +6,10 @@
import { Events } from 'jellyfin-apiclient'; import { Events } from 'jellyfin-apiclient';
import SyncPlay from '../../core'; import SyncPlay from '../../core';
import { setSetting } from '../../core/Settings'; import { setSetting } from '../../core/Settings';
import dialogHelper from '../../../dialogHelper/dialogHelper'; import dialogHelper from '../../../../components/dialogHelper/dialogHelper';
import layoutManager from '../../../layoutManager'; import layoutManager from '../../../../components/layoutManager';
import loading from '../../../loading/loading'; import loading from '../../../../components/loading/loading';
import toast from '../../../toast/toast'; import toast from '../../../../components/toast/toast';
import globalize from '../../../../scripts/globalize'; import globalize from '../../../../scripts/globalize';
import 'material-design-icons-iconfont'; import 'material-design-icons-iconfont';
@ -18,8 +18,8 @@ import '../../../../elements/emby-select/emby-select';
import '../../../../elements/emby-button/emby-button'; import '../../../../elements/emby-button/emby-button';
import '../../../../elements/emby-button/paper-icon-button-light'; import '../../../../elements/emby-button/paper-icon-button-light';
import '../../../../elements/emby-checkbox/emby-checkbox'; import '../../../../elements/emby-checkbox/emby-checkbox';
import '../../../listview/listview.scss'; import '../../../../components/listview/listview.scss';
import '../../../formdialog.scss'; import '../../../../components/formdialog.scss';
function centerFocus(elem, horiz, on) { function centerFocus(elem, horiz, on) {
import('../../../../scripts/scrollHelper').then((scrollHelper) => { import('../../../../scripts/scrollHelper').then((scrollHelper) => {

View file

@ -9,7 +9,8 @@ import viewManager from '../components/viewManager/viewManager';
import { appRouter } from '../components/appRouter'; import { appRouter } from '../components/appRouter';
import { appHost } from '../components/apphost'; import { appHost } from '../components/apphost';
import { playbackManager } from '../components/playback/playbackmanager'; 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 browser from './browser';
import globalize from './globalize'; import globalize from './globalize';
import imageHelper from './imagehelper'; import imageHelper from './imagehelper';
@ -154,8 +155,14 @@ import '../assets/css/flexstyles.scss';
const policy = user.Policy ? user.Policy : user.localUser.Policy; const policy = user.Policy ? user.Policy : user.localUser.Policy;
const apiClient = getCurrentApiClient(); if (
if (headerSyncButton && policy?.SyncPlayAccess !== 'None' && apiClient.isMinServerVersion('10.6.0')) { // 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'); headerSyncButton.classList.remove('hide');
} }
} else { } else {

View file

@ -1,5 +1,5 @@
import { playbackManager } from '../components/playback/playbackmanager'; import { playbackManager } from '../components/playback/playbackmanager';
import SyncPlay from '../components/syncPlay/core'; import SyncPlay from '../plugins/syncPlay/core';
import { Events } from 'jellyfin-apiclient'; import { Events } from 'jellyfin-apiclient';
import inputManager from '../scripts/inputManager'; import inputManager from '../scripts/inputManager';
import focusManager from '../components/focusManager'; import focusManager from '../components/focusManager';