mirror of
https://github.com/movie-web/movie-web.git
synced 2024-11-14 07:55:07 +01:00
Merge branch 'dev' into extension
This commit is contained in:
commit
8a79924abd
2
.github/workflows/deploying.yml
vendored
2
.github/workflows/deploying.yml
vendored
@ -173,7 +173,7 @@ jobs:
|
|||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
push: true
|
push: true
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm
|
platforms: linux/amd64,linux/arm64
|
||||||
context: .
|
context: .
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
@ -416,14 +416,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"server": {
|
"server": {
|
||||||
"description": "If you would like to connect to a custom backend to store your data, enable this and provide the URL.",
|
"description": "If you would like to connect to a custom backend to store your data, enable this and provide the URL. <0>Instructions.</0>",
|
||||||
"label": "Custom server",
|
"label": "Custom server",
|
||||||
"urlLabel": "Custom server URL"
|
"urlLabel": "Custom server URL"
|
||||||
},
|
},
|
||||||
"title": "Connections",
|
"title": "Connections",
|
||||||
"workers": {
|
"workers": {
|
||||||
"addButton": "Add new worker",
|
"addButton": "Add new worker",
|
||||||
"description": "To make the application function, all traffic is routed through proxies. Enable this if you want to bring your own workers.",
|
"description": "To make the application function, all traffic is routed through proxies. Enable this if you want to bring your own workers. <0>Instructions.</0>",
|
||||||
"emptyState": "No workers yet, add one below",
|
"emptyState": "No workers yet, add one below",
|
||||||
"label": "Use custom proxy workers",
|
"label": "Use custom proxy workers",
|
||||||
"urlLabel": "Worker URLs",
|
"urlLabel": "Worker URLs",
|
||||||
|
@ -41,7 +41,7 @@ export function Button(props: Props) {
|
|||||||
props.padding ?? "px-4 py-3",
|
props.padding ?? "px-4 py-3",
|
||||||
props.className,
|
props.className,
|
||||||
colorClasses,
|
colorClasses,
|
||||||
props.disabled ? "cursor-not-allowed bg-opacity-60 text-opacity-60" : null,
|
props.disabled ? "!cursor-not-allowed bg-opacity-60 text-opacity-60" : null,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (props.disabled)
|
if (props.disabled)
|
||||||
|
@ -75,6 +75,7 @@ function CustomCaptionOption() {
|
|||||||
setCaption({
|
setCaption({
|
||||||
language: "custom",
|
language: "custom",
|
||||||
srtData: converted,
|
srtData: converted,
|
||||||
|
id: "custom-caption",
|
||||||
});
|
});
|
||||||
setCustomSubs();
|
setCustomSubs();
|
||||||
});
|
});
|
||||||
@ -115,39 +116,38 @@ function useSubtitleList(subs: CaptionListItem[], searchQuery: string) {
|
|||||||
export function CaptionsView({ id }: { id: string }) {
|
export function CaptionsView({ id }: { id: string }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const router = useOverlayRouter(id);
|
const router = useOverlayRouter(id);
|
||||||
const lang = usePlayerStore((s) => s.caption.selected?.language);
|
const selectedCaptionId = usePlayerStore((s) => s.caption.selected?.id);
|
||||||
const [currentlyDownloading, setCurrentlyDownloading] = useState<
|
const [currentlyDownloading, setCurrentlyDownloading] = useState<
|
||||||
string | null
|
string | null
|
||||||
>(null);
|
>(null);
|
||||||
const { selectLanguage, disable } = useCaptions();
|
const { selectCaptionById, disable } = useCaptions();
|
||||||
const captionList = usePlayerStore((s) => s.captionList);
|
const captionList = usePlayerStore((s) => s.captionList);
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const subtitleList = useSubtitleList(captionList, searchQuery);
|
const subtitleList = useSubtitleList(captionList, searchQuery);
|
||||||
|
|
||||||
const [downloadReq, startDownload] = useAsyncFn(
|
const [downloadReq, startDownload] = useAsyncFn(
|
||||||
async (language: string) => {
|
async (captionId: string) => {
|
||||||
setCurrentlyDownloading(language);
|
setCurrentlyDownloading(captionId);
|
||||||
return selectLanguage(language);
|
return selectCaptionById(captionId);
|
||||||
},
|
},
|
||||||
[selectLanguage, setCurrentlyDownloading],
|
[selectCaptionById, setCurrentlyDownloading],
|
||||||
);
|
);
|
||||||
|
|
||||||
const content = subtitleList.map((v, i) => {
|
const content = subtitleList.map((v, i) => {
|
||||||
return (
|
return (
|
||||||
<CaptionOption
|
<CaptionOption
|
||||||
// key must use index to prevent url collisions
|
// key must use index to prevent url collisions
|
||||||
// eslint-disable-next-line react/no-array-index-key
|
key={v.id}
|
||||||
key={`${i}-${v.url}`}
|
|
||||||
countryCode={v.language}
|
countryCode={v.language}
|
||||||
selected={lang === v.language}
|
selected={v.id === selectedCaptionId}
|
||||||
loading={v.language === currentlyDownloading && downloadReq.loading}
|
loading={v.id === currentlyDownloading && downloadReq.loading}
|
||||||
error={
|
error={
|
||||||
v.language === currentlyDownloading && downloadReq.error
|
v.id === currentlyDownloading && downloadReq.error
|
||||||
? downloadReq.error.toString()
|
? downloadReq.error.toString()
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
onClick={() => startDownload(v.language)}
|
onClick={() => startDownload(v.id)}
|
||||||
>
|
>
|
||||||
{v.languageName}
|
{v.languageName}
|
||||||
</CaptionOption>
|
</CaptionOption>
|
||||||
@ -176,7 +176,7 @@ export function CaptionsView({ id }: { id: string }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Menu.ScrollToActiveSection className="!pt-1 mt-2 pb-3">
|
<Menu.ScrollToActiveSection className="!pt-1 mt-2 pb-3">
|
||||||
<CaptionOption onClick={() => disable()} selected={!lang}>
|
<CaptionOption onClick={() => disable()} selected={!selectedCaptionId}>
|
||||||
{t("player.menus.subtitles.offChoice")}
|
{t("player.menus.subtitles.offChoice")}
|
||||||
</CaptionOption>
|
</CaptionOption>
|
||||||
<CustomCaptionOption />
|
<CustomCaptionOption />
|
||||||
|
@ -41,6 +41,7 @@ export interface DisplayMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DisplayCaption {
|
export interface DisplayCaption {
|
||||||
|
id: string;
|
||||||
srtData: string;
|
srtData: string;
|
||||||
language: string;
|
language: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
|
@ -14,22 +14,32 @@ export function useCaptions() {
|
|||||||
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
|
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
|
||||||
const captionList = usePlayerStore((s) => s.captionList);
|
const captionList = usePlayerStore((s) => s.captionList);
|
||||||
|
|
||||||
const selectLanguage = useCallback(
|
const selectCaptionById = useCallback(
|
||||||
async (language: string) => {
|
async (captionId: string) => {
|
||||||
const caption = captionList.find((v) => v.language === language);
|
const caption = captionList.find((v) => v.id === captionId);
|
||||||
if (!caption) return;
|
if (!caption) return;
|
||||||
const srtData = await downloadCaption(caption);
|
const srtData = await downloadCaption(caption);
|
||||||
setCaption({
|
setCaption({
|
||||||
|
id: caption.id,
|
||||||
language: caption.language,
|
language: caption.language,
|
||||||
srtData,
|
srtData,
|
||||||
url: caption.url,
|
url: caption.url,
|
||||||
});
|
});
|
||||||
resetSubtitleSpecificSettings();
|
resetSubtitleSpecificSettings();
|
||||||
setLanguage(language);
|
setLanguage(caption.language);
|
||||||
},
|
},
|
||||||
[setLanguage, captionList, setCaption, resetSubtitleSpecificSettings],
|
[setLanguage, captionList, setCaption, resetSubtitleSpecificSettings],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selectLanguage = useCallback(
|
||||||
|
async (language: string) => {
|
||||||
|
const caption = captionList.find((v) => v.language === language);
|
||||||
|
if (!caption) return;
|
||||||
|
return selectCaptionById(caption.id);
|
||||||
|
},
|
||||||
|
[captionList, selectCaptionById],
|
||||||
|
);
|
||||||
|
|
||||||
const disable = useCallback(async () => {
|
const disable = useCallback(async () => {
|
||||||
setCaption(null);
|
setCaption(null);
|
||||||
setLanguage(null);
|
setLanguage(null);
|
||||||
@ -56,5 +66,6 @@ export function useCaptions() {
|
|||||||
selectLastUsedLanguage,
|
selectLastUsedLanguage,
|
||||||
toggleLastUsed,
|
toggleLastUsed,
|
||||||
selectLastUsedLanguageIfEnabled,
|
selectLastUsedLanguageIfEnabled,
|
||||||
|
selectCaptionById,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ export function convertProviderCaption(
|
|||||||
captions: RunOutput["stream"]["captions"],
|
captions: RunOutput["stream"]["captions"],
|
||||||
): CaptionListItem[] {
|
): CaptionListItem[] {
|
||||||
return captions.map((v) => ({
|
return captions.map((v) => ({
|
||||||
|
id: v.id,
|
||||||
language: v.language,
|
language: v.language,
|
||||||
url: v.url,
|
url: v.url,
|
||||||
needsProxy: v.hasCorsRestrictions,
|
needsProxy: v.hasCorsRestrictions,
|
||||||
|
@ -5,7 +5,6 @@ import { Avatar } from "@/components/Avatar";
|
|||||||
import { Button } from "@/components/buttons/Button";
|
import { Button } from "@/components/buttons/Button";
|
||||||
import { ColorPicker, initialColor } from "@/components/form/ColorPicker";
|
import { ColorPicker, initialColor } from "@/components/form/ColorPicker";
|
||||||
import { IconPicker, initialIcon } from "@/components/form/IconPicker";
|
import { IconPicker, initialIcon } from "@/components/form/IconPicker";
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
|
||||||
import {
|
import {
|
||||||
LargeCard,
|
LargeCard,
|
||||||
LargeCardButtons,
|
LargeCardButtons,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Dispatch, SetStateAction, useCallback } from "react";
|
import { Dispatch, SetStateAction, useCallback } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { Button } from "@/components/buttons/Button";
|
import { Button } from "@/components/buttons/Button";
|
||||||
import { Toggle } from "@/components/buttons/Toggle";
|
import { Toggle } from "@/components/buttons/Toggle";
|
||||||
import { Icon, Icons } from "@/components/Icon";
|
import { Icon, Icons } from "@/components/Icon";
|
||||||
import { SettingsCard } from "@/components/layout/SettingsCard";
|
import { SettingsCard } from "@/components/layout/SettingsCard";
|
||||||
|
import { MwLink } from "@/components/text/Link";
|
||||||
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
|
||||||
import { Divider } from "@/components/utils/Divider";
|
import { Divider } from "@/components/utils/Divider";
|
||||||
import { Heading1 } from "@/components/utils/Text";
|
import { Heading1 } from "@/components/utils/Text";
|
||||||
@ -53,7 +54,11 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
|
|||||||
{t("settings.connections.workers.label")}
|
{t("settings.connections.workers.label")}
|
||||||
</p>
|
</p>
|
||||||
<p className="max-w-[20rem] font-medium">
|
<p className="max-w-[20rem] font-medium">
|
||||||
{t("settings.connections.workers.description")}
|
<Trans i18nKey="settings.connections.workers.description">
|
||||||
|
<MwLink to="https://docs.movie-web.app/proxy/deploy">
|
||||||
|
Proxy documentation
|
||||||
|
</MwLink>
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -119,7 +124,11 @@ function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
|
|||||||
{t("settings.connections.server.label")}
|
{t("settings.connections.server.label")}
|
||||||
</p>
|
</p>
|
||||||
<p className="max-w-[20rem] font-medium">
|
<p className="max-w-[20rem] font-medium">
|
||||||
{t("settings.connections.server.description")}
|
<Trans i18nKey="settings.connections.server.description">
|
||||||
|
<MwLink to="https://docs.movie-web.app/backend/deploy">
|
||||||
|
Backend documentation
|
||||||
|
</MwLink>
|
||||||
|
</Trans>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -42,12 +42,14 @@ export interface PlayerMeta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Caption {
|
export interface Caption {
|
||||||
|
id: string;
|
||||||
language: string;
|
language: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
srtData: string;
|
srtData: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CaptionListItem {
|
export interface CaptionListItem {
|
||||||
|
id: string;
|
||||||
language: string;
|
language: string;
|
||||||
url: string;
|
url: string;
|
||||||
needsProxy: boolean;
|
needsProxy: boolean;
|
||||||
|
Loading…
Reference in New Issue
Block a user