diff --git a/src/lib/apis/jellyfin/jellyfinApi.ts b/src/lib/apis/jellyfin/jellyfinApi.ts index a2de89c..9b56871 100644 --- a/src/lib/apis/jellyfin/jellyfinApi.ts +++ b/src/lib/apis/jellyfin/jellyfinApi.ts @@ -104,7 +104,11 @@ export const getJellyfinItem = (itemId: string) => export const requestJellyfinItemByTmdbId = () => request((tmdbId: string) => getJellyfinItemByTmdbId(tmdbId)); -export const getJellyfinPlaybackInfo = (itemId: string, playbackProfile: DeviceProfile) => +export const getJellyfinPlaybackInfo = ( + itemId: string, + playbackProfile: DeviceProfile, + startTimeTicks = 0 +) => JellyfinApi.post('/Items/{itemId}/PlaybackInfo', { params: { path: { @@ -112,7 +116,7 @@ export const getJellyfinPlaybackInfo = (itemId: string, playbackProfile: DeviceP }, query: { userId: get(settings).jellyfin.userId, - startTimeTicks: 0, + startTimeTicks, autoOpenLiveStream: true, maxStreamingBitrate: 140000000 } @@ -121,9 +125,14 @@ export const getJellyfinPlaybackInfo = (itemId: string, playbackProfile: DeviceP DeviceProfile: playbackProfile } }).then((r) => ({ - playbackUrl: r.data?.MediaSources?.[0]?.TranscodingUrl, + playbackUri: + r.data?.MediaSources?.[0]?.TranscodingUrl || + `/Videos/${r.data?.MediaSources?.[0].Id}/stream.mp4?Static=true&mediaSourceId=${r.data?.MediaSources?.[0].Id}&deviceId=${JELLYFIN_DEVICE_ID}&api_key=${PUBLIC_JELLYFIN_API_KEY}&Tag=${r.data?.MediaSources?.[0].ETag}`, mediaSourceId: r.data?.MediaSources?.[0]?.Id, - playSessionId: r.data?.PlaySessionId + playSessionId: r.data?.PlaySessionId, + directPlay: + !!r.data?.MediaSources?.[0]?.SupportsDirectPlay || + !!r.data?.MediaSources?.[0]?.SupportsDirectStream })); export const reportJellyfinPlaybackStarted = ( diff --git a/src/lib/components/VideoPlayer/VideoPlayer.svelte b/src/lib/components/VideoPlayer/VideoPlayer.svelte index c66a40d..767e676 100644 --- a/src/lib/components/VideoPlayer/VideoPlayer.svelte +++ b/src/lib/components/VideoPlayer/VideoPlayer.svelte @@ -26,26 +26,34 @@ let progressInterval: NodeJS.Timeout; const fetchPlaybackInfo = (itemId: string) => - getJellyfinPlaybackInfo(itemId, getDeviceProfile()).then( - async ({ playbackUrl: uri, playSessionId: sessionId, mediaSourceId }) => { - if (!uri || !sessionId) return; + getJellyfinItem(itemId).then((item) => + getJellyfinPlaybackInfo( + itemId, + getDeviceProfile(), + item?.UserData?.PlaybackPositionTicks || 0 + ).then(async ({ playbackUri, playSessionId: sessionId, mediaSourceId, directPlay }) => { + if (!playbackUri || !sessionId) { + console.log('No playback URL or session ID', playbackUri, sessionId); + return; + } - const item = await getJellyfinItem(itemId); + if (!directPlay) { + const hls = new Hls(); - const hls = new Hls(); + hls.loadSource(PUBLIC_JELLYFIN_URL + playbackUri); + hls.attachMedia(video); + } else { + video.src = PUBLIC_JELLYFIN_URL + playbackUri; + } - hls.loadSource(PUBLIC_JELLYFIN_URL + uri); - hls.attachMedia(video); - video - .play() - .then(() => video.requestFullscreen()) - .then(() => { - if (item?.UserData?.PlaybackPositionTicks) { - video.currentTime = item?.UserData?.PlaybackPositionTicks / 10_000_000; - } - }); + if (item?.UserData?.PlaybackPositionTicks) { + video.currentTime = item?.UserData?.PlaybackPositionTicks / 10_000_000; + } + + video.play().then(() => video.requestFullscreen()); if (mediaSourceId) await reportJellyfinPlaybackStarted(itemId, sessionId, mediaSourceId); progressInterval = setInterval(() => { + video && video.readyState === 4 && video?.currentTime > 0 && sessionId && itemId; reportJellyfinPlaybackProgress( itemId, sessionId, @@ -56,7 +64,7 @@ stopCallback = () => { reportJellyfinPlaybackStopped(itemId, sessionId, video?.currentTime * 10_000_000); }; - } + }) ); function handleClose() {