feat: add mark season as watched for videos

This commit is contained in:
Tim 2025-01-22 18:39:45 +01:00
parent 9b197c8712
commit 6e00a3384c
3 changed files with 49 additions and 2 deletions

View file

@ -11,7 +11,7 @@ const useBinaryState = require('stremio/common/useBinaryState');
const VideoPlaceholder = require('./VideoPlaceholder');
const styles = require('./styles');
const Video = ({ className, id, title, thumbnail, episode, released, upcoming, watched, progress, scheduled, deepLinks, onMarkVideoAsWatched, ...props }) => {
const Video = ({ className, id, title, thumbnail, season, episode, released, upcoming, watched, progress, scheduled, seasonWatched, deepLinks, onMarkVideoAsWatched, onMarkSeasonAsWatched, ...props }) => {
const routeFocused = useRouteFocused();
const [menuOpen, , closeMenu, toggleMenu] = useBinaryState(false);
const popupLabelOnMouseUp = React.useCallback((event) => {
@ -50,6 +50,12 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w
closeMenu();
onMarkVideoAsWatched({ id, released }, watched);
}, [id, released, watched]);
const toggleWatchedSeasonOnClick = React.useCallback((event) => {
event.preventDefault();
event.stopPropagation();
closeMenu();
onMarkSeasonAsWatched(season, seasonWatched);
}, [season, seasonWatched, onMarkSeasonAsWatched]);
const videoButtonOnClick = React.useCallback(() => {
if (deepLinks) {
if (typeof deepLinks.player === 'string') {
@ -142,9 +148,12 @@ const Video = ({ className, id, title, thumbnail, episode, released, upcoming, w
<Button className={styles['context-menu-option-container']} title={watched ? 'Mark as non-watched' : 'Mark as watched'} onClick={toggleWatchedOnClick}>
<div className={styles['context-menu-option-label']}>{watched ? t('CTX_MARK_NON_WATCHED') : t('CTX_MARK_WATCHED')}</div>
</Button>
<Button className={styles['context-menu-option-container']} title={seasonWatched ? t('CTX_UNMARK_REST') : t('CTX_MARK_REST')} onClick={toggleWatchedSeasonOnClick}>
<div className={styles['context-menu-option-label']}>{seasonWatched ? t('CTX_UNMARK_REST') : t('CTX_MARK_REST')}</div>
</Button>
</div>
);
}, [watched, toggleWatchedOnClick]);
}, [watched, seasonWatched, toggleWatchedOnClick]);
React.useEffect(() => {
if (!routeFocused) {
closeMenu();
@ -182,17 +191,20 @@ Video.propTypes = {
id: PropTypes.string,
title: PropTypes.string,
thumbnail: PropTypes.string,
season: PropTypes.number,
episode: PropTypes.number,
released: PropTypes.instanceOf(Date),
upcoming: PropTypes.bool,
watched: PropTypes.bool,
progress: PropTypes.number,
scheduled: PropTypes.bool,
seasonWatched: PropTypes.bool,
deepLinks: PropTypes.shape({
metaDetailsStreams: PropTypes.string,
player: PropTypes.string
}),
onMarkVideoAsWatched: PropTypes.func,
onMarkSeasonAsWatched: PropTypes.func,
};
module.exports = Video;

View file

@ -56,6 +56,11 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect,
return a.episode - b.episode;
});
}, [videos, selectedSeason]);
const seasonWatched = React.useMemo(() => {
return videosForSeason.every((video) => video.watched);
}, [videosForSeason]);
const [search, setSearch] = React.useState('');
const searchInputOnChange = React.useCallback((event) => {
setSearch(event.currentTarget.value);
@ -71,6 +76,16 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect,
});
};
const onMarkSeasonAsWatched = (season, watched) => {
core.transport.dispatch({
action: 'MetaDetails',
args: {
action: 'MarkSeasonAsWatched',
args: [season, !watched]
}
});
};
return (
<div className={classnames(className, styles['videos-list-container'])}>
{
@ -135,6 +150,7 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect,
id={video.id}
title={video.title}
thumbnail={video.thumbnail}
season={video.season}
episode={video.episode}
released={video.released}
upcoming={video.upcoming}
@ -142,7 +158,9 @@ const VideosList = ({ className, metaItem, libraryItem, season, seasonOnSelect,
progress={video.progress}
deepLinks={video.deepLinks}
scheduled={video.scheduled}
seasonWatched={seasonWatched}
onMarkVideoAsWatched={onMarkVideoAsWatched}
onMarkSeasonAsWatched={onMarkSeasonAsWatched}
/>
))
}

View file

@ -47,6 +47,10 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
setSeason(parseInt(event.value));
}, []);
const seasonWatched = React.useMemo(() => {
return videos.every((video) => video.watched);
}, [videos]);
const onMarkVideoAsWatched = useCallback((video: Video, watched: boolean) => {
core.transport.dispatch({
action: 'Player',
@ -57,6 +61,16 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
});
}, []);
const onMarkSeasonAsWatched = (season: number, watched: boolean) => {
core.transport.dispatch({
action: 'MetaDetails',
args: {
action: 'MarkSeasonAsWatched',
args: [season, !watched]
}
});
};
const onMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};
@ -95,14 +109,17 @@ const SideDrawer = memo(forwardRef<HTMLDivElement, Props>(({ seriesInfo, classNa
id={video.id}
title={video.title}
thumbnail={video.thumbnail}
season={video.season}
episode={video.episode}
released={video.released}
upcoming={video.upcoming}
watched={video.watched}
seasonWatched={seasonWatched}
progress={video.progress}
deepLinks={video.deepLinks}
scheduled={video.scheduled}
onMarkVideoAsWatched={onMarkVideoAsWatched}
onMarkSeasonAsWatched={onMarkSeasonAsWatched}
/>
))}
</div>