movie-web/src/stores/progress/utils.ts
Joao Melo f4dd6f95a4 Fix #241: Last episode completed does not save
After ending episode or clicking on next episode, store state wasn't updating. Changed NextEpisodeButton and which series episodes are displayed
2024-03-25 17:59:11 +00:00

95 lines
2.3 KiB
TypeScript

import {
ProgressEpisodeItem,
ProgressItem,
ProgressMediaItem,
ProgressSeasonItem,
} from "@/stores/progress";
export interface ShowProgressResult {
episode?: ProgressEpisodeItem;
season?: ProgressSeasonItem;
progress: ProgressItem;
show: boolean;
}
const defaultProgress = {
duration: 0,
watched: 0,
};
function progressIsCompleted(duration: number, watched: number): boolean {
const timeFromEnd = duration - watched;
// too close to the end, is completed
if (timeFromEnd < 60 * 2) return true;
// satisfies all constraints, not completed
return false;
}
function progressIsNotStarted(duration: number, watched: number): boolean {
// too short watch time
if (watched < 20) return true;
// satisfies all constraints, not completed
return false;
}
function progressIsAcceptableRange(duration: number, watched: number): boolean {
// not started enough yet, not acceptable
if (progressIsNotStarted(duration, watched)) return false;
// is already at the end, not acceptable
if (progressIsCompleted(duration, watched)) return false;
// satisfied all constraints
return true;
}
function isFirstEpisodeOfShow(
item: ProgressMediaItem,
episode: ProgressEpisodeItem,
): boolean {
const seasonId = episode.seasonId;
const season = item.seasons[seasonId];
return season.number === 1 && episode.number === 1;
}
export function shouldShowProgress(
item: ProgressMediaItem,
): ShowProgressResult {
// non shows just hide or show depending on acceptable ranges
if (item.type !== "show") {
return {
show: progressIsAcceptableRange(
item.progress?.duration ?? 0,
item.progress?.watched ?? 0,
),
progress: item.progress ?? defaultProgress,
};
}
// shows only hide an item if its too early in episode, it still shows if its near the end.
// Otherwise you would lose episode progress
const ep = Object.values(item.episodes)
.sort((a, b) => b.updatedAt - a.updatedAt)
.filter(
(epi) =>
!progressIsNotStarted(epi.progress.duration, epi.progress.watched) ||
!isFirstEpisodeOfShow(item, epi),
)[0];
const season = item.seasons[ep?.seasonId];
if (!ep || !season)
return {
show: false,
progress: defaultProgress,
};
return {
season,
episode: ep,
show: true,
progress: ep.progress,
};
}