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.

create getProgressPercentage() function that handles greater than 100% values

Replace all old uses like
(itemToDisplay.progress.watched / itemToDisplay.progress.duration) * 100

Pas 84165370 ba594056

+63 -28
+5 -2
src/components/media/WatchedMediaCard.tsx
··· 1 1 import { useMemo } from "react"; 2 2 3 - import { useProgressStore } from "@/stores/progress"; 3 + import { getProgressPercentage, useProgressStore } from "@/stores/progress"; 4 4 import { 5 5 ShowProgressResult, 6 6 shouldShowProgress, ··· 36 36 [item], 37 37 ); 38 38 const percentage = itemToDisplay?.show 39 - ? (itemToDisplay.progress.watched / itemToDisplay.progress.duration) * 100 39 + ? getProgressPercentage( 40 + itemToDisplay.progress.watched, 41 + itemToDisplay.progress.duration, 42 + ) 40 43 : undefined; 41 44 42 45 return (
+21 -16
src/components/overlays/detailsModal/components/carousels/EpisodeCarousel.tsx
··· 9 9 import { Modal, ModalCard, useModal } from "@/components/overlays/Modal"; 10 10 import { hasAired } from "@/components/player/utils/aired"; 11 11 import { useBookmarkStore } from "@/stores/bookmarks"; 12 - import { useProgressStore } from "@/stores/progress"; 12 + import { getProgressPercentage, useProgressStore } from "@/stores/progress"; 13 13 14 14 import { EpisodeCarouselProps } from "../../types"; 15 15 ··· 170 170 const episodeProgress = 171 171 progress[mediaId.toString()]?.episodes?.[episodeId]; 172 172 const percentage = episodeProgress 173 - ? (episodeProgress.progress.watched / 174 - episodeProgress.progress.duration) * 175 - 100 173 + ? getProgressPercentage( 174 + episodeProgress.progress.watched, 175 + episodeProgress.progress.duration, 176 + ) 176 177 : 0; 177 178 178 179 // If watched (>90%), reset to 0%, otherwise set to 100% ··· 282 283 const episodeProgress = 283 284 progress[mediaId?.toString() ?? ""]?.episodes?.[episode.id]; 284 285 const percentage = episodeProgress 285 - ? (episodeProgress.progress.watched / 286 - episodeProgress.progress.duration) * 287 - 100 286 + ? getProgressPercentage( 287 + episodeProgress.progress.watched, 288 + episodeProgress.progress.duration, 289 + ) 288 290 : 0; 289 291 const isAired = hasAired(episode.air_date); 290 292 const isWatched = percentage > 90; ··· 299 301 const episodeProgress = 300 302 progress[mediaId?.toString() ?? ""]?.episodes?.[episode.id]; 301 303 const percentage = episodeProgress 302 - ? (episodeProgress.progress.watched / 303 - episodeProgress.progress.duration) * 304 - 100 304 + ? getProgressPercentage( 305 + episodeProgress.progress.watched, 306 + episodeProgress.progress.duration, 307 + ) 305 308 : 0; 306 309 const isAired = hasAired(episode.air_date); 307 310 const isWatched = percentage > 90; ··· 378 381 const episodeProgress = 379 382 progress[mediaId?.toString() ?? ""]?.episodes?.[episode.id]; 380 383 const percentage = episodeProgress 381 - ? (episodeProgress.progress.watched / 382 - episodeProgress.progress.duration) * 383 - 100 384 + ? getProgressPercentage( 385 + episodeProgress.progress.watched, 386 + episodeProgress.progress.duration, 387 + ) 384 388 : 0; 385 389 const isAired = hasAired(episode.air_date); 386 390 const isWatched = percentage > 90; ··· 565 569 const episodeProgress = 566 570 progress[mediaId?.toString() ?? ""]?.episodes?.[episode.id]; 567 571 const percentage = episodeProgress 568 - ? (episodeProgress.progress.watched / 569 - episodeProgress.progress.duration) * 570 - 100 572 + ? getProgressPercentage( 573 + episodeProgress.progress.watched, 574 + episodeProgress.progress.duration, 575 + ) 571 576 : 0; 572 577 const isAired = hasAired(episode.air_date); 573 578 const isExpanded = expandedEpisodes[episode.id];
+2 -1
src/components/player/atoms/WatchPartyStatus.tsx
··· 4 4 import { Button } from "@/components/buttons/Button"; 5 5 import { Icon, Icons } from "@/components/Icon"; 6 6 import { useWatchPartySync } from "@/hooks/useWatchPartySync"; 7 + import { getProgressPercentage } from "@/stores/progress"; 7 8 import { useWatchPartyStore } from "@/stores/watchParty"; 8 9 9 10 export function WatchPartyStatus() { ··· 110 111 </span> 111 112 <span className="text-type-secondary"> 112 113 {user.player.duration > 0 113 - ? `${Math.floor((user.player.time / user.player.duration) * 100)}%` 114 + ? `${Math.floor(getProgressPercentage(user.player.time, user.player.duration))}%` 114 115 : `${Math.floor(user.player.time)}s`} 115 116 </span> 116 117 </div>
+2 -1
src/components/player/atoms/settings/WatchPartyView.tsx
··· 13 13 import { useOverlayRouter } from "@/hooks/useOverlayRouter"; 14 14 import { useWatchPartySync } from "@/hooks/useWatchPartySync"; 15 15 import { useAuthStore } from "@/stores/auth"; 16 + import { getProgressPercentage } from "@/stores/progress"; 16 17 import { useWatchPartyStore } from "@/stores/watchParty"; 17 18 18 19 import { useDownloadLink } from "./Downloads"; ··· 326 327 </span> 327 328 <span className="text-type-secondary"> 328 329 {user.player.duration > 0 329 - ? `${Math.floor((user.player.time / user.player.duration) * 100)}%` 330 + ? `${Math.floor(getProgressPercentage(user.player.time, user.player.duration))}%` 330 331 : `${Math.floor(user.player.time)}s`} 331 332 </span> 332 333 </div>
+9 -5
src/pages/PlayerView.tsx
··· 26 26 import { useLastNonPlayerLink } from "@/stores/history"; 27 27 import { PlayerMeta, playerStatus } from "@/stores/player/slices/source"; 28 28 import { usePreferencesStore } from "@/stores/preferences"; 29 - import { useProgressStore } from "@/stores/progress"; 29 + import { getProgressPercentage, useProgressStore } from "@/stores/progress"; 30 30 import { needsOnboarding } from "@/utils/onboarding"; 31 31 import { parseTimestamp } from "@/utils/timestamp"; 32 32 ··· 107 107 108 108 if (meta.type === "movie") { 109 109 if (!item.progress) return false; 110 - const percentage = 111 - (item.progress.watched / item.progress.duration) * 100; 110 + const percentage = getProgressPercentage( 111 + item.progress.watched, 112 + item.progress.duration, 113 + ); 112 114 return percentage > 80; 113 115 } 114 116 115 117 if (meta.type === "show" && meta.episode?.tmdbId) { 116 118 const episode = item.episodes?.[meta.episode.tmdbId]; 117 119 if (!episode) return false; 118 - const percentage = 119 - (episode.progress.watched / episode.progress.duration) * 100; 120 + const percentage = getProgressPercentage( 121 + episode.progress.watched, 122 + episode.progress.duration, 123 + ); 120 124 return percentage > 80; 121 125 } 122 126
+9 -3
src/pages/parts/player/ResumePart.tsx
··· 8 8 import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout"; 9 9 import { PlayerMeta } from "@/stores/player/slices/source"; 10 10 import { usePlayerStore } from "@/stores/player/store"; 11 - import { useProgressStore } from "@/stores/progress"; 11 + import { getProgressPercentage, useProgressStore } from "@/stores/progress"; 12 12 13 13 export interface ResumePartProps { 14 14 onResume: () => void; ··· 30 30 31 31 if (meta.type === "movie") { 32 32 if (!item.progress) return 0; 33 - return (item.progress.watched / item.progress.duration) * 100; 33 + return getProgressPercentage( 34 + item.progress.watched, 35 + item.progress.duration, 36 + ); 34 37 } 35 38 36 39 if (meta.type === "show" && meta.episode?.tmdbId) { 37 40 const episode = item.episodes?.[meta.episode.tmdbId]; 38 41 if (!episode) return 0; 39 - return (episode.progress.watched / episode.progress.duration) * 100; 42 + return getProgressPercentage( 43 + episode.progress.watched, 44 + episode.progress.duration, 45 + ); 40 46 } 41 47 42 48 return 0;
+2
src/stores/progress/index.ts
··· 4 4 5 5 import { PlayerMeta } from "@/stores/player/slices/source"; 6 6 7 + export { getProgressPercentage } from "./utils"; 8 + 7 9 export interface ProgressItem { 8 10 watched: number; 9 11 duration: number;
+13
src/stores/progress/utils.ts
··· 55 55 return season.number === 1 && episode.number === 1; 56 56 } 57 57 58 + export function getProgressPercentage( 59 + watched: number, 60 + duration: number, 61 + ): number { 62 + // Handle edge cases to prevent infinity or invalid percentages 63 + if (!duration || duration <= 0) return 0; 64 + if (!watched || watched < 0) return 0; 65 + 66 + // Cap percentage at 100% to prevent >100% values 67 + const percentage = Math.min((watched / duration) * 100, 100); 68 + return percentage; 69 + } 70 + 58 71 export function shouldShowProgress( 59 72 item: ProgressMediaItem, 60 73 ): ShowProgressResult {