mirror of
https://github.com/Radiquum/AniX.git
synced 2025-04-19 16:04:41 +00:00
return source selection
This commit is contained in:
parent
0168daa6cc
commit
0a5b8a59e6
5 changed files with 128 additions and 224 deletions
|
@ -42,6 +42,7 @@ import {
|
||||||
MediaSettingsMenuItem,
|
MediaSettingsMenuItem,
|
||||||
} from "media-chrome/react/menu";
|
} from "media-chrome/react/menu";
|
||||||
import { VoiceoverSelectorMenu } from "./VoiceoverSelectorMenu";
|
import { VoiceoverSelectorMenu } from "./VoiceoverSelectorMenu";
|
||||||
|
import { SourceSelectorMenu } from "./SourceSelectorMenu";
|
||||||
|
|
||||||
export const ReleasePlayerCustom = (props: {
|
export const ReleasePlayerCustom = (props: {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -70,45 +71,6 @@ export const ReleasePlayerCustom = (props: {
|
||||||
// const [isErrorDetailsOpen, setIsErrorDetailsOpen] = useState(false);
|
// const [isErrorDetailsOpen, setIsErrorDetailsOpen] = useState(false);
|
||||||
// const [isLoading, setIsLoading] = useState(true);
|
// const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
// const playerPreferenceStore = useUserPlayerPreferencesStore();
|
|
||||||
// const preferredVO = playerPreferenceStore.getPreferredVoiceover(props.id);
|
|
||||||
// const preferredSource = playerPreferenceStore.getPreferredPlayer(props.id);
|
|
||||||
|
|
||||||
// old info fetching
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// const __getInfo = async () => {
|
|
||||||
// let url = `${ENDPOINTS.release.episode}/${props.id}/${voiceover.selected.id}`;
|
|
||||||
// const src = await _fetchAPI(
|
|
||||||
// url,
|
|
||||||
// "Не удалось получить информацию о источниках"
|
|
||||||
// );
|
|
||||||
// if (src) {
|
|
||||||
// const selectedSrc =
|
|
||||||
// src.sources.find((source: any) => source.name === preferredSource) ||
|
|
||||||
// src.sources[0];
|
|
||||||
// if (selectedSrc.episodes_count == 0) {
|
|
||||||
// const remSources = src.sources.filter(
|
|
||||||
// (source: any) => source.id !== selectedSrc.id
|
|
||||||
// );
|
|
||||||
// setSource({
|
|
||||||
// selected: remSources[0],
|
|
||||||
// available: remSources,
|
|
||||||
// });
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// setSource({
|
|
||||||
// selected: selectedSrc,
|
|
||||||
// available: src.sources,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// if (voiceover.selected) {
|
|
||||||
// __getInfo();
|
|
||||||
// }
|
|
||||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
// }, [voiceover.selected]);
|
|
||||||
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// const __getInfo = async () => {
|
// const __getInfo = async () => {
|
||||||
// let url = `${ENDPOINTS.release.episode}/${props.id}/${voiceover.selected.id}/${source.selected.id}`;
|
// let url = `${ENDPOINTS.release.episode}/${props.id}/${voiceover.selected.id}/${source.selected.id}`;
|
||||||
|
@ -364,6 +326,14 @@ export const ReleasePlayerCustom = (props: {
|
||||||
setVoiceover={setVoiceover}
|
setVoiceover={setVoiceover}
|
||||||
setPlayerError={setPlayerError}
|
setPlayerError={setPlayerError}
|
||||||
/>
|
/>
|
||||||
|
<SourceSelectorMenu
|
||||||
|
release_id={props.id}
|
||||||
|
voiceover={voiceover.selected}
|
||||||
|
source={source.selected}
|
||||||
|
sourceList={source.available}
|
||||||
|
setSource={setSource}
|
||||||
|
setPlayerError={setPlayerError}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</MediaChromeDialog>
|
</MediaChromeDialog>
|
||||||
<MediaControlBar className={`${Styles["media-control-bar"]}`}>
|
<MediaControlBar className={`${Styles["media-control-bar"]}`}>
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { Dropdown, DropdownItem } from "flowbite-react";
|
|
||||||
import { numberDeclension } from "#/api/utils";
|
|
||||||
import { useUserPlayerPreferencesStore } from "#/store/player";
|
|
||||||
|
|
||||||
interface Source {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
episodes_count: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DropdownTrigger = ({ name }: Source) => {
|
|
||||||
return (
|
|
||||||
<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 text-white iconify material-symbols--motion-play"></span>
|
|
||||||
<p className="text-white">{name}</p>
|
|
||||||
<span className="w-6 h-6 -ml-2 text-white iconify material-symbols--arrow-drop-down"></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DropdownItemInternal = ({ name, episodes_count }: Source) => {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-2 cursor-pointer">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p>{name}</p>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p>
|
|
||||||
{episodes_count}{" "}
|
|
||||||
{numberDeclension(episodes_count, "серия", "серии", "серий")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const SourceSelector = (props: {
|
|
||||||
availableSource: Source[];
|
|
||||||
source: Source;
|
|
||||||
setSource: any;
|
|
||||||
release_id: any;
|
|
||||||
}) => {
|
|
||||||
const playerPreferenceStore = useUserPlayerPreferencesStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
label=""
|
|
||||||
dismissOnClick={true}
|
|
||||||
renderTrigger={() => (
|
|
||||||
<span>
|
|
||||||
<DropdownTrigger {...props.source} />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{props.availableSource.map((source: Source) => (
|
|
||||||
<DropdownItem
|
|
||||||
key={`source_${source.id}`}
|
|
||||||
onClick={() => {
|
|
||||||
playerPreferenceStore.setPreferredPlayer(
|
|
||||||
props.release_id,
|
|
||||||
source.name
|
|
||||||
);
|
|
||||||
props.setSource({
|
|
||||||
selected: source,
|
|
||||||
available: props.availableSource,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownItemInternal {...source} />
|
|
||||||
</DropdownItem>
|
|
||||||
))}
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
};
|
|
115
app/components/ReleasePlayer/SourceSelectorMenu.tsx
Normal file
115
app/components/ReleasePlayer/SourceSelectorMenu.tsx
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ENDPOINTS } from "#/api/config";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
import { _fetchAPI } from "./PlayerParsing";
|
||||||
|
import { useUserPlayerPreferencesStore } from "#/store/player";
|
||||||
|
import { numberDeclension } from "#/api/utils";
|
||||||
|
import { Voiceover } from "./VoiceoverSelectorMenu";
|
||||||
|
|
||||||
|
export interface Source {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
episodes_count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SourceSelectorMenuProps {
|
||||||
|
release_id: number;
|
||||||
|
setSource: (state) => void;
|
||||||
|
voiceover: Voiceover;
|
||||||
|
source: Source;
|
||||||
|
sourceList: Source[];
|
||||||
|
setPlayerError: (state) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SourceSelectorMenu = ({
|
||||||
|
release_id,
|
||||||
|
setSource,
|
||||||
|
voiceover,
|
||||||
|
source,
|
||||||
|
sourceList,
|
||||||
|
setPlayerError,
|
||||||
|
}: SourceSelectorMenuProps) => {
|
||||||
|
const playerPreferenceStore = useUserPlayerPreferencesStore();
|
||||||
|
const preferredSource = playerPreferenceStore.getPreferredPlayer(release_id);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const __getInfo = async () => {
|
||||||
|
let url = `${ENDPOINTS.release.episode}/${release_id}/${voiceover.id}`;
|
||||||
|
const src = await _fetchAPI(
|
||||||
|
url,
|
||||||
|
"Не удалось получить информацию о источниках",
|
||||||
|
setPlayerError
|
||||||
|
);
|
||||||
|
if (src) {
|
||||||
|
const selectedSrc =
|
||||||
|
src.sources.find(
|
||||||
|
(source: Source) => source.name === preferredSource
|
||||||
|
) || src.sources[0];
|
||||||
|
if (selectedSrc.episodes_count == 0) {
|
||||||
|
const remSources = src.sources.filter(
|
||||||
|
(source: any) => source.id !== selectedSrc.id
|
||||||
|
);
|
||||||
|
setSource({
|
||||||
|
selected: remSources[0],
|
||||||
|
available: remSources,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSource({
|
||||||
|
selected: selectedSrc,
|
||||||
|
available: src.sources,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (voiceover) {
|
||||||
|
__getInfo();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [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)]">
|
||||||
|
{sourceList && sourceList.length > 0 ?
|
||||||
|
sourceList.map((src: Source) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={`release-${release_id}-voiceover-${voiceover.id}-source-${src.id}`}
|
||||||
|
className={`h-fit justify-start items-start ${source.id == src.id ? "text-white" : "text-gray-500 hover:text-gray-300"} transition-colors`}
|
||||||
|
onClick={() => {
|
||||||
|
setSource({
|
||||||
|
selected: src,
|
||||||
|
available: sourceList,
|
||||||
|
});
|
||||||
|
playerPreferenceStore.setPreferredPlayer(
|
||||||
|
release_id,
|
||||||
|
src.name
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="flex flex-col w-full gap-1">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="text-[16px] leading-none">{src.name}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<span>
|
||||||
|
{src.episodes_count || 0}{" "}
|
||||||
|
{numberDeclension(
|
||||||
|
src.episodes_count || 0,
|
||||||
|
"серия",
|
||||||
|
"серии",
|
||||||
|
"серий"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
: ""}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,104 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { Dropdown, DropdownItem } from "flowbite-react";
|
|
||||||
import { numberDeclension } from "#/api/utils";
|
|
||||||
import { useUserPlayerPreferencesStore } from "#/store/player";
|
|
||||||
|
|
||||||
interface Voiceover {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
icon: string;
|
|
||||||
episodes_count: number;
|
|
||||||
view_count: number;
|
|
||||||
pinned: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const DropdownTrigger = ({ icon, name, pinned }: Voiceover) => {
|
|
||||||
return (
|
|
||||||
<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 */}
|
|
||||||
{icon && <img alt="" className="w-6 h-6 rounded-full" src={icon}></img>}
|
|
||||||
<p className="text-white">{name}</p>
|
|
||||||
{pinned && (
|
|
||||||
<span className="h-6 bg-gray-300 iconify material-symbols--push-pin"></span>
|
|
||||||
)}
|
|
||||||
<span className="w-6 h-6 -ml-2 text-white iconify material-symbols--arrow-drop-down"></span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DropdownItemInternal = ({
|
|
||||||
icon,
|
|
||||||
name,
|
|
||||||
pinned,
|
|
||||||
episodes_count,
|
|
||||||
view_count,
|
|
||||||
}: Voiceover) => {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col gap-2 cursor-pointer">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
|
||||||
{icon && <img alt="" className="w-6 h-6 rounded-full" src={icon}></img>}
|
|
||||||
<p>{name}</p>
|
|
||||||
{pinned && (
|
|
||||||
<span className="h-6 iconify material-symbols--push-pin"></span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<p>
|
|
||||||
{episodes_count}{" "}
|
|
||||||
{numberDeclension(episodes_count, "серия", "серии", "серий")}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
{view_count}{" "}
|
|
||||||
{numberDeclension(view_count, "просмотр", "просмотра", "просмотров")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DropdownTheme = {
|
|
||||||
content: "md:grid md:grid-cols-2 xl:grid-cols-4 gap-2 w-full container",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const VoiceoverSelector = (props: {
|
|
||||||
availableVoiceover: Voiceover[];
|
|
||||||
voiceover: Voiceover;
|
|
||||||
setVoiceover: any;
|
|
||||||
release_id: number;
|
|
||||||
}) => {
|
|
||||||
const playerPreferenceStore = useUserPlayerPreferencesStore();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Dropdown
|
|
||||||
theme={DropdownTheme}
|
|
||||||
label=""
|
|
||||||
dismissOnClick={true}
|
|
||||||
renderTrigger={() => (
|
|
||||||
<span>
|
|
||||||
<DropdownTrigger {...props.voiceover} />
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{props.availableVoiceover.map((voiceover: Voiceover) => (
|
|
||||||
<DropdownItem
|
|
||||||
className="w-fit"
|
|
||||||
key={`voiceover_${voiceover.id}`}
|
|
||||||
onClick={() => {
|
|
||||||
playerPreferenceStore.setPreferredVoiceover(
|
|
||||||
props.release_id,
|
|
||||||
voiceover.name
|
|
||||||
);
|
|
||||||
props.setVoiceover({
|
|
||||||
selected: voiceover,
|
|
||||||
available: props.availableVoiceover,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DropdownItemInternal {...voiceover} />
|
|
||||||
</DropdownItem>
|
|
||||||
))}
|
|
||||||
</Dropdown>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -4,10 +4,9 @@ import { ENDPOINTS } from "#/api/config";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { _fetchAPI } from "./PlayerParsing";
|
import { _fetchAPI } from "./PlayerParsing";
|
||||||
import { useUserPlayerPreferencesStore } from "#/store/player";
|
import { useUserPlayerPreferencesStore } from "#/store/player";
|
||||||
import { Button } from "flowbite-react";
|
|
||||||
import { numberDeclension } from "#/api/utils";
|
import { numberDeclension } from "#/api/utils";
|
||||||
|
|
||||||
interface Voiceover {
|
export interface Voiceover {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
@ -50,7 +49,7 @@ export const VoiceoverSelectorMenu = ({
|
||||||
);
|
);
|
||||||
if (vo) {
|
if (vo) {
|
||||||
const selectedVO =
|
const selectedVO =
|
||||||
vo.types.find((voiceover: any) => voiceover.name === preferredVO) ||
|
vo.types.find((voiceover: Voiceover) => voiceover.name === preferredVO) ||
|
||||||
vo.types[0];
|
vo.types[0];
|
||||||
setVoiceover({
|
setVoiceover({
|
||||||
selected: selectedVO,
|
selected: selectedVO,
|
||||||
|
@ -64,8 +63,8 @@ export const VoiceoverSelectorMenu = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-start justify-start gap-4">
|
<div className="flex flex-col items-start justify-start gap-4">
|
||||||
<p className="text-[22px] px-2 py-2 font-bold">Озвучка</p>
|
<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 scrollbar-thin scrollbar-thumb-[rgb(60_60_60_/_.8)] scrollbar-track-[rgb(30_30_30_/_.8)]">
|
<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)]">
|
||||||
{voiceoverList && voiceoverList.length > 0 ?
|
{voiceoverList && voiceoverList.length > 0 ?
|
||||||
voiceoverList.map((vo: Voiceover) => {
|
voiceoverList.map((vo: Voiceover) => {
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Add table
Reference in a new issue