move selectors into player

This commit is contained in:
Kentai Radiquum 2025-04-08 01:04:21 +05:00
parent 13a3cc5ca5
commit 4c0345ffab
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
4 changed files with 88 additions and 47 deletions

View file

@ -57,7 +57,7 @@ export const EpisodeSelector = (props: {
} }
return ( return (
<div> <div className="px-2 py-2 bg-black bg-opacity-75 backdrop-blur-md">
<Swiper <Swiper
modules={[Navigation, Mousewheel, Scrollbar]} modules={[Navigation, Mousewheel, Scrollbar]}
spaceBetween={8} spaceBetween={8}
@ -75,6 +75,7 @@ export const EpisodeSelector = (props: {
style={ style={
{ {
"--swiper-scrollbar-bottom": "0", "--swiper-scrollbar-bottom": "0",
"--swiper-scrollbar-drag-bg-color": "#ffffff"
} as React.CSSProperties } as React.CSSProperties
} }
> >
@ -82,7 +83,7 @@ export const EpisodeSelector = (props: {
<SwiperSlide <SwiperSlide
key={`episode_${episode.position}`} key={`episode_${episode.position}`}
style={{ maxWidth: "fit-content" }} style={{ maxWidth: "fit-content" }}
className="pb-2" className="pb-4"
> >
<Button <Button
color={ color={

View file

@ -16,6 +16,18 @@ import MediaThemeSutro from "./MediaThemeSutro";
import { getAnonEpisodesWatched } from "./ReleasePlayer"; import { getAnonEpisodesWatched } from "./ReleasePlayer";
import { tryCatchPlayer, tryCatchAPI } from "#/api/utils"; import { tryCatchPlayer, tryCatchAPI } from "#/api/utils";
import {
MediaController,
MediaControlBar,
MediaTimeRange,
MediaTimeDisplay,
MediaVolumeRange,
MediaPlayButton,
MediaSeekBackwardButton,
MediaSeekForwardButton,
MediaMuteButton,
} from "media-chrome/react";
export const ReleasePlayerCustom = (props: { export const ReleasePlayerCustom = (props: {
id: number; id: number;
token: string | null; token: string | null;
@ -112,7 +124,8 @@ export const ReleasePlayerCustom = (props: {
if (data) { if (data) {
let lowQualityLink = data.links["360"][0].src; // we assume that 360p is always present let lowQualityLink = data.links["360"][0].src; // we assume that 360p is always present
if (!lowQualityLink.includes("//")) { // check if link is encrypted, else do nothing if (!lowQualityLink.includes("//")) {
// check if link is encrypted, else do nothing
const decryptedBase64 = lowQualityLink.replace(/[a-zA-Z]/g, (e) => { const decryptedBase64 = lowQualityLink.replace(/[a-zA-Z]/g, (e) => {
return String.fromCharCode( return String.fromCharCode(
(e <= "Z" ? 90 : 122) >= (e = e.charCodeAt(0) + 18) ? e : e - 26 (e <= "Z" ? 90 : 122) >= (e = e.charCodeAt(0) + 18) ? e : e - 26
@ -121,14 +134,16 @@ export const ReleasePlayerCustom = (props: {
lowQualityLink = atob(decryptedBase64); lowQualityLink = atob(decryptedBase64);
} }
if (lowQualityLink.includes("https://")) { // string the https prefix, since we add it manually if (lowQualityLink.includes("https://")) {
// string the https prefix, since we add it manually
lowQualityLink = lowQualityLink.replace("https://", "//"); lowQualityLink = lowQualityLink.replace("https://", "//");
} }
let manifest = `https:${lowQualityLink.replace("360.mp4:hls:", "")}`; let manifest = `https:${lowQualityLink.replace("360.mp4:hls:", "")}`;
let poster = `https:${lowQualityLink.replace("360.mp4:hls:manifest.m3u8", "thumb001.jpg")}`; let poster = `https:${lowQualityLink.replace("360.mp4:hls:manifest.m3u8", "thumb001.jpg")}`;
if (lowQualityLink.includes("animetvseries")) { // if link includes "animetvseries" we need to construct manifest ourselves if (lowQualityLink.includes("animetvseries")) {
// if link includes "animetvseries" we need to construct manifest ourselves
let blobTxt = "#EXTM3U\n"; let blobTxt = "#EXTM3U\n";
if (data.links.hasOwnProperty("240")) { if (data.links.hasOwnProperty("240")) {
@ -365,27 +380,8 @@ export const ReleasePlayerCustom = (props: {
}, [episode.selected]); }, [episode.selected]);
return ( return (
<Card className="aspect-video min-h-min-h-[300px] sm:min-h-[466px] md:min-h-[540px] lg:min-h-[512px] xl:min-h-[608px] 2xl:min-h-[712px]"> <Card className="">
<div className="flex flex-wrap gap-4"> {/* <div className="flex items-center justify-center w-full h-full">
{voiceover.selected && (
<VoiceoverSelector
availableVoiceover={voiceover.available}
voiceover={voiceover.selected}
setVoiceover={setVoiceover}
release_id={props.id}
/>
)}
{source.selected && (
<SourceSelector
availableSource={source.available}
source={source.selected}
setSource={setSource}
release_id={props.id}
/>
)}
</div>
<div className="flex items-center justify-center w-full h-full">
{isLoading ? {isLoading ?
!playerError ? !playerError ?
<Spinner /> <Spinner />
@ -455,21 +451,65 @@ export const ReleasePlayerCustom = (props: {
allowFullScreen={true} allowFullScreen={true}
/> />
} }
</div> */}
<div className="flex items-center justify-center w-full h-full">
<MediaController className="relative w-full overflow-hidden">
<div className="absolute flex flex-wrap w-full gap-2 top-2 left-2">
{voiceover.selected && (
<VoiceoverSelector
availableVoiceover={voiceover.available}
voiceover={voiceover.selected}
setVoiceover={setVoiceover}
release_id={props.id}
/>
)}
{source.selected && (
<SourceSelector
availableSource={source.available}
source={source.selected}
setSource={setSource}
release_id={props.id}
/>
)}
</div>
<HlsVideo
className="object-contain h-full aspect-video"
slot="media"
src={playerProps.src}
poster={playerProps.poster}
defaultPlaybackRate={playbackRate}
onRateChange={(e) => {
// @ts-ignore
setPlaybackRate(e.target.playbackRate || 1);
}}
/>
<MediaControlBar>
<MediaPlayButton></MediaPlayButton>
<MediaSeekBackwardButton></MediaSeekBackwardButton>
<MediaSeekForwardButton></MediaSeekForwardButton>
<MediaTimeRange></MediaTimeRange>
<MediaTimeDisplay showDuration></MediaTimeDisplay>
<MediaMuteButton></MediaMuteButton>
<MediaVolumeRange></MediaVolumeRange>
</MediaControlBar>
{episode.selected && source.selected && voiceover.selected && (
<div className="w-full">
<EpisodeSelector
availableEpisodes={episode.available}
episode={episode.selected}
setEpisode={setEpisode}
release_id={props.id}
source={source.selected}
voiceover={voiceover.selected}
token={props.token}
/>
</div>
)}
</MediaController>
</div> </div>
<div> <div></div>
{episode.selected && source.selected && voiceover.selected && (
<EpisodeSelector
availableEpisodes={episode.available}
episode={episode.selected}
setEpisode={setEpisode}
release_id={props.id}
source={source.selected}
voiceover={voiceover.selected}
token={props.token}
/>
)}
</div>
</Card> </Card>
); );
}; };

View file

@ -12,10 +12,10 @@ interface Source {
const DropdownTrigger = ({ name }: Source) => { const DropdownTrigger = ({ name }: Source) => {
return ( return (
<div className="flex items-center gap-1 cursor-pointer"> <div className="flex items-center gap-2 px-2 py-1 bg-black bg-opacity-75 rounded-lg cursor-pointer backdrop-blur-md">
<span className="w-6 h-6 iconify material-symbols--motion-play"></span> <span className="w-6 h-6 text-white iconify material-symbols--motion-play"></span>
<p>{name}</p> <p className="text-white">{name}</p>
<span className="w-6 h-6 iconify material-symbols--arrow-drop-down"></span> <span className="w-6 h-6 -ml-2 text-white iconify material-symbols--arrow-drop-down"></span>
</div> </div>
); );
}; };

View file

@ -15,14 +15,14 @@ interface Voiceover {
const DropdownTrigger = ({ icon, name, pinned }: Voiceover) => { const DropdownTrigger = ({ icon, name, pinned }: Voiceover) => {
return ( return (
<div className="flex items-center gap-2 cursor-pointer"> <div className="flex items-center gap-2 px-2 py-1 bg-black bg-opacity-75 rounded-lg cursor-pointer backdrop-blur-md">
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
{icon && <img alt="" className="w-6 h-6 rounded-full" src={icon}></img>} {icon && <img alt="" className="w-6 h-6 rounded-full" src={icon}></img>}
<p>{name}</p> <p className="text-white">{name}</p>
{pinned && ( {pinned && (
<span className="h-6 bg-gray-700 dark:bg-gray-300 iconify material-symbols--push-pin"></span> <span className="h-6 bg-gray-300 iconify material-symbols--push-pin"></span>
)} )}
<span className="w-6 h-6 -ml-2 iconify material-symbols--arrow-drop-down"></span> <span className="w-6 h-6 -ml-2 text-white iconify material-symbols--arrow-drop-down"></span>
</div> </div>
); );
}; };