mirror of
https://github.com/p-stream/p-stream.git
synced 2026-03-11 17:55:33 +00:00
Delete duplicate code and unify source selecting views
There were two because one was used on the atoms settings menu and the other was in place of ScrapePart prior to video playback
This commit is contained in:
parent
9a6bb041b2
commit
28d03a06a5
2 changed files with 14 additions and 162 deletions
|
|
@ -21,6 +21,7 @@ export interface SourceSelectionViewProps {
|
|||
export interface EmbedSelectionViewProps {
|
||||
id: string;
|
||||
sourceId: string | null;
|
||||
onBack?: () => void;
|
||||
}
|
||||
|
||||
export function EmbedOption(props: {
|
||||
|
|
@ -60,7 +61,11 @@ export function EmbedOption(props: {
|
|||
);
|
||||
}
|
||||
|
||||
export function EmbedSelectionView({ sourceId, id }: EmbedSelectionViewProps) {
|
||||
export function EmbedSelectionView({
|
||||
sourceId,
|
||||
id,
|
||||
onBack,
|
||||
}: EmbedSelectionViewProps) {
|
||||
const { t } = useTranslation();
|
||||
const router = useOverlayRouter(id);
|
||||
const { run, watching, notfound, loading, items, errored } =
|
||||
|
|
@ -126,7 +131,7 @@ export function EmbedSelectionView({ sourceId, id }: EmbedSelectionViewProps) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Menu.BackLink onClick={() => router.navigate("/source")}>
|
||||
<Menu.BackLink onClick={onBack || (() => router.navigate("/source"))}>
|
||||
{sourceName}
|
||||
</Menu.BackLink>
|
||||
<Menu.Section>{content}</Menu.Section>
|
||||
|
|
|
|||
|
|
@ -1,164 +1,20 @@
|
|||
import { ScrapeMedia } from "@p-stream/providers";
|
||||
import React, { ReactNode, useEffect, useMemo, useRef } from "react";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { getCachedMetadata } from "@/backend/helpers/providerApi";
|
||||
import { Loading } from "@/components/layout/Loading";
|
||||
import {
|
||||
useEmbedScraping,
|
||||
useSourceScraping,
|
||||
} from "@/components/player/hooks/useSourceSelection";
|
||||
EmbedSelectionView,
|
||||
SourceSelectionView,
|
||||
} from "@/components/player/atoms/settings/SourceSelectingView";
|
||||
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
|
||||
export function SourceSelectPart(props: { media: ScrapeMedia }) {
|
||||
export function SourceSelectPart(_props: { media: ScrapeMedia }) {
|
||||
const { t } = useTranslation();
|
||||
const [selectedSourceId, setSelectedSourceId] = React.useState<string | null>(
|
||||
null,
|
||||
);
|
||||
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) {
|
||||
return (
|
||||
|
|
@ -167,7 +23,7 @@ export function SourceSelectPart(props: { media: ScrapeMedia }) {
|
|||
<Menu.CardWithScrollable>
|
||||
<EmbedSelectionView
|
||||
sourceId={selectedSourceId}
|
||||
routerId={routerId}
|
||||
id={routerId}
|
||||
onBack={() => setSelectedSourceId(null)}
|
||||
/>
|
||||
</Menu.CardWithScrollable>
|
||||
|
|
@ -181,16 +37,7 @@ export function SourceSelectPart(props: { media: ScrapeMedia }) {
|
|||
<div className="w-full max-w-md h-[50vh] flex flex-col">
|
||||
<Menu.CardWithScrollable>
|
||||
<Menu.Title>{t("player.menus.sources.title")}</Menu.Title>
|
||||
<Menu.Section className="pb-4">
|
||||
{sources.map((v) => (
|
||||
<SelectableLink
|
||||
key={v.id}
|
||||
onClick={() => setSelectedSourceId(v.id)}
|
||||
>
|
||||
{v.name}
|
||||
</SelectableLink>
|
||||
))}
|
||||
</Menu.Section>
|
||||
<SourceSelectionView id={routerId} onChoose={setSelectedSourceId} />
|
||||
</Menu.CardWithScrollable>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue