feat: add a menu for selecting voiceover, source and episode inside of a player

This commit is contained in:
Kentai Radiquum 2025-04-09 17:11:08 +05:00
parent 0a5b8a59e6
commit 5264534693
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
5 changed files with 266 additions and 142 deletions

View file

@ -0,0 +1,131 @@
"use client";
import { ENDPOINTS } from "#/api/config";
import { useEffect, useState } from "react";
import { _fetchAPI } from "./PlayerParsing";
import { Voiceover } from "./VoiceoverSelectorMenu";
import { Source } from "./SourceSelectorMenu";
import { getAnonEpisodesWatched } from "./ReleasePlayer";
export interface Episode {
position: number;
name: string;
is_watched: boolean;
}
interface EpisodeSelectorMenuProps {
release_id: number;
voiceover: Voiceover;
source: Source;
token: string | null;
setEpisode: (state) => void;
episode: Episode;
episodeList: Episode[];
setPlayerError: (state) => void;
}
export const EpisodeSelectorMenu = ({
release_id,
token,
voiceover,
source,
setEpisode,
episode,
episodeList,
setPlayerError,
}: EpisodeSelectorMenuProps) => {
const [watchedEpisodes, setWatchedEpisodes] = useState([]);
useEffect(() => {
const __getInfo = async () => {
let url = `${ENDPOINTS.release.episode}/${release_id}/${voiceover.id}/${source.id}`;
if (token) {
url += `?token=${token}`;
}
const episodes = await _fetchAPI(
url,
"Не удалось получить информацию о эпизодах",
setPlayerError
);
if (episodes) {
let anonEpisodesWatched = getAnonEpisodesWatched(
release_id,
source.id,
voiceover.id
);
let lastEpisodeWatched = Math.max.apply(
0,
Object.keys(anonEpisodesWatched[release_id][source.id][voiceover.id])
);
let selectedEpisode =
episodes.episodes.find(
(episode: Episode) => episode.position == lastEpisodeWatched
) || episodes.episodes[0];
setEpisode({
selected: selectedEpisode,
available: episodes.episodes,
});
}
};
if (source) {
__getInfo();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [source]);
useEffect(() => {
if (release_id && source && voiceover) {
const anonEpisodesWatched = getAnonEpisodesWatched(
release_id,
source.id,
voiceover.id
);
setWatchedEpisodes(
anonEpisodesWatched[release_id][source.id][voiceover.id]
);
}
}, [release_id, source, voiceover]);
return (
<div className="flex flex-col items-start justify-start gap-4">
<p className="text-[20px] px-2 pt-2 pb-1 font-bold">Эпизод</p>
<div className="max-h-full flex flex-col gap-4 items-start justify-start overflow-x-hidden overflow-y-auto px-2 pb-2 scrollbar-thin scrollbar-thumb-[rgb(60_60_60_/_.8)] scrollbar-track-[rgb(30_30_30_/_.8)]">
{episodeList && episodeList.length > 0 ?
episodeList.map((epis: Episode) => {
return (
<button
key={`release-${release_id}-voiceover-${voiceover.id}-source-${source.id}-episode-${epis.position}`}
className={`h-fit px-2 justify-start items-start ${episode.position == epis.position ? "text-white" : "text-gray-400 hover:text-gray-100"} transition-colors`}
onClick={() => {
setEpisode({
selected: epis,
available: episodeList,
});
}}
>
<div className="flex items-center justify-between gap-2 min-w-32">
<p className="text-[16px] leading-none whitespace-nowrap">
{epis.name ?
epis.name
: ["Sibnet"].includes(source.name) ?
`${epis.position + 1} Серия`
: `${epis.position} Серия`}
</p>
{(
epis.is_watched ||
Object.keys(watchedEpisodes).includes(
epis.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>
);
})
: ""}
</div>
</div>
);
};