mirror of
https://github.com/p-stream/p-stream.git
synced 2026-04-18 21:22:14 +00:00
add embed order on admin page
This commit is contained in:
parent
aef4745e61
commit
6a50fec37b
8 changed files with 146 additions and 9 deletions
|
|
@ -1029,7 +1029,10 @@
|
|||
"lowPerformanceModeLabel": "Low performance mode",
|
||||
"sourceOrder": "Reordering sources",
|
||||
"sourceOrderDescription": "Drag and drop to reorder sources. This will determine the order in which sources are checked for the media you are trying to watch. If a source is greyed out, it means the <bold>extension</bold> is required for that source. <br><br> <strong>(The default order is best for most users)</strong>",
|
||||
"sourceOrderEnableLabel": "Custom source order"
|
||||
"sourceOrderEnableLabel": "Custom source order",
|
||||
"embedOrder": "Reordering embeds",
|
||||
"embedOrderDescription": "Drag and drop to reorder embeds. This will determine the order in which embeds are checked for the media you are trying to watch. <br><br> <strong>(The default order is best for most users)</strong>",
|
||||
"embedOrderEnableLabel": "Custom embed order"
|
||||
},
|
||||
"reset": "Reset",
|
||||
"save": "Save",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ export interface SettingsInput {
|
|||
forceCompactEpisodeView?: boolean;
|
||||
sourceOrder?: string[];
|
||||
enableSourceOrder?: boolean;
|
||||
embedOrder?: string[];
|
||||
enableEmbedOrder?: boolean;
|
||||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
enableNativeSubtitles?: boolean;
|
||||
|
|
@ -43,6 +45,8 @@ export interface SettingsResponse {
|
|||
enableCarouselView?: boolean;
|
||||
sourceOrder?: string[];
|
||||
enableSourceOrder?: boolean;
|
||||
embedOrder?: string[];
|
||||
enableEmbedOrder?: boolean;
|
||||
proxyTmdb?: boolean;
|
||||
enableLowPerformanceMode?: boolean;
|
||||
enableNativeSubtitles?: boolean;
|
||||
|
|
|
|||
|
|
@ -73,9 +73,19 @@ export function makeProviderUrl(base: string) {
|
|||
addQueryDataToUrl(url, { id: sourceId });
|
||||
return url.toString();
|
||||
},
|
||||
scrapeAll(media: ScrapeMedia) {
|
||||
scrapeAll(
|
||||
media: ScrapeMedia,
|
||||
sourceOrder?: string[],
|
||||
embedOrder?: string[],
|
||||
) {
|
||||
const url = makeUrl("/scrape");
|
||||
addQueryDataToUrl(url, scrapeMediaToQueryMedia(media));
|
||||
if (sourceOrder && sourceOrder.length > 0) {
|
||||
url.searchParams.set("sourceOrder", sourceOrder.join(","));
|
||||
}
|
||||
if (embedOrder && embedOrder.length > 0) {
|
||||
url.searchParams.set("embedOrder", embedOrder.join(","));
|
||||
}
|
||||
return url.toString();
|
||||
},
|
||||
scrapeEmbed(embedId: string, embedUrl: string) {
|
||||
|
|
|
|||
|
|
@ -155,6 +155,8 @@ export function useScrape() {
|
|||
|
||||
const preferredSourceOrder = usePreferencesStore((s) => s.sourceOrder);
|
||||
const enableSourceOrder = usePreferencesStore((s) => s.enableSourceOrder);
|
||||
const preferredEmbedOrder = usePreferencesStore((s) => s.embedOrder);
|
||||
const enableEmbedOrder = usePreferencesStore((s) => s.enableEmbedOrder);
|
||||
|
||||
const startScraping = useCallback(
|
||||
async (media: ScrapeMedia) => {
|
||||
|
|
@ -163,7 +165,11 @@ export function useScrape() {
|
|||
startScrape();
|
||||
const baseUrlMaker = makeProviderUrl(providerApiUrl);
|
||||
const conn = await connectServerSideEvents<RunOutput | "">(
|
||||
baseUrlMaker.scrapeAll(media),
|
||||
baseUrlMaker.scrapeAll(
|
||||
media,
|
||||
enableSourceOrder ? preferredSourceOrder : undefined,
|
||||
enableEmbedOrder ? preferredEmbedOrder : undefined,
|
||||
),
|
||||
["completed", "noOutput"],
|
||||
);
|
||||
conn.on("init", initEvent);
|
||||
|
|
@ -183,6 +189,8 @@ export function useScrape() {
|
|||
media,
|
||||
// Only pass sourceOrder if enableSourceOrder is true
|
||||
sourceOrder: enableSourceOrder ? preferredSourceOrder : undefined,
|
||||
// Only pass embedOrder if enableEmbedOrder is true
|
||||
embedOrder: enableEmbedOrder ? preferredEmbedOrder : undefined,
|
||||
events: {
|
||||
init: initEvent,
|
||||
start: startEvent,
|
||||
|
|
@ -203,6 +211,8 @@ export function useScrape() {
|
|||
startScrape,
|
||||
preferredSourceOrder,
|
||||
enableSourceOrder,
|
||||
preferredEmbedOrder,
|
||||
enableEmbedOrder,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -151,6 +151,11 @@ export function SettingsPage() {
|
|||
const sourceOrder = usePreferencesStore((s) => s.sourceOrder);
|
||||
const setSourceOrder = usePreferencesStore((s) => s.setSourceOrder);
|
||||
|
||||
const enableSourceOrder = usePreferencesStore((s) => s.enableSourceOrder);
|
||||
const setEnableSourceOrder = usePreferencesStore(
|
||||
(s) => s.setEnableSourceOrder,
|
||||
);
|
||||
|
||||
const enableDiscover = usePreferencesStore((s) => s.enableDiscover);
|
||||
const setEnableDiscover = usePreferencesStore((s) => s.setEnableDiscover);
|
||||
|
||||
|
|
@ -165,11 +170,6 @@ export function SettingsPage() {
|
|||
const enableImageLogos = usePreferencesStore((s) => s.enableImageLogos);
|
||||
const setEnableImageLogos = usePreferencesStore((s) => s.setEnableImageLogos);
|
||||
|
||||
const enableSourceOrder = usePreferencesStore((s) => s.enableSourceOrder);
|
||||
const setEnableSourceOrder = usePreferencesStore(
|
||||
(s) => s.setEnableSourceOrder,
|
||||
);
|
||||
|
||||
const proxyTmdb = usePreferencesStore((s) => s.proxyTmdb);
|
||||
const setProxyTmdb = usePreferencesStore((s) => s.setProxyTmdb);
|
||||
|
||||
|
|
@ -348,6 +348,7 @@ export function SettingsPage() {
|
|||
setEnableDetailsModal(state.enableDetailsModal.state);
|
||||
setEnableImageLogos(state.enableImageLogos.state);
|
||||
setSourceOrder(state.sourceOrder.state);
|
||||
setEnableSourceOrder(state.enableSourceOrder.state);
|
||||
setAppLanguage(state.appLanguage.state);
|
||||
setTheme(state.theme.state);
|
||||
setSubStyling(state.subtitleStyling.state);
|
||||
|
|
@ -389,6 +390,7 @@ export function SettingsPage() {
|
|||
setEnableDetailsModal,
|
||||
setEnableImageLogos,
|
||||
setSourceOrder,
|
||||
setEnableSourceOrder,
|
||||
setAppLanguage,
|
||||
setTheme,
|
||||
setSubStyling,
|
||||
|
|
@ -397,7 +399,6 @@ export function SettingsPage() {
|
|||
updateProfile,
|
||||
logout,
|
||||
setBackendUrl,
|
||||
setEnableSourceOrder,
|
||||
setProxyTmdb,
|
||||
setEnableCarouselView,
|
||||
setForceCompactEpisodeView,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { TMDBTestPart } from "@/pages/parts/admin/TMDBTestPart";
|
|||
import { WorkerTestPart } from "@/pages/parts/admin/WorkerTestPart";
|
||||
|
||||
import { BackendTestPart } from "../parts/admin/BackendTestPart";
|
||||
import { EmbedOrderPart } from "../parts/admin/EmbedOrderPart";
|
||||
|
||||
export function AdminPage() {
|
||||
return (
|
||||
|
|
@ -22,6 +23,7 @@ export function AdminPage() {
|
|||
<TMDBTestPart />
|
||||
<M3U8TestPart />
|
||||
<RegionSelectorPart />
|
||||
<EmbedOrderPart />
|
||||
</ThinContainer>
|
||||
</SubPageLayout>
|
||||
);
|
||||
|
|
|
|||
91
src/pages/parts/admin/EmbedOrderPart.tsx
Normal file
91
src/pages/parts/admin/EmbedOrderPart.tsx
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import { useMemo } from "react";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { getAllProviders, getProviders } from "@/backend/providers/providers";
|
||||
import { Button } from "@/components/buttons/Button";
|
||||
import { Toggle } from "@/components/buttons/Toggle";
|
||||
import { SortableList } from "@/components/form/SortableList";
|
||||
import { Heading2 } from "@/components/utils/Text";
|
||||
import { usePreferencesStore } from "@/stores/preferences";
|
||||
|
||||
export function EmbedOrderPart() {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const embedOrder = usePreferencesStore((s) => s.embedOrder);
|
||||
const setEmbedOrder = usePreferencesStore((s) => s.setEmbedOrder);
|
||||
const enableEmbedOrder = usePreferencesStore((s) => s.enableEmbedOrder);
|
||||
const setEnableEmbedOrder = usePreferencesStore((s) => s.setEnableEmbedOrder);
|
||||
|
||||
const allEmbeds = getAllProviders().listEmbeds();
|
||||
|
||||
const embedItems = useMemo(() => {
|
||||
const currentDeviceEmbeds = getProviders().listEmbeds();
|
||||
|
||||
// If embed order is empty, show all available embeds
|
||||
if (embedOrder.length === 0) {
|
||||
return allEmbeds.map((e) => ({
|
||||
id: e.id,
|
||||
name: e.name || e.id,
|
||||
disabled: !currentDeviceEmbeds.find((embed) => embed.id === e.id),
|
||||
}));
|
||||
}
|
||||
|
||||
// Otherwise, show embeds in the specified order
|
||||
return embedOrder.map((id) => ({
|
||||
id,
|
||||
name: allEmbeds.find((e) => e.id === id)?.name || id,
|
||||
disabled: !currentDeviceEmbeds.find((e) => e.id === id),
|
||||
}));
|
||||
}, [embedOrder, allEmbeds]);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<Heading2>Embed Order Settings</Heading2>
|
||||
<div className="flex flex-col gap-3">
|
||||
<p className="text-white font-bold">
|
||||
{t("settings.preferences.embedOrder")}
|
||||
</p>
|
||||
<div className="max-w-[25rem] font-medium">
|
||||
<Trans
|
||||
i18nKey="settings.preferences.embedOrderDescription"
|
||||
components={{
|
||||
bold: (
|
||||
<span
|
||||
className="text-type-link font-bold cursor-pointer"
|
||||
onClick={() => navigate("/onboarding/extension")}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
onClick={() => setEnableEmbedOrder(!enableEmbedOrder)}
|
||||
className="bg-dropdown-background hover:bg-dropdown-hoverBackground select-none my-4 cursor-pointer space-x-3 flex items-center max-w-[25rem] py-3 px-4 rounded-lg"
|
||||
>
|
||||
<Toggle enabled={enableEmbedOrder} />
|
||||
<p className="flex-1 text-white font-bold">
|
||||
{t("settings.preferences.embedOrderEnableLabel")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{enableEmbedOrder && (
|
||||
<div className="w-full flex flex-col gap-4">
|
||||
<SortableList
|
||||
items={embedItems}
|
||||
setItems={(items) => setEmbedOrder(items.map((item) => item.id))}
|
||||
/>
|
||||
<Button
|
||||
className="max-w-[25rem]"
|
||||
theme="secondary"
|
||||
onClick={() => setEmbedOrder(allEmbeds.map((e) => e.id))}
|
||||
>
|
||||
{t("settings.reset")}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,6 +14,8 @@ export interface PreferencesStore {
|
|||
forceCompactEpisodeView: boolean;
|
||||
sourceOrder: string[];
|
||||
enableSourceOrder: boolean;
|
||||
embedOrder: string[];
|
||||
enableEmbedOrder: boolean;
|
||||
proxyTmdb: boolean;
|
||||
febboxKey: string | null;
|
||||
realDebridKey: string | null;
|
||||
|
|
@ -31,6 +33,8 @@ export interface PreferencesStore {
|
|||
setForceCompactEpisodeView(v: boolean): void;
|
||||
setSourceOrder(v: string[]): void;
|
||||
setEnableSourceOrder(v: boolean): void;
|
||||
setEmbedOrder(v: string[]): void;
|
||||
setEnableEmbedOrder(v: boolean): void;
|
||||
setProxyTmdb(v: boolean): void;
|
||||
setFebboxKey(v: string | null): void;
|
||||
setRealDebridKey(v: string | null): void;
|
||||
|
|
@ -52,6 +56,8 @@ export const usePreferencesStore = create(
|
|||
forceCompactEpisodeView: false,
|
||||
sourceOrder: [],
|
||||
enableSourceOrder: false,
|
||||
embedOrder: [],
|
||||
enableEmbedOrder: false,
|
||||
proxyTmdb: false,
|
||||
febboxKey: null,
|
||||
realDebridKey: null,
|
||||
|
|
@ -112,6 +118,16 @@ export const usePreferencesStore = create(
|
|||
s.enableSourceOrder = v;
|
||||
});
|
||||
},
|
||||
setEmbedOrder(v) {
|
||||
set((s) => {
|
||||
s.embedOrder = v;
|
||||
});
|
||||
},
|
||||
setEnableEmbedOrder(v) {
|
||||
set((s) => {
|
||||
s.enableEmbedOrder = v;
|
||||
});
|
||||
},
|
||||
setProxyTmdb(v) {
|
||||
set((s) => {
|
||||
s.proxyTmdb = v;
|
||||
|
|
|
|||
Loading…
Reference in a new issue