pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

get episode rating for pause overlay

Pas a467dbbe 2811c4b3

+49 -5
+19
src/backend/metadata/tmdb.ts
··· 13 13 ExternalIdMovieSearchResult, 14 14 TMDBContentTypes, 15 15 TMDBCredits, 16 + TMDBEpisode, 16 17 TMDBEpisodeShort, 17 18 TMDBMediaResult, 18 19 TMDBMovieData, ··· 356 357 : T extends TMDBContentTypes.TV 357 358 ? TMDBShowData 358 359 : never; 360 + 361 + export async function getEpisodeDetails( 362 + showId: string, 363 + seasonNumber: number, 364 + episodeNumber: number, 365 + ): Promise<{ vote_average: number } | null> { 366 + try { 367 + const data = await get<TMDBEpisode>( 368 + `/tv/${showId}/season/${seasonNumber}/episode/${episodeNumber}`, 369 + ); 370 + return { 371 + vote_average: 372 + typeof data.vote_average === "number" ? data.vote_average : 0, 373 + }; 374 + } catch { 375 + return null; 376 + } 377 + } 359 378 360 379 export async function getSeasonDetails( 361 380 id: string,
+30 -5
src/components/player/overlays/PauseOverlay.tsx
··· 1 1 import { useEffect, useState } from "react"; 2 2 import { useIdle } from "react-use"; 3 3 4 - import { getMediaDetails, getMediaLogo } from "@/backend/metadata/tmdb"; 4 + import { 5 + getEpisodeDetails, 6 + getMediaDetails, 7 + getMediaLogo, 8 + } from "@/backend/metadata/tmdb"; 5 9 import { TMDBContentTypes } from "@/backend/metadata/types/tmdb"; 6 10 import { useShouldShowControls } from "@/components/player/hooks/useShouldShowControls"; 7 11 import { useIsMobile } from "@/hooks/useIsMobile"; ··· 67 71 try { 68 72 const type = 69 73 meta.type === "movie" ? TMDBContentTypes.MOVIE : TMDBContentTypes.TV; 74 + 75 + // For shows with episode, fetch episode-specific rating 76 + const isShowWithEpisode = 77 + meta.type === "show" && meta.season && meta.episode; 78 + let voteAverage: number | null = null; 79 + 80 + if (isShowWithEpisode) { 81 + const episodeData = await getEpisodeDetails( 82 + meta.tmdbId, 83 + meta.season?.number ?? 0, 84 + meta.episode?.number ?? 0, 85 + ); 86 + if (mounted && episodeData?.vote_average != null) { 87 + voteAverage = episodeData.vote_average; 88 + } 89 + } 90 + 70 91 const data = await getMediaDetails(meta.tmdbId, type, false); 71 92 if (mounted && data) { 72 - const voteAverage = 73 - typeof data.vote_average === "number" ? data.vote_average : null; 74 93 const genres = (data.genres ?? []).map( 75 94 (g: { name: string }) => g.name, 76 95 ); 77 - setDetails({ voteAverage, genres }); 96 + // Use episode rating for shows (never fall back to show rating) 97 + const finalVoteAverage = isShowWithEpisode 98 + ? voteAverage 99 + : typeof data.vote_average === "number" 100 + ? data.vote_average 101 + : null; 102 + setDetails({ voteAverage: finalVoteAverage, genres }); 78 103 } 79 104 } catch { 80 105 if (mounted) setDetails({ voteAverage: null, genres: [] }); ··· 85 110 return () => { 86 111 mounted = false; 87 112 }; 88 - }, [meta?.tmdbId, meta?.type]); 113 + }, [meta?.tmdbId, meta?.type, meta?.season, meta?.episode]); 89 114 90 115 if (!meta) return null; 91 116