feat: add episode selector

This commit is contained in:
Kentai Radiquum 2025-03-15 22:19:11 +05:00
parent 1b765fe857
commit cdce98b7e6
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
3 changed files with 148 additions and 30 deletions

View file

@ -1,3 +1,122 @@
export const EpisodeSelector = () => {
return <div>EPISODES</div>
"use client";
import { ENDPOINTS } from "#/api/config";
import { useState, useEffect } from "react";
import { Swiper, SwiperSlide } from "swiper/react";
import "swiper/css";
import "swiper/css/navigation";
import "swiper/css/mousewheel";
import "swiper/css/scrollbar";
import { Navigation, Mousewheel, Scrollbar } from "swiper/modules";
import { Button } from "flowbite-react";
import {
getAnonEpisodesWatched,
saveAnonEpisodeWatched,
} from "./ReleasePlayer";
interface Episode {
id: number;
position: number;
name: string;
is_watched: boolean;
}
interface Source {
id: number;
name: string;
episodes_count: number;
}
export const EpisodeSelector = (props: {
availableEpisodes: Episode[];
episode: Episode;
setEpisode: any;
source: Source;
release: any;
voiceover: any;
token: string | null;
}) => {
let anonEpisodesWatched = getAnonEpisodesWatched(
props.release,
props.source.id,
props.voiceover.id
);
anonEpisodesWatched =
anonEpisodesWatched[props.release][props.source.id][props.voiceover.id];
async function saveEpisodeToHistory(episode: Episode) {
if (episode && props.token) {
fetch(
`${ENDPOINTS.statistic.addHistory}/${props.release}/${props.source.id}/${episode.position}?token=${props.token}`
);
fetch(
`${ENDPOINTS.statistic.markWatched}/${props.release}/${props.source.id}/${episode.position}?token=${props.token}`
);
}
}
return (
<div>
<Swiper
modules={[Navigation, Mousewheel, Scrollbar]}
spaceBetween={8}
slidesPerView={"auto"}
direction={"horizontal"}
mousewheel={{
enabled: true,
sensitivity: 4,
}}
scrollbar={true}
allowTouchMove={true}
style={
{
"--swiper-scrollbar-bottom": "0",
} as React.CSSProperties
}
>
{props.availableEpisodes.map((episode: Episode) => (
<SwiperSlide
key={`episode_${episode.position}`}
style={{ maxWidth: "fit-content" }}
>
<Button
color={
props.episode.position === episode.position ? "blue" : "light"
}
theme={{ base: "w-full disabled:opacity-100" }}
onClick={() => {
props.availableEpisodes[episode.position - 1].is_watched = true;
saveAnonEpisodeWatched(
props.release,
props.source.id,
props.voiceover.id,
episode.position
);
saveEpisodeToHistory(episode);
props.setEpisode({
selected: { ...episode, is_watched: true },
available: props.availableEpisodes,
});
}}
disabled={props.episode.position === episode.position}
>
<div className="flex items-center">
{episode.name}
{(
episode.is_watched ||
Object.keys(anonEpisodesWatched).includes(
episode.position.toString()
)
) ?
<span className="w-4 h-4 ml-2 iconify material-symbols--check-circle"></span>
: <span className="w-4 h-4 ml-2 iconify material-symbols--check-circle-outline"></span>
}
</div>
</Button>
</SwiperSlide>
))}
</Swiper>
</div>
);
};

View file

@ -32,7 +32,7 @@ async function _fetch(url: string) {
return data;
}
const getAnonEpisodesWatched = (
export const getAnonEpisodesWatched = (
Release: number,
Source: number,
Voiceover: number
@ -80,7 +80,7 @@ const getAnonCurrentEpisodeWatched = (
return anonEpisodesWatched[Release][Source][Voiceover][Episode];
};
const saveAnonEpisodeWatched = (
export const saveAnonEpisodeWatched = (
Release: number,
Source: number,
Voiceover: number,

View file

@ -57,9 +57,11 @@ export const ReleasePlayerCustom = (props: {
voiceover_id: number,
source_id: number
) => {
const response = await fetch(
`${ENDPOINTS.release.episode}/${release_id}/${voiceover_id}/${source_id}`
);
let url = `${ENDPOINTS.release.episode}/${release_id}/${voiceover_id}/${source_id}`
if (props.token) {
url += `?token=${props.token}`;
}
const response = await fetch(url);
const data = await response.json();
return data;
};
@ -196,7 +198,7 @@ export const ReleasePlayerCustom = (props: {
episode.selected.url
);
SetPlayerProps({
src: `${manifest}`,
src: manifest,
poster: poster,
useCustom: true,
});
@ -214,7 +216,7 @@ export const ReleasePlayerCustom = (props: {
}, [episode.selected]);
return (
<Card>
<Card className="h-full">
{(
!voiceover.selected ||
!source.selected ||
@ -237,27 +239,24 @@ export const ReleasePlayerCustom = (props: {
setSource={setSource}
/>
</div>
{
playerProps.useCustom ?
<MediaThemeSutro>
<HlsVideo
slot="media"
src={playerProps.src}
poster={playerProps.poster}
preload="auto"
muted
crossOrigin=""
/>
</MediaThemeSutro>
// @ts-ignore
// <Player
// src={playerProps.src}
// poster={playerProps.poster}
// className="w-full aspect-video"
// type="hls"
// />
: <iframe src={playerProps.src} className="w-full aspect-video" />
}
{playerProps.useCustom ?
<MediaThemeSutro className="w-full aspect-video">
<HlsVideo
slot="media"
src={playerProps.src}
poster={playerProps.poster}
/>
</MediaThemeSutro>
: <iframe src={playerProps.src} className="w-full aspect-video" />}
<EpisodeSelector
availableEpisodes={episode.available}
episode={episode.selected}
setEpisode={setEpisode}
release={props.id}
source={source.selected}
voiceover={voiceover.selected}
token={props.token}
/>
</div>
}
</Card>