mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-21 07:12:17 +00:00
Revert "Delete duplicate code and unify source selecting views"
This reverts commit 28d03a06a5.
This commit is contained in:
parent
28d03a06a5
commit
40eb846a68
2 changed files with 162 additions and 14 deletions
|
|
@ -21,7 +21,6 @@ export interface SourceSelectionViewProps {
|
||||||
export interface EmbedSelectionViewProps {
|
export interface EmbedSelectionViewProps {
|
||||||
id: string;
|
id: string;
|
||||||
sourceId: string | null;
|
sourceId: string | null;
|
||||||
onBack?: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EmbedOption(props: {
|
export function EmbedOption(props: {
|
||||||
|
|
@ -61,11 +60,7 @@ export function EmbedOption(props: {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EmbedSelectionView({
|
export function EmbedSelectionView({ sourceId, id }: EmbedSelectionViewProps) {
|
||||||
sourceId,
|
|
||||||
id,
|
|
||||||
onBack,
|
|
||||||
}: EmbedSelectionViewProps) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useOverlayRouter(id);
|
const router = useOverlayRouter(id);
|
||||||
const { run, watching, notfound, loading, items, errored } =
|
const { run, watching, notfound, loading, items, errored } =
|
||||||
|
|
@ -131,7 +126,7 @@ export function EmbedSelectionView({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Menu.BackLink onClick={onBack || (() => router.navigate("/source"))}>
|
<Menu.BackLink onClick={() => router.navigate("/source")}>
|
||||||
{sourceName}
|
{sourceName}
|
||||||
</Menu.BackLink>
|
</Menu.BackLink>
|
||||||
<Menu.Section>{content}</Menu.Section>
|
<Menu.Section>{content}</Menu.Section>
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,164 @@
|
||||||
import { ScrapeMedia } from "@p-stream/providers";
|
import { ScrapeMedia } from "@p-stream/providers";
|
||||||
import React from "react";
|
import React, { ReactNode, useEffect, useMemo, useRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import { getCachedMetadata } from "@/backend/helpers/providerApi";
|
||||||
|
import { Loading } from "@/components/layout/Loading";
|
||||||
import {
|
import {
|
||||||
EmbedSelectionView,
|
useEmbedScraping,
|
||||||
SourceSelectionView,
|
useSourceScraping,
|
||||||
} from "@/components/player/atoms/settings/SourceSelectingView";
|
} from "@/components/player/hooks/useSourceSelection";
|
||||||
import { Menu } from "@/components/player/internals/ContextMenu";
|
import { Menu } from "@/components/player/internals/ContextMenu";
|
||||||
|
import { SelectableLink } from "@/components/player/internals/ContextMenu/Links";
|
||||||
|
import { usePreferencesStore } from "@/stores/preferences";
|
||||||
|
|
||||||
|
// Embed option component
|
||||||
|
function EmbedOption(props: {
|
||||||
|
embedId: string;
|
||||||
|
url: string;
|
||||||
|
sourceId: string;
|
||||||
|
routerId: string;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const unknownEmbedName = t("player.menus.sources.unknownOption");
|
||||||
|
|
||||||
|
const embedName = useMemo(() => {
|
||||||
|
if (!props.embedId) return unknownEmbedName;
|
||||||
|
const sourceMeta = getCachedMetadata().find((s) => s.id === props.embedId);
|
||||||
|
return sourceMeta?.name ?? unknownEmbedName;
|
||||||
|
}, [props.embedId, unknownEmbedName]);
|
||||||
|
|
||||||
|
const { run, errored, loading } = useEmbedScraping(
|
||||||
|
props.routerId,
|
||||||
|
props.sourceId,
|
||||||
|
props.url,
|
||||||
|
props.embedId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SelectableLink loading={loading} error={errored} onClick={run}>
|
||||||
|
<span className="flex flex-col">
|
||||||
|
<span>{embedName}</span>
|
||||||
|
</span>
|
||||||
|
</SelectableLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Embed selection view (when a source is selected)
|
||||||
|
function EmbedSelectionView(props: {
|
||||||
|
sourceId: string;
|
||||||
|
routerId: string;
|
||||||
|
onBack: () => void;
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { run, notfound, loading, items, errored } = useSourceScraping(
|
||||||
|
props.sourceId,
|
||||||
|
props.routerId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const sourceName = useMemo(() => {
|
||||||
|
if (!props.sourceId) return "...";
|
||||||
|
const sourceMeta = getCachedMetadata().find((s) => s.id === props.sourceId);
|
||||||
|
return sourceMeta?.name ?? "...";
|
||||||
|
}, [props.sourceId]);
|
||||||
|
|
||||||
|
const lastSourceId = useRef<string | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastSourceId.current === props.sourceId) return;
|
||||||
|
lastSourceId.current = props.sourceId;
|
||||||
|
if (!props.sourceId) return;
|
||||||
|
run();
|
||||||
|
}, [run, props.sourceId]);
|
||||||
|
|
||||||
|
let content: ReactNode = null;
|
||||||
|
if (loading)
|
||||||
|
content = (
|
||||||
|
<Menu.TextDisplay noIcon>
|
||||||
|
<Loading />
|
||||||
|
</Menu.TextDisplay>
|
||||||
|
);
|
||||||
|
else if (notfound)
|
||||||
|
content = (
|
||||||
|
<Menu.TextDisplay
|
||||||
|
title={t("player.menus.sources.noStream.title") ?? undefined}
|
||||||
|
>
|
||||||
|
{t("player.menus.sources.noStream.text")}
|
||||||
|
</Menu.TextDisplay>
|
||||||
|
);
|
||||||
|
else if (items?.length === 0)
|
||||||
|
content = (
|
||||||
|
<Menu.TextDisplay
|
||||||
|
title={t("player.menus.sources.noEmbeds.title") ?? undefined}
|
||||||
|
>
|
||||||
|
{t("player.menus.sources.noEmbeds.text")}
|
||||||
|
</Menu.TextDisplay>
|
||||||
|
);
|
||||||
|
else if (errored)
|
||||||
|
content = (
|
||||||
|
<Menu.TextDisplay
|
||||||
|
title={t("player.menus.sources.failed.title") ?? undefined}
|
||||||
|
>
|
||||||
|
{t("player.menus.sources.failed.text")}
|
||||||
|
</Menu.TextDisplay>
|
||||||
|
);
|
||||||
|
else if (items && props.sourceId)
|
||||||
|
content = items.map((v) => (
|
||||||
|
<EmbedOption
|
||||||
|
key={`${v.embedId}-${v.url}`}
|
||||||
|
embedId={v.embedId}
|
||||||
|
url={v.url}
|
||||||
|
routerId={props.routerId}
|
||||||
|
sourceId={props.sourceId}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Menu.BackLink onClick={props.onBack}>{sourceName}</Menu.BackLink>
|
||||||
|
<Menu.Section>{content}</Menu.Section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Main source selection view
|
// Main source selection view
|
||||||
export function SourceSelectPart(_props: { media: ScrapeMedia }) {
|
export function SourceSelectPart(props: { media: ScrapeMedia }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedSourceId, setSelectedSourceId] = React.useState<string | null>(
|
const [selectedSourceId, setSelectedSourceId] = React.useState<string | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const routerId = "manualSourceSelect";
|
const routerId = "manualSourceSelect";
|
||||||
|
const preferredSourceOrder = usePreferencesStore((s) => s.sourceOrder);
|
||||||
|
const enableSourceOrder = usePreferencesStore((s) => s.enableSourceOrder);
|
||||||
|
|
||||||
|
const sources = useMemo(() => {
|
||||||
|
const metaType = props.media.type;
|
||||||
|
if (!metaType) return [];
|
||||||
|
const allSources = getCachedMetadata()
|
||||||
|
.filter((v) => v.type === "source")
|
||||||
|
.filter((v) => v.mediaTypes?.includes(metaType));
|
||||||
|
|
||||||
|
if (!enableSourceOrder || preferredSourceOrder.length === 0) {
|
||||||
|
return allSources;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort sources according to preferred order
|
||||||
|
const orderedSources = [];
|
||||||
|
const remainingSources = [...allSources];
|
||||||
|
|
||||||
|
// Add sources in preferred order
|
||||||
|
for (const sourceId of preferredSourceOrder) {
|
||||||
|
const sourceIndex = remainingSources.findIndex((s) => s.id === sourceId);
|
||||||
|
if (sourceIndex !== -1) {
|
||||||
|
orderedSources.push(remainingSources[sourceIndex]);
|
||||||
|
remainingSources.splice(sourceIndex, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add remaining sources that weren't in the preferred order
|
||||||
|
orderedSources.push(...remainingSources);
|
||||||
|
|
||||||
|
return orderedSources;
|
||||||
|
}, [props.media.type, preferredSourceOrder, enableSourceOrder]);
|
||||||
|
|
||||||
if (selectedSourceId) {
|
if (selectedSourceId) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -23,7 +167,7 @@ export function SourceSelectPart(_props: { media: ScrapeMedia }) {
|
||||||
<Menu.CardWithScrollable>
|
<Menu.CardWithScrollable>
|
||||||
<EmbedSelectionView
|
<EmbedSelectionView
|
||||||
sourceId={selectedSourceId}
|
sourceId={selectedSourceId}
|
||||||
id={routerId}
|
routerId={routerId}
|
||||||
onBack={() => setSelectedSourceId(null)}
|
onBack={() => setSelectedSourceId(null)}
|
||||||
/>
|
/>
|
||||||
</Menu.CardWithScrollable>
|
</Menu.CardWithScrollable>
|
||||||
|
|
@ -37,7 +181,16 @@ export function SourceSelectPart(_props: { media: ScrapeMedia }) {
|
||||||
<div className="w-full max-w-md h-[50vh] flex flex-col">
|
<div className="w-full max-w-md h-[50vh] flex flex-col">
|
||||||
<Menu.CardWithScrollable>
|
<Menu.CardWithScrollable>
|
||||||
<Menu.Title>{t("player.menus.sources.title")}</Menu.Title>
|
<Menu.Title>{t("player.menus.sources.title")}</Menu.Title>
|
||||||
<SourceSelectionView id={routerId} onChoose={setSelectedSourceId} />
|
<Menu.Section className="pb-4">
|
||||||
|
{sources.map((v) => (
|
||||||
|
<SelectableLink
|
||||||
|
key={v.id}
|
||||||
|
onClick={() => setSelectedSourceId(v.id)}
|
||||||
|
>
|
||||||
|
{v.name}
|
||||||
|
</SelectableLink>
|
||||||
|
))}
|
||||||
|
</Menu.Section>
|
||||||
</Menu.CardWithScrollable>
|
</Menu.CardWithScrollable>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue