mirror of
https://github.com/movie-web/movie-web.git
synced 2024-12-29 15:36:11 +00:00
Merge pull request #938 from qtchaos/remove-domain
Remove references to official domain
This commit is contained in:
commit
9e4241e464
2
.github/CODE_OF_CONDUCT.md
vendored
2
.github/CODE_OF_CONDUCT.md
vendored
|
@ -60,7 +60,7 @@ representative at an online or offline event.
|
||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
reported to the community leaders responsible for enforcement at
|
reported to the community leaders responsible for enforcement at
|
||||||
codeofconduct@movie-web.app.
|
our [Discord](https://discord.gg/gQYB6fGArX).
|
||||||
All complaints will be reviewed and investigated promptly and fairly.
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and security of the
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
|
6
.github/CONTRIBUTING.md
vendored
6
.github/CONTRIBUTING.md
vendored
|
@ -1,6 +1,6 @@
|
||||||
# Contributing Guidelines for movie-web
|
# Contributing Guidelines for movie-web
|
||||||
|
|
||||||
Thank you for investing your time in contributing to our project! Your contribution will be reflected on [movie-web.app](https://movie-web.app).
|
Thank you for investing your time in contributing to our project! Your contribution will be reflected on all of the community hosted instances that are on the latest version.
|
||||||
|
|
||||||
Please read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
|
Please read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ There are two places where to request features or report bugs:
|
||||||
### Discord Server
|
### Discord Server
|
||||||
If you do not have a GitHub account or want to discuss a feature or bug with us before making an issue, you can join our Discord server.
|
If you do not have a GitHub account or want to discuss a feature or bug with us before making an issue, you can join our Discord server.
|
||||||
|
|
||||||
<a href="https://discord.movie-web.app"><img src="https://discord.com/api/guilds/871713465100816424/widget.png?style=banner2" alt="Discord Server"></a>
|
<a href="https://discord.gg/gQYB6fGArX"><img src="https://discord.com/api/guilds/871713465100816424/widget.png?style=banner2" alt="Discord Server"></a>
|
||||||
|
|
||||||
### GitHub Issues
|
### GitHub Issues
|
||||||
To make a GitHub issue for movie-web, please visit the [new issue page](https://github.com/movie-web/movie-web/issues/new/choose) where you can pick either the "Bug Report" or "Feature Request" template.
|
To make a GitHub issue for movie-web, please visit the [new issue page](https://github.com/movie-web/movie-web/issues/new/choose) where you can pick either the "Bug Report" or "Feature Request" template.
|
||||||
|
@ -85,7 +85,7 @@ Here are some tips to make sure that your pull requests are :pinched_fingers: fi
|
||||||
### Language Contributions
|
### Language Contributions
|
||||||
Language contributions help movie-web massively, allowing people worldwide to use our app!
|
Language contributions help movie-web massively, allowing people worldwide to use our app!
|
||||||
|
|
||||||
We use weblate for crowdsourcing our translations. [Click here to go to our translation tool.](https://weblate.movie-web.app/projects/movie-web/website/)
|
We use weblate for crowdsourcing our translations.
|
||||||
|
|
||||||
1. First make sure you make an account. (click the link above)
|
1. First make sure you make an account. (click the link above)
|
||||||
2. Click the language you want to help translate, if it's not listed you can click the plus top left to add a new language.
|
2. Click the language you want to help translate, if it's not listed you can click the plus top left to add a new language.
|
||||||
|
|
9
.github/SECURITY.md
vendored
9
.github/SECURITY.md
vendored
|
@ -2,12 +2,9 @@
|
||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
The movie-web maintainers only support the latest version of movie-web published at https://movie-web.app.
|
The latest version of movie-web is the only version that is supported, as it is the only version that is being actively developed.
|
||||||
|
|
||||||
Support is not provided for any forks or mirrors of movie-web.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
There are two ways you can contact the movie-web maintainers to report a vulnerability:
|
You can contact the movie-web maintainers to report a vulnerability:
|
||||||
- Email [security@movie-web.app](mailto:security@movie-web.app)
|
- Report the vulnerability in the [movie-web Discord server](https://discord.gg/gQYB6fGArX)
|
||||||
- Report the vulnerability in the [movie-web Discord server](https://discord.movie-web.app)
|
|
||||||
|
|
|
@ -4,13 +4,13 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://skillicons.dev/icons?i=react,vite,ts" />
|
<img src="https://skillicons.dev/icons?i=react,vite,ts" />
|
||||||
<br/>
|
<br/>
|
||||||
<a href="https://discord.movie-web.app"><kbd>🔵 discord</kbd></a> <a href="https://movie-web.app"><kbd>🟢 website</kbd></a>
|
<a href="https://discord.gg/gQYB6fGArX"><kbd>🔵 discord</kbd></a> <a href="https://movie-web.github.io/docs"><kbd>🟢 docs</kbd></a>
|
||||||
</p>
|
</p>
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
|
|
||||||
# ⚡What is movie-web?
|
# ⚡What is movie-web?
|
||||||
|
|
||||||
movie-web is a web app for watching movies easily. Check it out at <a href="https://movie-web.app"><kbd>movie-web.app</kbd></a>.
|
movie-web is a web app for watching movies easily.
|
||||||
|
|
||||||
This service works by displaying video files from third-party providers inside an intuitive and aesthetic user interface.
|
This service works by displaying video files from third-party providers inside an intuitive and aesthetic user interface.
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ pnpm build
|
||||||
|
|
||||||
A simple guide has been written to assist in hosting your own instance of movie-web. Check it out below
|
A simple guide has been written to assist in hosting your own instance of movie-web. Check it out below
|
||||||
|
|
||||||
|[Selfhosting guide](https://docs.movie-web.app)|
|
|[Selfhosting guide](https://movie-web.github.io/docs)|
|
||||||
|---|
|
|---|
|
||||||
|
|
||||||
## 🤝 Thanks to all Contributors
|
## 🤝 Thanks to all Contributors
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "movie-web",
|
"name": "movie-web",
|
||||||
"version": "4.4.2",
|
"version": "4.4.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"homepage": "https://movie-web.app",
|
"homepage": "https://github.com/movie-web/movie-web",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
|
|
@ -11,7 +11,7 @@ window.__CONFIG__ = {
|
||||||
// Whether to disable hash-based routing, leave this as false if you don't know what this is
|
// Whether to disable hash-based routing, leave this as false if you don't know what this is
|
||||||
VITE_NORMAL_ROUTER: false,
|
VITE_NORMAL_ROUTER: false,
|
||||||
|
|
||||||
// The backend URL to communicate with, defaults to the movie-web hosted one at backend.movie-web.app
|
// The backend URL to communicate with
|
||||||
VITE_BACKEND_URL: null,
|
VITE_BACKEND_URL: null,
|
||||||
|
|
||||||
// A comma separated list of disallowed IDs in the case of a DMCA claim - in the format "series-<id>" and "movie-<id>"
|
// A comma separated list of disallowed IDs in the case of a DMCA claim - in the format "series-<id>" and "movie-<id>"
|
||||||
|
|
|
@ -55,6 +55,8 @@
|
||||||
"text": "Did you configure it correctly?",
|
"text": "Did you configure it correctly?",
|
||||||
"title": "Failed to reach server"
|
"title": "Failed to reach server"
|
||||||
},
|
},
|
||||||
|
"noHostTitle": "Server not configured!",
|
||||||
|
"noHost": "The server has not been configured, therefore you cannot create an account",
|
||||||
"host": "You are connecting to <0>{{hostname}}</0> - please confirm you trust it before making an account",
|
"host": "You are connecting to <0>{{hostname}}</0> - please confirm you trust it before making an account",
|
||||||
"no": "Go back",
|
"no": "Go back",
|
||||||
"title": "Do you trust this server?",
|
"title": "Do you trust this server?",
|
||||||
|
|
|
@ -5,13 +5,14 @@ import { useCallback } from "react";
|
||||||
|
|
||||||
import { isExtensionActiveCached } from "@/backend/extension/messaging";
|
import { isExtensionActiveCached } from "@/backend/extension/messaging";
|
||||||
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
|
import { ScrapingItems, ScrapingSegment } from "@/hooks/useProviderScrape";
|
||||||
|
import { BACKEND_URL } from "@/setup/constants";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
import { PlayerMeta } from "@/stores/player/slices/source";
|
import { PlayerMeta } from "@/stores/player/slices/source";
|
||||||
|
|
||||||
// for anybody who cares - these are anonymous metrics.
|
// for anybody who cares - these are anonymous metrics.
|
||||||
// They are just used for figuring out if providers are broken or not
|
// They are just used for figuring out if providers are broken or not
|
||||||
const metricsEndpoint = "https://backend.movie-web.app/metrics/providers";
|
const metricsEndpoint = `${BACKEND_URL}/metrics/providers`;
|
||||||
const captchaMetricsEndpoint = "https://backend.movie-web.app/metrics/captcha";
|
const captchaMetricsEndpoint = `${BACKEND_URL}/metrics/captcha`;
|
||||||
const batchId = () => nanoid(32);
|
const batchId = () => nanoid(32);
|
||||||
|
|
||||||
export type ProviderMetric = {
|
export type ProviderMetric = {
|
||||||
|
@ -44,6 +45,7 @@ function getStackTrace(error: Error, lines: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reportProviders(items: ProviderMetric[]): Promise<void> {
|
export async function reportProviders(items: ProviderMetric[]): Promise<void> {
|
||||||
|
if (!BACKEND_URL) return;
|
||||||
return ofetch(metricsEndpoint, {
|
return ofetch(metricsEndpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: {
|
body: {
|
||||||
|
@ -156,6 +158,7 @@ export function useReportProviders() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reportCaptchaSolve(success: boolean) {
|
export function reportCaptchaSolve(success: boolean) {
|
||||||
|
if (!BACKEND_URL) return;
|
||||||
ofetch(captchaMetricsEndpoint, {
|
ofetch(captchaMetricsEndpoint, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: {
|
body: {
|
||||||
|
|
|
@ -63,6 +63,7 @@ export function useAuth() {
|
||||||
|
|
||||||
const login = useCallback(
|
const login = useCallback(
|
||||||
async (loginData: LoginData) => {
|
async (loginData: LoginData) => {
|
||||||
|
if (!backendUrl) return;
|
||||||
const keys = await keysFromMnemonic(loginData.mnemonic);
|
const keys = await keysFromMnemonic(loginData.mnemonic);
|
||||||
const publicKeyBase64Url = bytesToBase64Url(keys.publicKey);
|
const publicKeyBase64Url = bytesToBase64Url(keys.publicKey);
|
||||||
const { challenge } = await getLoginChallengeToken(
|
const { challenge } = await getLoginChallengeToken(
|
||||||
|
@ -87,7 +88,7 @@ export function useAuth() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const logout = useCallback(async () => {
|
const logout = useCallback(async () => {
|
||||||
if (!currentAccount) return;
|
if (!currentAccount || !backendUrl) return;
|
||||||
try {
|
try {
|
||||||
await removeSession(
|
await removeSession(
|
||||||
backendUrl,
|
backendUrl,
|
||||||
|
@ -102,6 +103,7 @@ export function useAuth() {
|
||||||
|
|
||||||
const register = useCallback(
|
const register = useCallback(
|
||||||
async (registerData: RegistrationData) => {
|
async (registerData: RegistrationData) => {
|
||||||
|
if (!backendUrl) return;
|
||||||
const { challenge } = await getRegisterChallengeToken(
|
const { challenge } = await getRegisterChallengeToken(
|
||||||
backendUrl,
|
backendUrl,
|
||||||
registerData.recaptchaToken,
|
registerData.recaptchaToken,
|
||||||
|
@ -134,6 +136,7 @@ export function useAuth() {
|
||||||
progressItems: Record<string, ProgressMediaItem>,
|
progressItems: Record<string, ProgressMediaItem>,
|
||||||
bookmarks: Record<string, BookmarkMediaItem>,
|
bookmarks: Record<string, BookmarkMediaItem>,
|
||||||
) => {
|
) => {
|
||||||
|
if (!backendUrl) return;
|
||||||
if (
|
if (
|
||||||
Object.keys(progressItems).length === 0 &&
|
Object.keys(progressItems).length === 0 &&
|
||||||
Object.keys(bookmarks).length === 0
|
Object.keys(bookmarks).length === 0
|
||||||
|
@ -159,6 +162,7 @@ export function useAuth() {
|
||||||
|
|
||||||
const restore = useCallback(
|
const restore = useCallback(
|
||||||
async (account: AccountWithToken) => {
|
async (account: AccountWithToken) => {
|
||||||
|
if (!backendUrl) return;
|
||||||
let user: { user: UserResponse; session: SessionResponse };
|
let user: { user: UserResponse; session: SessionResponse };
|
||||||
try {
|
try {
|
||||||
user = await getUser(backendUrl, account.token);
|
user = await getUser(backendUrl, account.token);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { conf } from "@/setup/config";
|
import { conf } from "@/setup/config";
|
||||||
import { useAuthStore } from "@/stores/auth";
|
import { useAuthStore } from "@/stores/auth";
|
||||||
|
|
||||||
export function useBackendUrl() {
|
export function useBackendUrl(): string | undefined {
|
||||||
const backendUrl = useAuthStore((s) => s.backendUrl);
|
const backendUrl = useAuthStore((s) => s.backendUrl);
|
||||||
return backendUrl ?? conf().BACKEND_URL;
|
return backendUrl ?? conf().BACKEND_URL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ export function AccountSettings(props: {
|
||||||
const url = useBackendUrl();
|
const url = useBackendUrl();
|
||||||
const { account } = props;
|
const { account } = props;
|
||||||
const [sessionsResult, execSessions] = useAsyncFn(() => {
|
const [sessionsResult, execSessions] = useAsyncFn(() => {
|
||||||
|
if (!url) return Promise.resolve([]);
|
||||||
return getSessions(url, account);
|
return getSessions(url, account);
|
||||||
}, [account, url]);
|
}, [account, url]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -144,7 +145,7 @@ export function SettingsPage() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const saveChanges = useCallback(async () => {
|
const saveChanges = useCallback(async () => {
|
||||||
if (account) {
|
if (account && backendUrl) {
|
||||||
if (
|
if (
|
||||||
state.appLanguage.changed ||
|
state.appLanguage.changed ||
|
||||||
state.theme.changed ||
|
state.theme.changed ||
|
||||||
|
|
|
@ -43,7 +43,7 @@ export function OnboardingProxyPage() {
|
||||||
throw new Error("onboarding.proxy.input.errorNotProxy");
|
throw new Error("onboarding.proxy.input.errorNotProxy");
|
||||||
setProxySet([url]);
|
setProxySet([url]);
|
||||||
|
|
||||||
if (account) {
|
if (account && backendUrl) {
|
||||||
await updateSettings(backendUrl, account, {
|
await updateSettings(backendUrl, account, {
|
||||||
proxyUrls: [url],
|
proxyUrls: [url],
|
||||||
});
|
});
|
||||||
|
|
|
@ -32,13 +32,21 @@ export function BackendTestPart() {
|
||||||
value: null,
|
value: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!backendUrl) {
|
||||||
|
return setStatus({
|
||||||
|
hasTested: true,
|
||||||
|
success: false,
|
||||||
|
errorText: "Backend URL is not set",
|
||||||
|
value: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const backendData = await getBackendMeta(backendUrl);
|
const backendData = await getBackendMeta(backendUrl);
|
||||||
return setStatus({
|
return setStatus({
|
||||||
hasTested: true,
|
hasTested: true,
|
||||||
success: true,
|
success: true,
|
||||||
errorText:
|
errorText: "",
|
||||||
"Failed to call backend, double check the URL key and your internet connection",
|
|
||||||
value: backendData,
|
value: backendData,
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -46,7 +54,7 @@ export function BackendTestPart() {
|
||||||
hasTested: true,
|
hasTested: true,
|
||||||
success: false,
|
success: false,
|
||||||
errorText:
|
errorText:
|
||||||
"Failed to call backend, double check the URL key and your internet connection",
|
"Failed to call backend, double check the URL, your internet connection, and ensure CORS is properly configured on your backend.",
|
||||||
value: null,
|
value: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,9 @@ export function LoginFormPart(props: LoginFormPartProps) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!account)
|
||||||
|
throw new Error(t("auth.login.validationError") ?? undefined);
|
||||||
|
|
||||||
await importData(account, progressItems, bookmarkItems);
|
await importData(account, progressItems, bookmarkItems);
|
||||||
|
|
||||||
await restore(account);
|
await restore(account);
|
||||||
|
|
|
@ -22,8 +22,12 @@ interface TrustBackendPartProps {
|
||||||
export function TrustBackendPart(props: TrustBackendPartProps) {
|
export function TrustBackendPart(props: TrustBackendPartProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const backendUrl = useBackendUrl();
|
const backendUrl = useBackendUrl();
|
||||||
const hostname = useMemo(() => new URL(backendUrl).hostname, [backendUrl]);
|
const hostname = useMemo(
|
||||||
|
() => (backendUrl ? new URL(backendUrl).hostname : undefined),
|
||||||
|
[backendUrl],
|
||||||
|
);
|
||||||
const result = useAsync(() => {
|
const result = useAsync(() => {
|
||||||
|
if (!backendUrl) return Promise.resolve(null);
|
||||||
return getBackendMeta(backendUrl);
|
return getBackendMeta(backendUrl);
|
||||||
}, [backendUrl]);
|
}, [backendUrl]);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -50,38 +54,52 @@ export function TrustBackendPart(props: TrustBackendPartProps) {
|
||||||
return (
|
return (
|
||||||
<LargeCard>
|
<LargeCard>
|
||||||
<LargeCardText
|
<LargeCardText
|
||||||
title={t("auth.trust.title")}
|
title={hostname ? t("auth.trust.title") : t("auth.trust.noHostTitle")}
|
||||||
icon={<Icon icon={Icons.CIRCLE_EXCLAMATION} />}
|
icon={<Icon icon={Icons.CIRCLE_EXCLAMATION} />}
|
||||||
>
|
>
|
||||||
<Trans
|
{hostname ? (
|
||||||
i18nKey="auth.trust.host"
|
<Trans
|
||||||
values={{
|
i18nKey="auth.trust.host"
|
||||||
hostname,
|
values={{
|
||||||
}}
|
hostname,
|
||||||
>
|
}}
|
||||||
<span className="text-white" />
|
>
|
||||||
</Trans>
|
<span className="text-white" />
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<p>{t("auth.trust.noHost")}</p>
|
||||||
|
)}
|
||||||
</LargeCardText>
|
</LargeCardText>
|
||||||
|
|
||||||
<div className="border border-authentication-border rounded-xl px-4 py-8 flex flex-col items-center space-y-2 my-8">
|
{hostname ? (
|
||||||
{cardContent}
|
<>
|
||||||
</div>
|
<div className="border border-authentication-border rounded-xl px-4 py-8 flex flex-col items-center space-y-2 my-8">
|
||||||
<LargeCardButtons>
|
{cardContent}
|
||||||
<Button theme="secondary" onClick={() => navigate("/")}>
|
</div>
|
||||||
{t("auth.trust.no")}
|
<LargeCardButtons>
|
||||||
</Button>
|
<Button theme="secondary" onClick={() => navigate("/")}>
|
||||||
<Button
|
{t("auth.trust.no")}
|
||||||
theme="purple"
|
</Button>
|
||||||
onClick={() => result.value && props.onNext?.(result.value)}
|
<Button
|
||||||
>
|
theme="purple"
|
||||||
{t("auth.trust.yes")}
|
onClick={() => result.value && props.onNext?.(result.value)}
|
||||||
</Button>
|
>
|
||||||
</LargeCardButtons>
|
{t("auth.trust.yes")}
|
||||||
<p className="text-center mt-6">
|
</Button>
|
||||||
<Trans i18nKey="auth.hasAccount">
|
</LargeCardButtons>
|
||||||
<MwLink to="/login">.</MwLink>
|
<p className="text-center mt-6">
|
||||||
</Trans>
|
<Trans i18nKey="auth.hasAccount">
|
||||||
</p>
|
<MwLink to="/login">.</MwLink>
|
||||||
|
</Trans>
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<LargeCardButtons>
|
||||||
|
<Button theme="purple" onClick={() => navigate("/")}>
|
||||||
|
{t("auth.trust.no")}
|
||||||
|
</Button>
|
||||||
|
</LargeCardButtons>
|
||||||
|
)}
|
||||||
</LargeCard>
|
</LargeCard>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,8 @@ export function VerifyPassphrase(props: VerifyPassphraseProps) {
|
||||||
|
|
||||||
const [result, execute] = useAsyncFn(
|
const [result, execute] = useAsyncFn(
|
||||||
async (inputMnemonic: string) => {
|
async (inputMnemonic: string) => {
|
||||||
|
if (!backendUrl)
|
||||||
|
throw new Error(t("auth.verify.noBackendUrl") ?? undefined);
|
||||||
if (!props.mnemonic || !props.userData)
|
if (!props.mnemonic || !props.userData)
|
||||||
throw new Error(t("auth.verify.invalidData") ?? undefined);
|
throw new Error(t("auth.verify.invalidData") ?? undefined);
|
||||||
|
|
||||||
|
@ -68,6 +70,9 @@ export function VerifyPassphrase(props: VerifyPassphraseProps) {
|
||||||
recaptchaToken,
|
recaptchaToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!account)
|
||||||
|
throw new Error(t("auth.verify.registrationFailed") ?? undefined);
|
||||||
|
|
||||||
await importData(account, progressItems, bookmarkItems);
|
await importData(account, progressItems, bookmarkItems);
|
||||||
|
|
||||||
await updateSettings(backendUrl, account, {
|
await updateSettings(backendUrl, account, {
|
||||||
|
|
|
@ -18,7 +18,7 @@ export function AccountActionsPart() {
|
||||||
const deleteModal = useModal("account-delete");
|
const deleteModal = useModal("account-delete");
|
||||||
|
|
||||||
const [deleteResult, deleteExec] = useAsyncFn(async () => {
|
const [deleteResult, deleteExec] = useAsyncFn(async () => {
|
||||||
if (!account) return;
|
if (!account || !url) return;
|
||||||
await deleteUser(url, account);
|
await deleteUser(url, account);
|
||||||
await logout();
|
await logout();
|
||||||
deleteModal.hide();
|
deleteModal.hide();
|
||||||
|
|
|
@ -55,7 +55,7 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
|
||||||
</p>
|
</p>
|
||||||
<p className="max-w-[20rem] font-medium">
|
<p className="max-w-[20rem] font-medium">
|
||||||
<Trans i18nKey="settings.connections.workers.description">
|
<Trans i18nKey="settings.connections.workers.description">
|
||||||
<MwLink to="https://docs.movie-web.app/proxy/deploy">
|
<MwLink to="https://movie-web.github.io/docs/proxy/deploy">
|
||||||
Proxy documentation
|
Proxy documentation
|
||||||
</MwLink>
|
</MwLink>
|
||||||
</Trans>
|
</Trans>
|
||||||
|
@ -125,7 +125,7 @@ function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
|
||||||
</p>
|
</p>
|
||||||
<p className="max-w-[20rem] font-medium">
|
<p className="max-w-[20rem] font-medium">
|
||||||
<Trans i18nKey="settings.connections.server.description">
|
<Trans i18nKey="settings.connections.server.description">
|
||||||
<MwLink to="https://docs.movie-web.app/backend/deploy">
|
<MwLink to="https://movie-web.github.io/docs/backend/deploy">
|
||||||
Backend documentation
|
Backend documentation
|
||||||
</MwLink>
|
</MwLink>
|
||||||
</Trans>
|
</Trans>
|
||||||
|
|
|
@ -24,6 +24,7 @@ export function Device(props: {
|
||||||
const token = useAuthStore((s) => s.account?.token);
|
const token = useAuthStore((s) => s.account?.token);
|
||||||
const [result, exec] = useAsyncFn(async () => {
|
const [result, exec] = useAsyncFn(async () => {
|
||||||
if (!token) throw new Error("No token present");
|
if (!token) throw new Error("No token present");
|
||||||
|
if (!url) throw new Error("No backend set");
|
||||||
await removeSession(url, token, props.id);
|
await removeSession(url, token, props.id);
|
||||||
props.onRemove?.();
|
props.onRemove?.();
|
||||||
}, [url, token, props.id]);
|
}, [url, token, props.id]);
|
||||||
|
|
|
@ -14,9 +14,9 @@ import { useAuthStore } from "@/stores/auth";
|
||||||
|
|
||||||
const rem = 16;
|
const rem = 16;
|
||||||
|
|
||||||
function SecureBadge(props: { url: string }) {
|
function SecureBadge(props: { url: string | undefined }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const secure = props.url.startsWith("https://");
|
const secure = props.url ? props.url.startsWith("https://") : false;
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1 -mx-1 ml-3 px-1 rounded bg-largeCard-background font-bold">
|
<div className="flex items-center gap-1 -mx-1 ml-3 px-1 rounded bg-largeCard-background font-bold">
|
||||||
<Icon icon={secure ? Icons.LOCK : Icons.UNLOCK} />
|
<Icon icon={secure ? Icons.LOCK : Icons.UNLOCK} />
|
||||||
|
@ -68,6 +68,7 @@ export function SidebarPart() {
|
||||||
const backendUrl = useBackendUrl();
|
const backendUrl = useBackendUrl();
|
||||||
|
|
||||||
const backendMeta = useAsync(async () => {
|
const backendMeta = useAsync(async () => {
|
||||||
|
if (!backendUrl) return;
|
||||||
return getBackendMeta(backendUrl);
|
return getBackendMeta(backendUrl);
|
||||||
}, [backendUrl]);
|
}, [backendUrl]);
|
||||||
|
|
||||||
|
@ -159,7 +160,7 @@ export function SidebarPart() {
|
||||||
<SecureBadge url={backendUrl} />
|
<SecureBadge url={backendUrl} />
|
||||||
</div>
|
</div>
|
||||||
<p className="text-white">
|
<p className="text-white">
|
||||||
{backendUrl.replace(/https?:\/\//, "")}
|
{backendUrl?.replace(/https?:\/\//, "") ?? "—"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export const APP_VERSION = import.meta.env.PACKAGE_VERSION;
|
export const APP_VERSION = import.meta.env.PACKAGE_VERSION;
|
||||||
export const DISCORD_LINK = "https://discord.movie-web.app";
|
export const DISCORD_LINK = "https://discord.gg/gQYB6fGArX";
|
||||||
export const GITHUB_LINK = "https://github.com/movie-web/movie-web";
|
export const GITHUB_LINK = "https://github.com/movie-web/movie-web";
|
||||||
export const DONATION_LINK = "https://ko-fi.com/movieweb";
|
export const DONATION_LINK = "https://ko-fi.com/movieweb";
|
||||||
export const GA_ID = "G-44YVXRL61C";
|
export const GA_ID = "G-44YVXRL61C";
|
||||||
export const BACKEND_URL = "https://backend.movie-web.app";
|
export const BACKEND_URL = import.meta.env.VITE_BACKEND_URL;
|
||||||
|
|
|
@ -60,6 +60,7 @@ export function BookmarkSyncer() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
if (!url) return;
|
||||||
const state = useBookmarkStore.getState();
|
const state = useBookmarkStore.getState();
|
||||||
const user = useAuthStore.getState();
|
const user = useAuthStore.getState();
|
||||||
await syncBookmarks(
|
await syncBookmarks(
|
||||||
|
|
|
@ -62,6 +62,7 @@ export function ProgressSyncer() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
if (!url) return;
|
||||||
const state = useProgressStore.getState();
|
const state = useProgressStore.getState();
|
||||||
const user = useAuthStore.getState();
|
const user = useAuthStore.getState();
|
||||||
await syncProgress(
|
await syncProgress(
|
||||||
|
|
|
@ -16,6 +16,7 @@ export function SettingsSyncer() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
(async () => {
|
(async () => {
|
||||||
|
if (!url) return;
|
||||||
const state = useSubtitleStore.getState();
|
const state = useSubtitleStore.getState();
|
||||||
const user = useAuthStore.getState();
|
const user = useAuthStore.getState();
|
||||||
if (state.lastSync.lastSelectedLanguage === state.lastSelectedLanguage)
|
if (state.lastSync.lastSelectedLanguage === state.lastSelectedLanguage)
|
||||||
|
|
Loading…
Reference in a new issue