Skip to content

Commit

Permalink
refactor: better video player routing
Browse files Browse the repository at this point in the history
  • Loading branch information
ThibaultNocchi authored and ferferga committed Feb 28, 2023
1 parent 5e3e245 commit cf5bc5e
Show file tree
Hide file tree
Showing 8 changed files with 40 additions and 34 deletions.
4 changes: 4 additions & 0 deletions frontend/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
"errorCode": "Error code: {errorCode}",
"videoPlayerError": "The video player encountered an unrecoverable error."
},
"playback": {
"mediaError": "Fatal media error encountered, trying to recover",
"networkError": "Fatal network error encountered, trying to recover"
},
"unauthorized": "You're not authorized to access this page"
},
"failedRetrievingDisplayPreferences": "Unable to get display preferences. Using last known settings.",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Playback/OsdPlayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<v-btn :icon="IMdiClose" @click="playbackManager.stop" />
<v-btn
:icon="IMdiChevronDown"
@click="playerElement.toggleMinimize" />
@click="playerElement.toggleFullscreenVideoPlayer" />
</div>
<div class="d-flex ml-auto">
<cast-button />
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/Playback/PiPVideoPlayer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
width="100%">
<div class="d-flex flex-column">
<div class="d-flex flex-row">
<v-btn icon @click="playerElement.toggleMinimize">
<v-btn icon @click="playerElement.toggleFullscreenVideoPlayer">
<v-icon>
<i-mdi-arrow-expand-all />
</v-icon>
Expand Down Expand Up @@ -80,7 +80,7 @@ const playbackManager = playbackManagerStore();
const keys = useMagicKeys();
whenever(keys.f, () => playerElement.toggleMinimize);
whenever(keys.f, () => playerElement.toggleFullscreenVideoPlayer);
onMounted(() => {
playerElement.isPiPMounted = true;
Expand Down
25 changes: 25 additions & 0 deletions frontend/src/components/Playback/PlayerElement.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

<script setup lang="ts">
import { computed, watch, nextTick } from 'vue';
import { useRouter } from 'vue-router';
import { isNil } from 'lodash-es';
import { useI18n } from 'vue-i18n';
import Hls, { ErrorData, ErrorTypes, Events } from 'hls.js';
Expand All @@ -41,6 +42,7 @@ const playbackManager = playbackManagerStore();
const playerElement = playerElementStore();
const { t } = useI18n();
const router = useRouter();
/**
* Safari iOS doesn't support hls.js, so we need to handle the cases where we don't need hls.js
*/
Expand Down Expand Up @@ -118,11 +120,13 @@ function onHlsEror(_event: Events.ERROR, data: ErrorData): void {
switch (data.type) {
case ErrorTypes.NETWORK_ERROR: {
// try to recover network error
useSnackbar(t('errors.playback.networkError'), 'error');
console.error('fatal network error encountered, try to recover');
hls.startLoad();
break;
}
case ErrorTypes.MEDIA_ERROR: {
useSnackbar(t('errors.playback.mediaError'), 'error');
console.error('fatal media error encountered, try to recover');
hls.recoverMediaError();
break;
Expand Down Expand Up @@ -152,6 +156,27 @@ watch(
}
);
watch(
() => ({ currentItem: playbackManager.currentItem }),
(newValue, oldValue) => {
if (
(!newValue.currentItem &&
router.currentRoute.value.fullPath === '/playback/video') ||
(newValue.currentItem &&
!oldValue?.currentItem &&
playbackManager.currentlyPlayingMediaType === 'Video')
) {
/**
* If no item is present, we either manually loaded this or playback is stopped
* OR
* If there was no item and there's now a video, default to going FS
*/
playerElement.toggleFullscreenVideoPlayer();
}
},
{ immediate: true }
);
watch(mediaElementRef, async () => {
await nextTick();
detachHls();
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<pi-p-video-player
v-if="
playbackManager.currentlyPlayingMediaType === 'Video' &&
playerElement.isMinimized
!playerElement.isFullscreenVideoPlayer
" />
</template>

Expand Down
8 changes: 1 addition & 7 deletions frontend/src/pages/playback/video/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ meta:

<script lang="ts" setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useFullscreen } from '@vueuse/core';
import { playbackManagerStore, playerElementStore } from '@/store';
import { mediaElementRef } from '@/store/playbackManager';
const router = useRouter();
const playbackManager = playbackManagerStore();
const playerElement = playerElementStore();
Expand Down Expand Up @@ -49,16 +47,12 @@ function toggleFullscreen(): void {
}
}
if (!playbackManager.currentItem) {
router.replace('/');
}
onBeforeUnmount(() => {
if (fullscreen.isFullscreen.value) {
fullscreen.exit();
}
if (!playerElement.isMinimized) {
if (playerElement.isFullscreenVideoPlayer) {
playbackManager.stop();
}
Expand Down
21 changes: 2 additions & 19 deletions frontend/src/store/playbackManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { getPlaystateApi } from '@jellyfin/sdk/lib/utils/api/playstate-api';
import { getMediaInfoApi } from '@jellyfin/sdk/lib/utils/api/media-info-api';
import { useMediaControls, useNow } from '@vueuse/core';
import { itemsStore } from '.';
import { usei18n, useRemote, useRouter, useSnackbar } from '@/composables';
import { usei18n, useRemote, useSnackbar } from '@/composables';
import { getImageInfo } from '@/utils/images';
import { msToTicks } from '@/utils/time';
import playbackProfile from '@/utils/playback-profiles';
Expand Down Expand Up @@ -1145,31 +1145,14 @@ class PlaybackManagerStore {
*/
watch(
() => this.currentItemIndex,
async (newIndex, oldIndex) => {
async (newIndex) => {
await this.fetchCurrentMediaSource();

const router = useRouter();

if (newIndex && !state.currentSourceUrl) {
const { t } = usei18n();

useSnackbar(t('errors.cantPlayItem'), 'error');
this.stop();
} else if (
this.currentlyPlayingMediaType === 'Video' &&
oldIndex === undefined &&
newIndex !== undefined
) {
router.push('/playback/video');
} else if (
router.currentRoute.value.fullPath === '/playback/video' &&
newIndex === undefined
) {
router.replace(
typeof router.options.history.state.back === 'string'
? router.options.history.state.back
: '/'
);
}

if (this.previousItem?.Id) {
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/store/playerElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,22 @@ class PlayerElementStore {
state.isStretched = newisStretched;
}

public get isMinimized(): boolean {
return useRouter().currentRoute.value.fullPath !== '/playback/video';
public get isFullscreenVideoPlayer(): boolean {
return useRouter().currentRoute.value.fullPath === '/playback/video';
}

/**
* == ACTIONS ==
*/
public toggleMinimize = (): void => {
public toggleFullscreenVideoPlayer = (): void => {
/**
* Destroys SSO before chaning view cause the canvas needs to be destroyed to be recreated in the other view
*/
playerElement.freeSsaTrack();

const router = useRouter();

if (this.isMinimized) {
if (!this.isFullscreenVideoPlayer) {
router.push('/playback/video');
} else {
router.replace(
Expand Down

0 comments on commit cf5bc5e

Please sign in to comment.