diff --git a/frontend/src/components/Buttons/Playback/PlaybackSettingsButton.vue b/frontend/src/components/Buttons/Playback/PlaybackSettingsButton.vue index 16566597..b57e6c2a 100644 --- a/frontend/src/components/Buttons/Playback/PlaybackSettingsButton.vue +++ b/frontend/src/components/Buttons/Playback/PlaybackSettingsButton.vue @@ -75,7 +75,7 @@ :cols="8" class="text-right"> @@ -87,19 +87,8 @@ -@/store/playback-manager diff --git a/frontend/src/components/Playback/PiPVideoPlayer.vue b/frontend/src/components/Playback/PiPVideoPlayer.vue index 8bb124ea..13af56c9 100644 --- a/frontend/src/components/Playback/PiPVideoPlayer.vue +++ b/frontend/src/components/Playback/PiPVideoPlayer.vue @@ -1,19 +1,18 @@ - - + + @@ -40,7 +39,7 @@ class="pointer-events-all" icon size="large" - @click="() => playbackManager.setPreviousItem()"> + @click="playbackManager.setPreviousItem"> @@ -67,22 +66,17 @@ - - + + diff --git a/frontend/src/components/Playback/PlayerElement.vue b/frontend/src/components/Playback/PlayerElement.vue index a2fe8529..83da0f27 100644 --- a/frontend/src/components/Playback/PlayerElement.vue +++ b/frontend/src/components/Playback/PlayerElement.vue @@ -12,7 +12,7 @@ crossorigin playsinline :loop="playbackManager.isRepeatingOnce" - :class="{ stretched: playerElement.isStretched }" + :class="{ stretched: playerElement.isStretched.value }" @loadeddata="onLoadedData"> (() => { if (playbackManager.currentlyPlayingMediaType === 'Video') { - if (playerElement.isFullscreenMounted) { + if (playerElement.isFullscreenMounted.value) { return '.fullscreen-video-container'; - } else if (playerElement.isPiPMounted) { + } else if (playerElement.isPiPMounted.value) { return '.minimized-video-container'; } } diff --git a/frontend/src/layouts/default.vue b/frontend/src/layouts/default.vue index 4b4afd6d..5ef6db7b 100644 --- a/frontend/src/layouts/default.vue +++ b/frontend/src/layouts/default.vue @@ -11,8 +11,7 @@ @@ -22,7 +21,6 @@ import { computed, onBeforeMount, onUnmounted, provide, ref, watch } from 'vue'; import { useDisplay } from 'vuetify'; import type { DrawerItem } from '@/components/Layout/Navigation/NavigationDrawer.vue'; import { playbackManager } from '@/store/playback-manager'; -import { playerElement } from '@/store/player-element'; import { fetchIndexPage, getLibraryIcon } from '@/utils/items'; const display = useDisplay(); diff --git a/frontend/src/pages/playback/video.vue b/frontend/src/pages/playback/video.vue index a33fe403..c259b8d4 100644 --- a/frontend/src/pages/playback/video.vue +++ b/frontend/src/pages/playback/video.vue @@ -183,10 +183,6 @@ function handleMouseMove(): void { } onBeforeUnmount(() => { - if (playerElement.isFullscreenVideoPlayer) { - playbackManager.stop(); - } - /** * We need to destroy JASSUB so the canvas can be recreated in the other view */ diff --git a/frontend/src/plugins/router/index.ts b/frontend/src/plugins/router/index.ts index 225a2c96..343702ee 100644 --- a/frontend/src/plugins/router/index.ts +++ b/frontend/src/plugins/router/index.ts @@ -31,7 +31,6 @@ export const router = createRouter({ * Middleware pipeline: The order IS IMPORTANT (meta handling should always go first) * * Route-specific guards should be defined in the route itself, not here. - * See the playback pages for an example of this. */ router.beforeEach(metaGuard); router.beforeEach(loginGuard); diff --git a/frontend/src/store/player-element.ts b/frontend/src/store/player-element.ts index f92df7de..ea179e29 100644 --- a/frontend/src/store/player-element.ts +++ b/frontend/src/store/player-element.ts @@ -7,17 +7,13 @@ import JASSUB from 'jassub'; import jassubWorker from 'jassub/dist/jassub-worker.js?url'; import jassubWasmUrl from 'jassub/dist/jassub-worker.wasm?url'; -import { nextTick, reactive, watch } from 'vue'; +import { computed, nextTick, reactive, watch } from 'vue'; import { playbackManager } from './playback-manager'; import { isArray, isNil, sealed } from '@/utils/validation'; import { mediaElementRef } from '@/store'; import { router } from '@/plugins/router'; import { remote } from '@/plugins/remote'; -let jassub: JASSUB | undefined; -const fullscreenVideoRoute = '/playback/video'; -const fullscreenMusicRoute = '/playback/music'; - /** * == INTERFACES AND TYPES == */ @@ -32,6 +28,11 @@ interface PlayerElementState { */ @sealed class PlayerElementStore { + /** + * == NON REACTIVE STATE == + */ + private readonly _fullscreenVideoRoute = '/playback/video'; + private _jassub: JASSUB | undefined; /** * == STATE SECTION == */ @@ -47,52 +48,49 @@ class PlayerElementStore { /** * == GETTERS AND SETTERS == */ - public get isFullscreenMounted(): boolean { - return this._state.isFullscreenMounted; - } + public readonly isFullscreenMounted = computed({ + get: () => this._state.isFullscreenMounted, + set: (newVal: boolean) => { + this._state.isFullscreenMounted = newVal; + } + }); - public set isFullscreenMounted(newIsMounted: boolean) { - this._state.isFullscreenMounted = newIsMounted; - } + public readonly isPiPMounted = computed({ + get: () => this._state.isPiPMounted, + set: (newVal: boolean) => { + this._state.isPiPMounted = newVal; + } + }); - public get isPiPMounted(): boolean { - return this._state.isPiPMounted; - } + public readonly isStretched = computed({ + get: () => this._state.isStretched, + set: (newVal: boolean) => { + this._state.isStretched = newVal; + } + }); - public set isPiPMounted(newIsPipMounted: boolean) { - this._state.isPiPMounted = newIsPipMounted; - } - - public get isStretched(): boolean { - return this._state.isStretched; - } - - public set isStretched(newIsStretched: boolean) { - this._state.isStretched = newIsStretched; - } - - public get isFullscreenVideoPlayer(): boolean { - return router.currentRoute.value.fullPath === fullscreenVideoRoute; - } + public readonly isFullscreenVideoPlayer = computed( + () => router.currentRoute.value.fullPath === this._fullscreenVideoRoute + ); /** * == ACTIONS == */ public readonly toggleFullscreenVideoPlayer = async (): Promise => { - if (this.isFullscreenVideoPlayer) { + if (this.isFullscreenVideoPlayer.value) { router.back(); } else { - await router.push(fullscreenVideoRoute); + await router.push(this._fullscreenVideoRoute); } }; private readonly _setSsaTrack = (trackSrc: string, attachedFonts?: string[]): void => { if ( - !jassub && + !this._jassub && mediaElementRef.value && mediaElementRef.value instanceof HTMLVideoElement ) { - jassub = new JASSUB({ + this._jassub = new JASSUB({ video: mediaElementRef.value, subUrl: trackSrc, fonts: attachedFonts, @@ -105,24 +103,24 @@ class PlayerElementStore { // OffscreenCanvas doesn't work perfectly on Workers: https://github.com/ThaUnknown/jassub/issues/33 offscreenRender: false }); - } else if (jassub) { + } else if (this._jassub) { if (isArray(attachedFonts)) { for (const font of attachedFonts) { - jassub.addFont(font); + this._jassub.addFont(font); } } - jassub.setTrackByUrl(trackSrc); + this._jassub.setTrackByUrl(trackSrc); } }; public readonly freeSsaTrack = (): void => { - if (jassub) { + if (this._jassub) { try { - jassub.destroy(); + this._jassub.destroy(); } catch {} - jassub = undefined; + this._jassub = undefined; } }; @@ -212,15 +210,7 @@ class PlayerElementStore { watch( () => playbackManager.currentItem, async (newValue, oldValue) => { - const currentFullPath = router.currentRoute.value.fullPath; - if ( - !newValue && - (currentFullPath.includes(fullscreenMusicRoute) || - currentFullPath.includes(fullscreenVideoRoute)) - ) { - router.back(); - } else if ( newValue && !oldValue && playbackManager.currentlyPlayingMediaType === 'Video'