From cd02f6d7a3be25dc2a3eb6ee7d3898148328e90b Mon Sep 17 00:00:00 2001
From: Ashutosh Shinde
Date: Sat, 6 Jan 2024 13:40:04 +0530
Subject: [PATCH 001/151] fixed #614 multiple captions of the same language all
appeared as selected when selecting only one
---
.../player/atoms/settings/CaptionsView.tsx | 23 ++++++++++---------
.../player/display/displayInterface.ts | 1 +
src/components/player/hooks/useCaptions.ts | 19 +++++++++++++++
src/components/player/utils/captions.ts | 1 +
src/stores/player/slices/source.ts | 2 ++
5 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/src/components/player/atoms/settings/CaptionsView.tsx b/src/components/player/atoms/settings/CaptionsView.tsx
index dc9a112f..3d89655d 100644
--- a/src/components/player/atoms/settings/CaptionsView.tsx
+++ b/src/components/player/atoms/settings/CaptionsView.tsx
@@ -75,6 +75,7 @@ function CustomCaptionOption() {
setCaption({
language: "custom",
srtData: converted,
+ id: "custom-caption",
});
setCustomSubs();
});
@@ -115,22 +116,22 @@ function useSubtitleList(subs: CaptionListItem[], searchQuery: string) {
export function CaptionsView({ id }: { id: string }) {
const { t } = useTranslation();
const router = useOverlayRouter(id);
- const lang = usePlayerStore((s) => s.caption.selected?.language);
+ const selectedCaptionId = usePlayerStore((s) => s.caption.selected?.id);
const [currentlyDownloading, setCurrentlyDownloading] = useState<
string | null
>(null);
- const { selectLanguage, disable } = useCaptions();
+ const { selectCaptionById, disable } = useCaptions();
const captionList = usePlayerStore((s) => s.captionList);
const [searchQuery, setSearchQuery] = useState("");
const subtitleList = useSubtitleList(captionList, searchQuery);
const [downloadReq, startDownload] = useAsyncFn(
- async (language: string) => {
- setCurrentlyDownloading(language);
- return selectLanguage(language);
+ async (captionId: string) => {
+ setCurrentlyDownloading(captionId);
+ return selectCaptionById(captionId);
},
- [selectLanguage, setCurrentlyDownloading],
+ [selectCaptionById, setCurrentlyDownloading],
);
const content = subtitleList.map((v, i) => {
@@ -140,14 +141,14 @@ export function CaptionsView({ id }: { id: string }) {
// eslint-disable-next-line react/no-array-index-key
key={`${i}-${v.url}`}
countryCode={v.language}
- selected={lang === v.language}
- loading={v.language === currentlyDownloading && downloadReq.loading}
+ selected={v.id === selectedCaptionId}
+ loading={v.id === currentlyDownloading && downloadReq.loading}
error={
- v.language === currentlyDownloading && downloadReq.error
+ v.id === currentlyDownloading && downloadReq.error
? downloadReq.error.toString()
: undefined
}
- onClick={() => startDownload(v.language)}
+ onClick={() => startDownload(v.id)}
>
{v.languageName}
@@ -176,7 +177,7 @@ export function CaptionsView({ id }: { id: string }) {
- disable()} selected={!lang}>
+ disable()} selected={!selectedCaptionId}>
{t("player.menus.subtitles.offChoice")}
diff --git a/src/components/player/display/displayInterface.ts b/src/components/player/display/displayInterface.ts
index 604bdeca..8ba8480a 100644
--- a/src/components/player/display/displayInterface.ts
+++ b/src/components/player/display/displayInterface.ts
@@ -41,6 +41,7 @@ export interface DisplayMeta {
}
export interface DisplayCaption {
+ id: string;
srtData: string;
language: string;
url?: string;
diff --git a/src/components/player/hooks/useCaptions.ts b/src/components/player/hooks/useCaptions.ts
index 9f96c41c..0f79aa51 100644
--- a/src/components/player/hooks/useCaptions.ts
+++ b/src/components/player/hooks/useCaptions.ts
@@ -14,12 +14,30 @@ export function useCaptions() {
const lastSelectedLanguage = useSubtitleStore((s) => s.lastSelectedLanguage);
const captionList = usePlayerStore((s) => s.captionList);
+ const selectCaptionById = useCallback(
+ async (captionId: string) => {
+ const caption = captionList.find((v) => v.id === captionId);
+ if (!caption) return;
+ const srtData = await downloadCaption(caption);
+ setCaption({
+ id: caption.id,
+ language: caption.language,
+ srtData,
+ url: caption.url,
+ });
+ resetSubtitleSpecificSettings();
+ setLanguage(caption.language);
+ },
+ [setLanguage, captionList, setCaption, resetSubtitleSpecificSettings],
+ );
+
const selectLanguage = useCallback(
async (language: string) => {
const caption = captionList.find((v) => v.language === language);
if (!caption) return;
const srtData = await downloadCaption(caption);
setCaption({
+ id: caption.id,
language: caption.language,
srtData,
url: caption.url,
@@ -56,5 +74,6 @@ export function useCaptions() {
selectLastUsedLanguage,
toggleLastUsed,
selectLastUsedLanguageIfEnabled,
+ selectCaptionById,
};
}
diff --git a/src/components/player/utils/captions.ts b/src/components/player/utils/captions.ts
index abccee9f..bc2079db 100644
--- a/src/components/player/utils/captions.ts
+++ b/src/components/player/utils/captions.ts
@@ -80,6 +80,7 @@ export function convertProviderCaption(
captions: RunOutput["stream"]["captions"],
): CaptionListItem[] {
return captions.map((v) => ({
+ id: v.id,
language: v.language,
url: v.url,
needsProxy: v.hasCorsRestrictions,
diff --git a/src/stores/player/slices/source.ts b/src/stores/player/slices/source.ts
index 56e84f74..1e26abc2 100644
--- a/src/stores/player/slices/source.ts
+++ b/src/stores/player/slices/source.ts
@@ -42,12 +42,14 @@ export interface PlayerMeta {
}
export interface Caption {
+ id: string;
language: string;
url?: string;
srtData: string;
}
export interface CaptionListItem {
+ id: string;
language: string;
url: string;
needsProxy: boolean;
From 32dd68c90e0965c0321aa5c8f16446d73703c3ea Mon Sep 17 00:00:00 2001
From: Ashutosh Shinde
Date: Sat, 6 Jan 2024 23:18:54 +0530
Subject: [PATCH 002/151] updated CaptionOption key to use caption id instead
of index and url in CaptionView
---
src/components/player/atoms/settings/CaptionsView.tsx | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/components/player/atoms/settings/CaptionsView.tsx b/src/components/player/atoms/settings/CaptionsView.tsx
index 3d89655d..09ab5685 100644
--- a/src/components/player/atoms/settings/CaptionsView.tsx
+++ b/src/components/player/atoms/settings/CaptionsView.tsx
@@ -138,8 +138,7 @@ export function CaptionsView({ id }: { id: string }) {
return (
Date: Sat, 6 Jan 2024 23:19:06 +0530
Subject: [PATCH 003/151] updated selectLanguage callback to call
selectCaptionById after searching for correct caption
---
src/components/player/hooks/useCaptions.ts | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/src/components/player/hooks/useCaptions.ts b/src/components/player/hooks/useCaptions.ts
index 0f79aa51..424edcad 100644
--- a/src/components/player/hooks/useCaptions.ts
+++ b/src/components/player/hooks/useCaptions.ts
@@ -35,17 +35,9 @@ export function useCaptions() {
async (language: string) => {
const caption = captionList.find((v) => v.language === language);
if (!caption) return;
- const srtData = await downloadCaption(caption);
- setCaption({
- id: caption.id,
- language: caption.language,
- srtData,
- url: caption.url,
- });
- resetSubtitleSpecificSettings();
- setLanguage(language);
+ selectCaptionById(caption.id);
},
- [setLanguage, captionList, setCaption, resetSubtitleSpecificSettings],
+ [captionList, selectCaptionById],
);
const disable = useCallback(async () => {
From d71d082ed12d2606205f55505dd3b80e8d59901b Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 13:05:38 +0000
Subject: [PATCH 004/151] Update deploying.yml
---
.github/workflows/deploying.yml | 35 ++++++++++++++++++---------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/.github/workflows/deploying.yml b/.github/workflows/deploying.yml
index 9c642cf6..ebf9d131 100644
--- a/.github/workflows/deploying.yml
+++ b/.github/workflows/deploying.yml
@@ -12,16 +12,16 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
cache: 'pnpm'
- name: Install pnpm packages
@@ -31,7 +31,7 @@ jobs:
run: pnpm run build:pwa
- name: Upload production-ready build files
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: pwa
path: ./dist
@@ -42,16 +42,16 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
cache: 'pnpm'
- name: Install pnpm packages
@@ -61,7 +61,7 @@ jobs:
run: pnpm run build
- name: Upload production-ready build files
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: normal
path: ./dist
@@ -73,10 +73,10 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Download PWA artifact
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: pwa
path: ./dist_pwa
@@ -85,7 +85,7 @@ jobs:
run: cd dist_pwa && zip -r ../movie-web.pwa.zip .
- name: Download normal artifact
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
with:
name: normal
path: ./dist_normal
@@ -142,17 +142,17 @@ jobs:
steps:
- name: Checkout repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Setup Docker buildx
- uses: docker/setup-buildx-action@v2
+ uses: docker/setup-buildx-action@v3
- name: Get version
id: package-version
uses: martinbeentjes/npm-get-version-action@main
- name: Log into registry ${{ env.REGISTRY }}
- uses: docker/login-action@v2
+ uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
@@ -160,7 +160,7 @@ jobs:
- name: Extract Docker metadata
id: meta
- uses: docker/metadata-action@v4
+ uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
flavor: |
@@ -170,9 +170,12 @@ jobs:
- name: Build and push Docker image
id: build-and-push
- uses: docker/build-push-action@v4
+ uses: docker/build-push-action@v5
with:
push: true
+ platforms: linux/amd64,linux/arm64,linux/arm
context: .
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
From bb7f19fbae4aeafc72b5fb540b8cc52508537a86 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 13:08:01 +0000
Subject: [PATCH 005/151] Update action and Node versions for linting and
testing
---
.github/workflows/linting_testing.yml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/.github/workflows/linting_testing.yml b/.github/workflows/linting_testing.yml
index 4b2c2caa..497131bc 100644
--- a/.github/workflows/linting_testing.yml
+++ b/.github/workflows/linting_testing.yml
@@ -14,16 +14,16 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
cache: 'pnpm'
- name: Install pnpm packages
@@ -38,16 +38,16 @@ jobs:
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
with:
version: 8
- name: Install Node.js
- uses: actions/setup-node@v3
+ uses: actions/setup-node@v4
with:
- node-version: 18
+ node-version: 20
cache: 'pnpm'
- name: Install pnpm packages
From ff8661a644be3231b4098e54e541b9f0ccb37922 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 13:09:45 +0000
Subject: [PATCH 006/151] Update dockerfile to use Node 20
---
dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dockerfile b/dockerfile
index 5dd5465b..cc9b84be 100644
--- a/dockerfile
+++ b/dockerfile
@@ -1,4 +1,4 @@
-FROM node:16.15-alpine as build
+FROM node:20-alpine as build
WORKDIR /app
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
From a62c029514277ac4b1f2fd03f6dfc4c430c5c6b7 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 13:10:59 +0000
Subject: [PATCH 007/151] Rename dockerfile to have capital D
---
dockerfile => Dockerfile | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename dockerfile => Dockerfile (100%)
diff --git a/dockerfile b/Dockerfile
similarity index 100%
rename from dockerfile
rename to Dockerfile
From dcac36846805745a5ad9d11e5848b21be1b7e121 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 16:43:22 +0000
Subject: [PATCH 008/151] Use @rollup/wasm-node to allow building on ARM
---
package.json | 4 +-
pnpm-lock.yaml | 213 ++++++++++---------------------------------------
2 files changed, 47 insertions(+), 170 deletions(-)
diff --git a/package.json b/package.json
index 8620c18b..388054df 100644
--- a/package.json
+++ b/package.json
@@ -70,6 +70,7 @@
"@babel/core": "^7.23.6",
"@babel/preset-env": "^7.23.6",
"@babel/preset-typescript": "^7.23.3",
+ "@rollup/wasm-node": "^4.9.4",
"@types/chromecast-caf-sender": "^1.0.8",
"@types/crypto-js": "^4.2.1",
"@types/dompurify": "^3.0.5",
@@ -125,7 +126,8 @@
"get-func-name@<2.0.1": ">=2.0.1",
"postcss@<8.4.31": ">=8.4.31",
"@babel/traverse@<7.23.2": ">=7.23.2",
- "crypto-js@<4.2.0": ">=4.2.0"
+ "crypto-js@<4.2.0": ">=4.2.0",
+ "rollup": "npm:@rollup/wasm-node"
}
}
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 459ee71c..6d6bb9bd 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,6 +9,7 @@ overrides:
postcss@<8.4.31: '>=8.4.31'
'@babel/traverse@<7.23.2': '>=7.23.2'
crypto-js@<4.2.0: '>=4.2.0'
+ rollup: npm:@rollup/wasm-node
dependencies:
'@formkit/auto-animate':
@@ -139,6 +140,9 @@ devDependencies:
'@babel/preset-typescript':
specifier: ^7.23.3
version: 7.23.3(@babel/core@7.23.6)
+ '@rollup/wasm-node':
+ specifier: ^4.9.4
+ version: 4.9.4
'@types/chromecast-caf-sender':
specifier: ^1.0.8
version: 1.0.8
@@ -252,7 +256,7 @@ devDependencies:
version: 0.5.9(prettier@3.1.1)
rollup-plugin-visualizer:
specifier: ^5.11.0
- version: 5.11.0(rollup@2.79.1)
+ version: 5.11.0(@rollup/wasm-node@4.9.4)
tailwind-scrollbar:
specifier: ^3.0.5
version: 3.0.5(tailwindcss@3.4.0)
@@ -2029,163 +2033,68 @@ packages:
engines: {node: '>=14.0.0'}
dev: false
- /@rollup/plugin-babel@5.3.1(@babel/core@7.23.6)(rollup@2.79.1):
+ /@rollup/plugin-babel@5.3.1(@babel/core@7.23.6)(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
engines: {node: '>= 10.0.0'}
peerDependencies:
'@babel/core': ^7.0.0
'@types/babel__core': ^7.1.9
- rollup: ^1.20.0||^2.0.0
+ rollup: npm:@rollup/wasm-node
peerDependenciesMeta:
'@types/babel__core':
optional: true
dependencies:
'@babel/core': 7.23.6
'@babel/helper-module-imports': 7.22.15
- '@rollup/pluginutils': 3.1.0(rollup@2.79.1)
- rollup: 2.79.1
+ '@rollup/pluginutils': 3.1.0(@rollup/wasm-node@4.9.4)
+ rollup: /@rollup/wasm-node@4.9.4
dev: true
- /@rollup/plugin-node-resolve@11.2.1(rollup@2.79.1):
+ /@rollup/plugin-node-resolve@11.2.1(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==}
engines: {node: '>= 10.0.0'}
peerDependencies:
- rollup: ^1.20.0||^2.0.0
+ rollup: npm:@rollup/wasm-node
dependencies:
- '@rollup/pluginutils': 3.1.0(rollup@2.79.1)
+ '@rollup/pluginutils': 3.1.0(@rollup/wasm-node@4.9.4)
'@types/resolve': 1.17.1
builtin-modules: 3.3.0
deepmerge: 4.3.1
is-module: 1.0.0
resolve: 1.22.4
- rollup: 2.79.1
+ rollup: /@rollup/wasm-node@4.9.4
dev: true
- /@rollup/plugin-replace@2.4.2(rollup@2.79.1):
+ /@rollup/plugin-replace@2.4.2(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==}
peerDependencies:
- rollup: ^1.20.0 || ^2.0.0
+ rollup: npm:@rollup/wasm-node
dependencies:
- '@rollup/pluginutils': 3.1.0(rollup@2.79.1)
+ '@rollup/pluginutils': 3.1.0(@rollup/wasm-node@4.9.4)
magic-string: 0.25.9
- rollup: 2.79.1
+ rollup: /@rollup/wasm-node@4.9.4
dev: true
- /@rollup/pluginutils@3.1.0(rollup@2.79.1):
+ /@rollup/pluginutils@3.1.0(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
peerDependencies:
- rollup: ^1.20.0||^2.0.0
+ rollup: npm:@rollup/wasm-node
dependencies:
'@types/estree': 0.0.39
estree-walker: 1.0.1
picomatch: 2.3.1
- rollup: 2.79.1
+ rollup: /@rollup/wasm-node@4.9.4
dev: true
- /@rollup/rollup-android-arm-eabi@4.9.1:
- resolution: {integrity: sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-android-arm64@4.9.1:
- resolution: {integrity: sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-arm64@4.9.1:
- resolution: {integrity: sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-x64@4.9.1:
- resolution: {integrity: sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm-gnueabihf@4.9.1:
- resolution: {integrity: sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-gnu@4.9.1:
- resolution: {integrity: sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-musl@4.9.1:
- resolution: {integrity: sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-riscv64-gnu@4.9.1:
- resolution: {integrity: sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-gnu@4.9.1:
- resolution: {integrity: sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-musl@4.9.1:
- resolution: {integrity: sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-arm64-msvc@4.9.1:
- resolution: {integrity: sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-ia32-msvc@4.9.1:
- resolution: {integrity: sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-x64-msvc@4.9.1:
- resolution: {integrity: sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
+ /@rollup/wasm-node@4.9.4:
+ resolution: {integrity: sha512-K9ZPYMCxP7sBElj5du0En/zpbhXTQxpWI7RlF+8bNpLUozhzg2Pcx2h3cBCzV7xtiUt0dc+pF2Ib3/Sg8R0JMA==}
+ engines: {node: '>=18.0.0', npm: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ '@types/estree': 1.0.5
+ optionalDependencies:
+ fsevents: 2.3.3
/@scure/base@1.1.5:
resolution: {integrity: sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==}
@@ -2274,6 +2183,9 @@ packages:
resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==}
dev: true
+ /@types/estree@1.0.5:
+ resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+
/@types/filesystem@0.0.32:
resolution: {integrity: sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ==}
dependencies:
@@ -5142,7 +5054,7 @@ packages:
'@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.6)
'@babel/types': 7.23.6
kleur: 4.1.5
- rollup: 3.29.4
+ rollup: /@rollup/wasm-node@4.9.4
unplugin: 1.5.1
transitivePeerDependencies:
- supports-color
@@ -6064,73 +5976,36 @@ packages:
glob: 7.2.3
dev: true
- /rollup-plugin-terser@7.0.2(rollup@2.79.1):
+ /rollup-plugin-terser@7.0.2(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==}
deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser
peerDependencies:
- rollup: ^2.0.0
+ rollup: npm:@rollup/wasm-node
dependencies:
'@babel/code-frame': 7.23.5
jest-worker: 26.6.2
- rollup: 2.79.1
+ rollup: /@rollup/wasm-node@4.9.4
serialize-javascript: 4.0.0
terser: 5.19.3
dev: true
- /rollup-plugin-visualizer@5.11.0(rollup@2.79.1):
+ /rollup-plugin-visualizer@5.11.0(@rollup/wasm-node@4.9.4):
resolution: {integrity: sha512-exM0Ms2SN3AgTzMeW7y46neZQcyLY7eKwWAop1ZoRTCZwyrIRdMMJ6JjToAJbML77X/9N8ZEpmXG4Z/Clb9k8g==}
engines: {node: '>=14'}
hasBin: true
peerDependencies:
- rollup: 2.x || 3.x || 4.x
+ rollup: npm:@rollup/wasm-node
peerDependenciesMeta:
rollup:
optional: true
dependencies:
open: 8.4.2
picomatch: 2.3.1
- rollup: 2.79.1
+ rollup: /@rollup/wasm-node@4.9.4
source-map: 0.7.4
yargs: 17.7.2
dev: true
- /rollup@2.79.1:
- resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==}
- engines: {node: '>=10.0.0'}
- hasBin: true
- optionalDependencies:
- fsevents: 2.3.3
- dev: true
-
- /rollup@3.29.4:
- resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
- engines: {node: '>=14.18.0', npm: '>=8.0.0'}
- hasBin: true
- optionalDependencies:
- fsevents: 2.3.3
- dev: false
-
- /rollup@4.9.1:
- resolution: {integrity: sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==}
- engines: {node: '>=18.0.0', npm: '>=8.0.0'}
- hasBin: true
- optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.9.1
- '@rollup/rollup-android-arm64': 4.9.1
- '@rollup/rollup-darwin-arm64': 4.9.1
- '@rollup/rollup-darwin-x64': 4.9.1
- '@rollup/rollup-linux-arm-gnueabihf': 4.9.1
- '@rollup/rollup-linux-arm64-gnu': 4.9.1
- '@rollup/rollup-linux-arm64-musl': 4.9.1
- '@rollup/rollup-linux-riscv64-gnu': 4.9.1
- '@rollup/rollup-linux-x64-gnu': 4.9.1
- '@rollup/rollup-linux-x64-musl': 4.9.1
- '@rollup/rollup-win32-arm64-msvc': 4.9.1
- '@rollup/rollup-win32-ia32-msvc': 4.9.1
- '@rollup/rollup-win32-x64-msvc': 4.9.1
- fsevents: 2.3.3
- dev: true
-
/rrweb-cssom@0.6.0:
resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==}
dev: true
@@ -7109,7 +6984,7 @@ packages:
'@types/node': 20.10.5
esbuild: 0.19.10
postcss: 8.4.32
- rollup: 4.9.1
+ rollup: /@rollup/wasm-node@4.9.4
optionalDependencies:
fsevents: 2.3.3
dev: true
@@ -7371,9 +7246,9 @@ packages:
'@babel/core': 7.23.6
'@babel/preset-env': 7.23.6(@babel/core@7.23.6)
'@babel/runtime': 7.23.6
- '@rollup/plugin-babel': 5.3.1(@babel/core@7.23.6)(rollup@2.79.1)
- '@rollup/plugin-node-resolve': 11.2.1(rollup@2.79.1)
- '@rollup/plugin-replace': 2.4.2(rollup@2.79.1)
+ '@rollup/plugin-babel': 5.3.1(@babel/core@7.23.6)(@rollup/wasm-node@4.9.4)
+ '@rollup/plugin-node-resolve': 11.2.1(@rollup/wasm-node@4.9.4)
+ '@rollup/plugin-replace': 2.4.2(@rollup/wasm-node@4.9.4)
'@surma/rollup-plugin-off-main-thread': 2.2.3
ajv: 8.12.0
common-tags: 1.8.2
@@ -7382,8 +7257,8 @@ packages:
glob: 7.2.3
lodash: 4.17.21
pretty-bytes: 5.6.0
- rollup: 2.79.1
- rollup-plugin-terser: 7.0.2(rollup@2.79.1)
+ rollup: /@rollup/wasm-node@4.9.4
+ rollup-plugin-terser: 7.0.2(@rollup/wasm-node@4.9.4)
source-map: 0.8.0-beta.0
stringify-object: 3.3.0
strip-comments: 2.0.1
From 75a2c31800631958e23c14c434b2fba626a71573 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 16:56:49 +0000
Subject: [PATCH 009/151] Add Docker build to test workflow
---
.github/workflows/linting_testing.yml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/.github/workflows/linting_testing.yml b/.github/workflows/linting_testing.yml
index 497131bc..6f41126f 100644
--- a/.github/workflows/linting_testing.yml
+++ b/.github/workflows/linting_testing.yml
@@ -55,3 +55,21 @@ jobs:
- name: Build Project
run: pnpm run build
+
+ docker:
+ name: Build Docker
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Setup Docker buildx
+ uses: docker/setup-buildx-action@v3
+
+ - name: Build Docker image
+ uses: docker/build-push-action@v5
+ with:
+ push: false
+ platforms: linux/amd64,linux/arm64,linux/arm
+ context: .
From 93d8f7263ee2d613ea5fd511568d57b59a577106 Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Sun, 7 Jan 2024 17:05:59 +0000
Subject: [PATCH 010/151] Remove ARM 32-bit from testing
---
.github/workflows/linting_testing.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/linting_testing.yml b/.github/workflows/linting_testing.yml
index 6f41126f..c782bcb1 100644
--- a/.github/workflows/linting_testing.yml
+++ b/.github/workflows/linting_testing.yml
@@ -71,5 +71,5 @@ jobs:
uses: docker/build-push-action@v5
with:
push: false
- platforms: linux/amd64,linux/arm64,linux/arm
+ platforms: linux/amd64,linux/arm64
context: .
From ef85c217f7a6288321eb8c785c8bb33f23b582df Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Mon, 8 Jan 2024 17:06:27 +0100
Subject: [PATCH 011/151] first mvp extension
---
package.json | 1 +
pnpm-lock.yaml | 21 +++
src/@types/plasmo.d.ts | 37 ++++++
src/components/player/display/base.ts | 120 ++++++++++--------
.../player/utils/convertRunoutputToSource.ts | 2 +
src/stores/player/utils/qualities.ts | 5 +-
src/utils/providers.ts | 4 +-
7 files changed, 134 insertions(+), 56 deletions(-)
create mode 100644 src/@types/plasmo.d.ts
diff --git a/package.json b/package.json
index 388054df..3148f860 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"@ladjs/country-language": "^1.0.3",
"@movie-web/providers": "^2.0.5",
"@noble/hashes": "^1.3.3",
+ "@plasmohq/messaging": "^0.6.1",
"@react-spring/web": "^9.7.3",
"@scure/bip39": "^1.2.2",
"@sozialhelden/ietf-language-tags": "^5.4.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6d6bb9bd..5c1d1c9e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -27,6 +27,9 @@ dependencies:
'@noble/hashes':
specifier: ^1.3.3
version: 1.3.3
+ '@plasmohq/messaging':
+ specifier: ^0.6.1
+ version: 0.6.1(react@18.2.0)
'@react-spring/web':
specifier: ^9.7.3
version: 9.7.3(react-dom@18.2.0)(react@18.2.0)
@@ -1980,6 +1983,18 @@ packages:
tslib: 2.6.2
dev: true
+ /@plasmohq/messaging@0.6.1(react@18.2.0):
+ resolution: {integrity: sha512-/nn1k8SG5z++o/NnZu+byHWcC9MhPLxfmvj+AP3buqMn7uwfYDcYWURLuMW2Knw08HBg+wku2v1Ltt4evN0nzA==}
+ peerDependencies:
+ react: ^16.8.6 || ^17 || ^18
+ peerDependenciesMeta:
+ react:
+ optional: true
+ dependencies:
+ nanoid: 5.0.3
+ react: 18.2.0
+ dev: false
+
/@react-spring/animated@9.7.3(react@18.2.0):
resolution: {integrity: sha512-5CWeNJt9pNgyvuSzQH+uy2pvTg8Y4/OisoscZIR8/ZNLIOI+CatFBhGZpDGTF/OzdNFsAoGk3wiUYTwoJ0YIvw==}
peerDependencies:
@@ -5156,6 +5171,12 @@ packages:
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
+ /nanoid@5.0.3:
+ resolution: {integrity: sha512-I7X2b22cxA4LIHXPSqbBCEQSL+1wv8TuoefejsX4HFWyC6jc5JG7CEaxOltiKjc1M+YCS2YkrZZcj4+dytw9GA==}
+ engines: {node: ^18 || >=20}
+ hasBin: true
+ dev: false
+
/nanoid@5.0.4:
resolution: {integrity: sha512-vAjmBf13gsmhXSgBrtIclinISzFFy22WwCYoyilZlsrRXNIHSwgFQ1bEdjRwMT3aoadeIF6HMuDRlOxzfXV8ig==}
engines: {node: ^18 || >=20}
diff --git a/src/@types/plasmo.d.ts b/src/@types/plasmo.d.ts
new file mode 100644
index 00000000..4570cae4
--- /dev/null
+++ b/src/@types/plasmo.d.ts
@@ -0,0 +1,37 @@
+/* eslint-disable @typescript-eslint/ban-types */
+import "@plasmohq/messaging";
+
+export interface PlasmoRequestBody {
+ ruleId: number;
+ domain: string;
+ requestHeaders?: Record;
+ responseHeaders?: Record;
+}
+
+export type PlasmoResponseBody =
+ | {
+ success: true;
+ ruleId: number;
+ }
+ | {
+ success: false;
+ error: string;
+ };
+
+interface MmMetadata {
+ "declarative-net-request": {
+ req: PlasmoRequestBody;
+ res: PlasmoResponseBody;
+ };
+ "proxy-request": {
+ req: PlasmoRequestBody;
+ res: PlasmoResponseBody;
+ };
+}
+
+interface MpMetadata {}
+
+declare module "@plasmohq/messaging" {
+ interface MessagesMetadata extends MmMetadata {}
+ interface PortsMetadata extends MpMetadata {}
+}
diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts
index 7a9ce041..11a0799c 100644
--- a/src/components/player/display/base.ts
+++ b/src/components/player/display/base.ts
@@ -1,6 +1,8 @@
+import { sendToBackgroundViaRelay } from "@plasmohq/messaging";
import fscreen from "fscreen";
import Hls, { Level } from "hls.js";
+import { PlasmoRequestBody, PlasmoResponseBody } from "@/@types/plasmo";
import {
DisplayInterface,
DisplayInterfaceEvents,
@@ -100,65 +102,75 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
}
function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
- if (src.type === "hls") {
- if (canPlayHlsNatively(vid)) {
- vid.src = processCdnLink(src.url);
+ // TODO: Add check whether the extension is installed
+ sendToBackgroundViaRelay({
+ name: "declarative-net-request",
+ body: {
+ ruleId: 1,
+ domain: src.type === "hls" ? new URL(src.url).hostname : src.url,
+ requestHeaders: src.preferredHeaders,
+ },
+ }).then(() => {
+ if (src.type === "hls") {
+ if (canPlayHlsNatively(vid)) {
+ vid.src = processCdnLink(src.url);
+ vid.currentTime = startAt;
+ return;
+ }
+
+ if (!Hls.isSupported()) throw new Error("HLS not supported");
+ if (!hls) {
+ hls = new Hls({
+ maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
+ fragLoadPolicy: {
+ default: {
+ maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
+ maxTimeToFirstByteMs: 30 * 1000,
+ errorRetry: {
+ maxNumRetry: 2,
+ retryDelayMs: 1000,
+ maxRetryDelayMs: 8000,
+ },
+ timeoutRetry: {
+ maxNumRetry: 3,
+ maxRetryDelayMs: 0,
+ retryDelayMs: 0,
+ },
+ },
+ },
+ });
+ hls.on(Hls.Events.ERROR, (event, data) => {
+ console.error("HLS error", data);
+ if (data.fatal) {
+ emit("error", {
+ message: data.error.message,
+ stackTrace: data.error.stack,
+ errorName: data.error.name,
+ type: "hls",
+ });
+ }
+ });
+ hls.on(Hls.Events.MANIFEST_LOADED, () => {
+ if (!hls) return;
+ reportLevels();
+ setupQualityForHls();
+ });
+ hls.on(Hls.Events.LEVEL_SWITCHED, () => {
+ if (!hls) return;
+ const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
+ emit("changedquality", quality);
+ });
+ }
+
+ hls.attachMedia(vid);
+ hls.loadSource(processCdnLink(src.url));
vid.currentTime = startAt;
return;
}
- if (!Hls.isSupported()) throw new Error("HLS not supported");
- if (!hls) {
- hls = new Hls({
- maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
- fragLoadPolicy: {
- default: {
- maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
- maxTimeToFirstByteMs: 30 * 1000,
- errorRetry: {
- maxNumRetry: 2,
- retryDelayMs: 1000,
- maxRetryDelayMs: 8000,
- },
- timeoutRetry: {
- maxNumRetry: 3,
- maxRetryDelayMs: 0,
- retryDelayMs: 0,
- },
- },
- },
- });
- hls.on(Hls.Events.ERROR, (event, data) => {
- console.error("HLS error", data);
- if (data.fatal) {
- emit("error", {
- message: data.error.message,
- stackTrace: data.error.stack,
- errorName: data.error.name,
- type: "hls",
- });
- }
- });
- hls.on(Hls.Events.MANIFEST_LOADED, () => {
- if (!hls) return;
- reportLevels();
- setupQualityForHls();
- });
- hls.on(Hls.Events.LEVEL_SWITCHED, () => {
- if (!hls) return;
- const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
- emit("changedquality", quality);
- });
- }
-
- hls.attachMedia(vid);
- hls.loadSource(processCdnLink(src.url));
+ vid.src = processCdnLink(src.url);
vid.currentTime = startAt;
- return;
- }
-
- vid.src = processCdnLink(src.url);
- vid.currentTime = startAt;
+ });
}
function setSource() {
diff --git a/src/components/player/utils/convertRunoutputToSource.ts b/src/components/player/utils/convertRunoutputToSource.ts
index fba59e63..f54c5396 100644
--- a/src/components/player/utils/convertRunoutputToSource.ts
+++ b/src/components/player/utils/convertRunoutputToSource.ts
@@ -28,6 +28,7 @@ export function convertRunoutputToSource(out: {
return {
type: "hls",
url: out.stream.playlist,
+ preferredHeaders: out.stream.preferredHeaders,
};
}
if (out.stream.type === "file") {
@@ -49,6 +50,7 @@ export function convertRunoutputToSource(out: {
return {
type: "file",
qualities,
+ preferredHeaders: out.stream.preferredHeaders,
};
}
throw new Error("unrecognized type");
diff --git a/src/stores/player/utils/qualities.ts b/src/stores/player/utils/qualities.ts
index dbd84b5c..e5140d53 100644
--- a/src/stores/player/utils/qualities.ts
+++ b/src/stores/player/utils/qualities.ts
@@ -1,4 +1,4 @@
-import { Qualities } from "@movie-web/providers";
+import { Qualities, Stream } from "@movie-web/providers";
import { QualityStore } from "@/stores/quality";
@@ -14,16 +14,19 @@ export type SourceFileStream = {
export type LoadableSource = {
type: StreamType;
url: string;
+ preferredHeaders?: Stream["preferredHeaders"];
};
export type SourceSliceSource =
| {
type: "file";
qualities: Partial>;
+ preferredHeaders?: Stream["preferredHeaders"];
}
| {
type: "hls";
url: string;
+ preferredHeaders?: Stream["preferredHeaders"];
};
const qualitySorting: Record = {
diff --git a/src/utils/providers.ts b/src/utils/providers.ts
index e5c8503c..73c95662 100644
--- a/src/utils/providers.ts
+++ b/src/utils/providers.ts
@@ -62,5 +62,7 @@ function makeLoadBalancedSimpleProxyFetcher() {
export const providers = makeProviders({
fetcher: makeStandardFetcher(fetch),
proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
- target: targets.BROWSER,
+ // TODO: Add check whether the extension is installed
+ // target: targets.BROWSER,
+ target: targets.BROWSER_EXTENSION,
}) as any as ProviderControls;
From 803668b49289effa63b11ef95e023156e7340f2b Mon Sep 17 00:00:00 2001
From: Ashutosh Shinde
Date: Tue, 9 Jan 2024 10:43:20 +0530
Subject: [PATCH 012/151] added return value of selectCaptionById from
selectLanguage function
---
src/components/player/hooks/useCaptions.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/player/hooks/useCaptions.ts b/src/components/player/hooks/useCaptions.ts
index 424edcad..458c704a 100644
--- a/src/components/player/hooks/useCaptions.ts
+++ b/src/components/player/hooks/useCaptions.ts
@@ -35,7 +35,7 @@ export function useCaptions() {
async (language: string) => {
const caption = captionList.find((v) => v.language === language);
if (!caption) return;
- selectCaptionById(caption.id);
+ return selectCaptionById(caption.id);
},
[captionList, selectCaptionById],
);
From f70d13f2c9e3b91b5b3caccbdf29e9ae77827944 Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Tue, 9 Jan 2024 20:07:22 +0100
Subject: [PATCH 013/151] Clean up extension code
---
src/backend/extension/messaging.ts | 51 ++++++++
.../extension/plasmo.ts} | 17 ++-
src/backend/helpers/fetch.ts | 2 +-
.../providers/fetchers.ts} | 25 ++--
src/backend/providers/providers.ts | 26 ++++
src/components/player/display/base.ts | 120 ++++++++----------
.../player/hooks/useSourceSelection.ts | 9 +-
src/hooks/useProviderScrape.tsx | 5 +-
src/pages/parts/player/MetaPart.tsx | 15 ++-
9 files changed, 172 insertions(+), 98 deletions(-)
create mode 100644 src/backend/extension/messaging.ts
rename src/{@types/plasmo.d.ts => backend/extension/plasmo.ts} (72%)
rename src/{utils/providers.ts => backend/providers/fetchers.ts} (74%)
create mode 100644 src/backend/providers/providers.ts
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
new file mode 100644
index 00000000..ec0b4bf6
--- /dev/null
+++ b/src/backend/extension/messaging.ts
@@ -0,0 +1,51 @@
+import {
+ MessagesMetadata,
+ sendToBackgroundViaRelay,
+} from "@plasmohq/messaging";
+
+let activeExtension = false;
+
+export interface ExtensionHello {
+ version: string;
+}
+
+function sendMessage(
+ message: keyof MessagesMetadata,
+ payload: any,
+ timeout: number = -1,
+) {
+ return new Promise((resolve) => {
+ if (timeout >= 0) setTimeout(() => resolve(null), timeout);
+ sendToBackgroundViaRelay({
+ name: message,
+ body: payload,
+ })
+ .then((res) => {
+ activeExtension = true;
+ resolve(res);
+ })
+ .catch(() => {
+ activeExtension = false;
+ resolve(null);
+ });
+ });
+}
+
+export async function sendExtensionRequest(
+ url: string,
+ ops: any,
+): Promise {
+ return sendMessage("proxy-request", { url, ...ops });
+}
+
+export async function extensionInfo(): Promise {
+ return sendMessage("hello", null, 300);
+}
+
+export function isExtensionActiveCached(): boolean {
+ return activeExtension;
+}
+
+export async function isExtensionActive(): Promise {
+ return !!(await extensionInfo());
+}
diff --git a/src/@types/plasmo.d.ts b/src/backend/extension/plasmo.ts
similarity index 72%
rename from src/@types/plasmo.d.ts
rename to src/backend/extension/plasmo.ts
index 4570cae4..2e9cacbf 100644
--- a/src/@types/plasmo.d.ts
+++ b/src/backend/extension/plasmo.ts
@@ -1,6 +1,3 @@
-/* eslint-disable @typescript-eslint/ban-types */
-import "@plasmohq/messaging";
-
export interface PlasmoRequestBody {
ruleId: number;
domain: string;
@@ -8,7 +5,11 @@ export interface PlasmoRequestBody {
responseHeaders?: Record;
}
-export type PlasmoResponseBody =
+export interface ExtensionHelloReply {
+ version: string;
+}
+
+export type ExtensionRequestReply =
| {
success: true;
ruleId: number;
@@ -21,11 +22,15 @@ export type PlasmoResponseBody =
interface MmMetadata {
"declarative-net-request": {
req: PlasmoRequestBody;
- res: PlasmoResponseBody;
+ res: ExtensionRequestReply;
};
"proxy-request": {
req: PlasmoRequestBody;
- res: PlasmoResponseBody;
+ res: ExtensionRequestReply;
+ };
+ hello: {
+ req: null;
+ res: ExtensionHelloReply;
};
}
diff --git a/src/backend/helpers/fetch.ts b/src/backend/helpers/fetch.ts
index cc3e735e..f9aa145a 100644
--- a/src/backend/helpers/fetch.ts
+++ b/src/backend/helpers/fetch.ts
@@ -1,7 +1,7 @@
import { ofetch } from "ofetch";
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
-import { getLoadbalancedProxyUrl } from "@/utils/providers";
+import { getLoadbalancedProxyUrl } from "@/backend/providers/fetchers";
type P = Parameters>;
type R = ReturnType>;
diff --git a/src/utils/providers.ts b/src/backend/providers/fetchers.ts
similarity index 74%
rename from src/utils/providers.ts
rename to src/backend/providers/fetchers.ts
index 73c95662..596e8376 100644
--- a/src/utils/providers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -1,12 +1,6 @@
-import {
- Fetcher,
- ProviderControls,
- makeProviders,
- makeSimpleProxyFetcher,
- makeStandardFetcher,
- targets,
-} from "@movie-web/providers";
+import { Fetcher, makeSimpleProxyFetcher } from "@movie-web/providers";
+import { sendExtensionRequest } from "@/backend/extension/messaging";
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
import { getProviderApiUrls, getProxyUrls } from "@/utils/proxyUrls";
@@ -48,7 +42,7 @@ async function fetchButWithApiTokens(
return response;
}
-function makeLoadBalancedSimpleProxyFetcher() {
+export function makeLoadBalancedSimpleProxyFetcher() {
const fetcher: Fetcher = async (a, b) => {
const currentFetcher = makeSimpleProxyFetcher(
getLoadbalancedProxyUrl(),
@@ -59,10 +53,9 @@ function makeLoadBalancedSimpleProxyFetcher() {
return fetcher;
}
-export const providers = makeProviders({
- fetcher: makeStandardFetcher(fetch),
- proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
- // TODO: Add check whether the extension is installed
- // target: targets.BROWSER,
- target: targets.BROWSER_EXTENSION,
-}) as any as ProviderControls;
+export function makeExtensionFetcher() {
+ const fetcher: Fetcher = async (a, b) => {
+ return sendExtensionRequest(a, b) as any;
+ };
+ return fetcher;
+}
diff --git a/src/backend/providers/providers.ts b/src/backend/providers/providers.ts
new file mode 100644
index 00000000..1a7b484a
--- /dev/null
+++ b/src/backend/providers/providers.ts
@@ -0,0 +1,26 @@
+import {
+ makeProviders,
+ makeStandardFetcher,
+ targets,
+} from "@movie-web/providers";
+
+import { isExtensionActiveCached } from "@/backend/extension/messaging";
+import {
+ makeExtensionFetcher,
+ makeLoadBalancedSimpleProxyFetcher,
+} from "@/backend/providers/fetchers";
+
+export function getProviders() {
+ if (isExtensionActiveCached()) {
+ return makeProviders({
+ fetcher: makeExtensionFetcher(),
+ target: targets.BROWSER_EXTENSION,
+ });
+ }
+
+ return makeProviders({
+ fetcher: makeStandardFetcher(fetch),
+ proxiedFetcher: makeLoadBalancedSimpleProxyFetcher(),
+ target: targets.BROWSER,
+ });
+}
diff --git a/src/components/player/display/base.ts b/src/components/player/display/base.ts
index 11a0799c..91f36722 100644
--- a/src/components/player/display/base.ts
+++ b/src/components/player/display/base.ts
@@ -1,8 +1,6 @@
-import { sendToBackgroundViaRelay } from "@plasmohq/messaging";
import fscreen from "fscreen";
import Hls, { Level } from "hls.js";
-import { PlasmoRequestBody, PlasmoResponseBody } from "@/@types/plasmo";
import {
DisplayInterface,
DisplayInterfaceEvents,
@@ -43,6 +41,7 @@ function qualityToHlsLevel(quality: SourceQuality): number | null {
);
return found ? +found[0] : null;
}
+
function hlsLevelsToQualities(levels: Level[]): SourceQuality[] {
return levels
.map((v) => hlsLevelToQuality(v))
@@ -103,74 +102,65 @@ export function makeVideoElementDisplayInterface(): DisplayInterface {
function setupSource(vid: HTMLVideoElement, src: LoadableSource) {
// TODO: Add check whether the extension is installed
- sendToBackgroundViaRelay({
- name: "declarative-net-request",
- body: {
- ruleId: 1,
- domain: src.type === "hls" ? new URL(src.url).hostname : src.url,
- requestHeaders: src.preferredHeaders,
- },
- }).then(() => {
- if (src.type === "hls") {
- if (canPlayHlsNatively(vid)) {
- vid.src = processCdnLink(src.url);
- vid.currentTime = startAt;
- return;
- }
-
- if (!Hls.isSupported()) throw new Error("HLS not supported");
- if (!hls) {
- hls = new Hls({
- maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
- fragLoadPolicy: {
- default: {
- maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
- maxTimeToFirstByteMs: 30 * 1000,
- errorRetry: {
- maxNumRetry: 2,
- retryDelayMs: 1000,
- maxRetryDelayMs: 8000,
- },
- timeoutRetry: {
- maxNumRetry: 3,
- maxRetryDelayMs: 0,
- retryDelayMs: 0,
- },
- },
- },
- });
- hls.on(Hls.Events.ERROR, (event, data) => {
- console.error("HLS error", data);
- if (data.fatal) {
- emit("error", {
- message: data.error.message,
- stackTrace: data.error.stack,
- errorName: data.error.name,
- type: "hls",
- });
- }
- });
- hls.on(Hls.Events.MANIFEST_LOADED, () => {
- if (!hls) return;
- reportLevels();
- setupQualityForHls();
- });
- hls.on(Hls.Events.LEVEL_SWITCHED, () => {
- if (!hls) return;
- const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
- emit("changedquality", quality);
- });
- }
-
- hls.attachMedia(vid);
- hls.loadSource(processCdnLink(src.url));
+ if (src.type === "hls") {
+ if (canPlayHlsNatively(vid)) {
+ vid.src = processCdnLink(src.url);
vid.currentTime = startAt;
return;
}
- vid.src = processCdnLink(src.url);
+ if (!Hls.isSupported()) throw new Error("HLS not supported");
+ if (!hls) {
+ hls = new Hls({
+ maxBufferSize: 500 * 1000 * 1000, // 500 mb of buffering, should load more fragments at once
+ fragLoadPolicy: {
+ default: {
+ maxLoadTimeMs: 30 * 1000, // allow it load extra long, fragments are slow if requested for the first time on an origin
+ maxTimeToFirstByteMs: 30 * 1000,
+ errorRetry: {
+ maxNumRetry: 2,
+ retryDelayMs: 1000,
+ maxRetryDelayMs: 8000,
+ },
+ timeoutRetry: {
+ maxNumRetry: 3,
+ maxRetryDelayMs: 0,
+ retryDelayMs: 0,
+ },
+ },
+ },
+ });
+ hls.on(Hls.Events.ERROR, (event, data) => {
+ console.error("HLS error", data);
+ if (data.fatal) {
+ emit("error", {
+ message: data.error.message,
+ stackTrace: data.error.stack,
+ errorName: data.error.name,
+ type: "hls",
+ });
+ }
+ });
+ hls.on(Hls.Events.MANIFEST_LOADED, () => {
+ if (!hls) return;
+ reportLevels();
+ setupQualityForHls();
+ });
+ hls.on(Hls.Events.LEVEL_SWITCHED, () => {
+ if (!hls) return;
+ const quality = hlsLevelToQuality(hls.levels[hls.currentLevel]);
+ emit("changedquality", quality);
+ });
+ }
+
+ hls.attachMedia(vid);
+ hls.loadSource(processCdnLink(src.url));
vid.currentTime = startAt;
- });
+ return;
+ }
+
+ vid.src = processCdnLink(src.url);
+ vid.currentTime = startAt;
}
function setSource() {
diff --git a/src/components/player/hooks/useSourceSelection.ts b/src/components/player/hooks/useSourceSelection.ts
index e28507cf..bca884f7 100644
--- a/src/components/player/hooks/useSourceSelection.ts
+++ b/src/components/player/hooks/useSourceSelection.ts
@@ -13,12 +13,13 @@ import {
scrapeSourceOutputToProviderMetric,
useReportProviders,
} from "@/backend/helpers/report";
+import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
+import { getProviders } from "@/backend/providers/providers";
import { convertProviderCaption } from "@/components/player/utils/captions";
import { convertRunoutputToSource } from "@/components/player/utils/convertRunoutputToSource";
import { useOverlayRouter } from "@/hooks/useOverlayRouter";
import { metaToScrapeMedia } from "@/stores/player/slices/source";
import { usePlayerStore } from "@/stores/player/store";
-import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
export function useEmbedScraping(
routerId: string,
@@ -47,7 +48,7 @@ export function useEmbedScraping(
);
result = await conn.promise();
} else {
- result = await providers.runEmbedScraper({
+ result = await getProviders().runEmbedScraper({
id: embedId,
url,
});
@@ -111,7 +112,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
);
result = await conn.promise();
} else {
- result = await providers.runSourceScraper({
+ result = await getProviders().runSourceScraper({
id: sourceId,
media: scrapeMedia,
});
@@ -155,7 +156,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
);
embedResult = await conn.promise();
} else {
- embedResult = await providers.runEmbedScraper({
+ embedResult = await getProviders().runEmbedScraper({
id: result.embeds[0].embedId,
url: result.embeds[0].url,
});
diff --git a/src/hooks/useProviderScrape.tsx b/src/hooks/useProviderScrape.tsx
index 43328184..21cb985e 100644
--- a/src/hooks/useProviderScrape.tsx
+++ b/src/hooks/useProviderScrape.tsx
@@ -10,7 +10,8 @@ import {
getCachedMetadata,
makeProviderUrl,
} from "@/backend/helpers/providerApi";
-import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
+import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
+import { getProviders } from "@/backend/providers/providers";
export interface ScrapingItems {
id: string;
@@ -172,8 +173,8 @@ export function useScrape() {
return getResult(sseOutput === "" ? null : sseOutput);
}
- if (!providers) return null;
startScrape();
+ const providers = getProviders();
const output = await providers.runAll({
media,
events: {
diff --git a/src/pages/parts/player/MetaPart.tsx b/src/pages/parts/player/MetaPart.tsx
index 4930fffb..6d5b64ef 100644
--- a/src/pages/parts/player/MetaPart.tsx
+++ b/src/pages/parts/player/MetaPart.tsx
@@ -3,6 +3,7 @@ import { useNavigate, useParams } from "react-router-dom";
import { useAsync } from "react-use";
import type { AsyncReturnType } from "type-fest";
+import { isExtensionActive } from "@/backend/extension/messaging";
import {
fetchMetadata,
setCachedMetadata,
@@ -10,6 +11,8 @@ import {
import { DetailedMeta, getMetaFromId } from "@/backend/metadata/getmeta";
import { decodeTMDBId } from "@/backend/metadata/tmdb";
import { MWMediaType } from "@/backend/metadata/types/mw";
+import { getLoadbalancedProviderApiUrl } from "@/backend/providers/fetchers";
+import { getProviders } from "@/backend/providers/providers";
import { Button } from "@/components/buttons/Button";
import { Icons } from "@/components/Icon";
import { IconPill } from "@/components/layout/IconPill";
@@ -18,7 +21,6 @@ import { Paragraph } from "@/components/text/Paragraph";
import { Title } from "@/components/text/Title";
import { ErrorContainer, ErrorLayout } from "@/pages/layouts/ErrorLayout";
import { conf } from "@/setup/config";
-import { getLoadbalancedProviderApiUrl, providers } from "@/utils/providers";
export interface MetaPartProps {
onGetMeta?: (meta: DetailedMeta, episodeId?: string) => void;
@@ -41,8 +43,12 @@ export function MetaPart(props: MetaPartProps) {
const navigate = useNavigate();
const { error, value, loading } = useAsync(async () => {
+ // check extension
+ const isActive = await isExtensionActive();
+
+ // use api metadata or providers metadata
const providerApiUrl = getLoadbalancedProviderApiUrl();
- if (providerApiUrl) {
+ if (providerApiUrl && !isActive) {
try {
await fetchMetadata(providerApiUrl);
} catch (err) {
@@ -50,11 +56,12 @@ export function MetaPart(props: MetaPartProps) {
}
} else {
setCachedMetadata([
- ...providers.listSources(),
- ...providers.listEmbeds(),
+ ...getProviders().listSources(),
+ ...getProviders().listEmbeds(),
]);
}
+ // get media meta data
let data: ReturnType = null;
try {
if (!params.media) throw new Error("no media params");
From dc67ef0c3a8867c1555e9d847862ae1703cfdd96 Mon Sep 17 00:00:00 2001
From: Astrid
Date: Tue, 9 Jan 2024 20:50:27 +0100
Subject: [PATCH 014/151] remove unused vars
---
src/pages/parts/auth/AccountCreatePart.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/pages/parts/auth/AccountCreatePart.tsx b/src/pages/parts/auth/AccountCreatePart.tsx
index 674a3be6..6f8b9ad4 100644
--- a/src/pages/parts/auth/AccountCreatePart.tsx
+++ b/src/pages/parts/auth/AccountCreatePart.tsx
@@ -5,7 +5,6 @@ import { Avatar } from "@/components/Avatar";
import { Button } from "@/components/buttons/Button";
import { ColorPicker, initialColor } from "@/components/form/ColorPicker";
import { IconPicker, initialIcon } from "@/components/form/IconPicker";
-import { Icon, Icons } from "@/components/Icon";
import {
LargeCard,
LargeCardButtons,
From dec967418bcf1b9ba5efb5ca32de623f1ec89852 Mon Sep 17 00:00:00 2001
From: Astrid
Date: Tue, 9 Jan 2024 20:50:45 +0100
Subject: [PATCH 015/151] Mark cursor-not-allowed as important so that
cursor-pointer gets overridden
---
src/components/buttons/Button.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/buttons/Button.tsx b/src/components/buttons/Button.tsx
index ed0eebf8..70e2c780 100644
--- a/src/components/buttons/Button.tsx
+++ b/src/components/buttons/Button.tsx
@@ -41,7 +41,7 @@ export function Button(props: Props) {
props.padding ?? "px-4 py-3",
props.className,
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)
From 421186cb54737655446c3c87469697b4f82d180c Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Tue, 9 Jan 2024 21:56:39 +0100
Subject: [PATCH 016/151] Version checking + preparing streams
---
src/backend/extension/compatibility.ts | 5 +++
src/backend/extension/messaging.ts | 17 +++++++-
src/backend/extension/plasmo.ts | 4 +-
src/backend/extension/streams.ts | 40 +++++++++++++++++++
.../player/hooks/useSourceSelection.ts | 3 ++
src/hooks/useProviderScrape.tsx | 3 ++
6 files changed, 68 insertions(+), 4 deletions(-)
create mode 100644 src/backend/extension/compatibility.ts
create mode 100644 src/backend/extension/streams.ts
diff --git a/src/backend/extension/compatibility.ts b/src/backend/extension/compatibility.ts
new file mode 100644
index 00000000..31471d26
--- /dev/null
+++ b/src/backend/extension/compatibility.ts
@@ -0,0 +1,5 @@
+const allowedExtensionVersion = ["0.0.1"];
+
+export function isAllowedExtensionVersion(version: string): boolean {
+ return allowedExtensionVersion.includes(version);
+}
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index ec0b4bf6..3c5480c1 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -3,6 +3,8 @@ import {
sendToBackgroundViaRelay,
} from "@plasmohq/messaging";
+import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
+
let activeExtension = false;
export interface ExtensionHello {
@@ -35,7 +37,14 @@ export async function sendExtensionRequest(
url: string,
ops: any,
): Promise {
- return sendMessage("proxy-request", { url, ...ops });
+ return sendMessage("make-request", { url, ...ops });
+}
+
+export async function setDomainRule(
+ domains: string[],
+ headers: Record,
+): Promise {
+ return sendMessage("prepare-stream", { domains, headers });
}
export async function extensionInfo(): Promise {
@@ -47,5 +56,9 @@ export function isExtensionActiveCached(): boolean {
}
export async function isExtensionActive(): Promise {
- return !!(await extensionInfo());
+ const info = await extensionInfo();
+ if (!info) return false;
+ const allowedVersion = isAllowedExtensionVersion(info.version);
+ if (!allowedVersion) return false;
+ return true;
}
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index 2e9cacbf..8c0093f0 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -20,11 +20,11 @@ export type ExtensionRequestReply =
};
interface MmMetadata {
- "declarative-net-request": {
+ "prepare-stream": {
req: PlasmoRequestBody;
res: ExtensionRequestReply;
};
- "proxy-request": {
+ "make-request": {
req: PlasmoRequestBody;
res: ExtensionRequestReply;
};
diff --git a/src/backend/extension/streams.ts b/src/backend/extension/streams.ts
new file mode 100644
index 00000000..8d202992
--- /dev/null
+++ b/src/backend/extension/streams.ts
@@ -0,0 +1,40 @@
+import { Stream } from "@movie-web/providers";
+
+import { setDomainRule } from "@/backend/extension/messaging";
+
+function extractDomain(url: string): string {
+ try {
+ const u = new URL(url);
+ return u.hostname;
+ } catch {
+ return url;
+ }
+}
+
+function extractDomainsFromStream(stream: Stream): string[] {
+ if (stream.type === "hls") {
+ return [extractDomain(stream.playlist)];
+ }
+ if (stream.type === "file") {
+ return Object.values(stream.qualities).map((v) => extractDomain(v.url));
+ }
+ return [];
+}
+
+function buildHeadersFromStream(stream: Stream): Record {
+ const headers: Record = {};
+ Object.entries(stream.headers ?? {}).forEach((entry) => {
+ headers[entry[0]] = entry[1];
+ });
+ Object.entries(stream.preferredHeaders ?? {}).forEach((entry) => {
+ headers[entry[0]] = entry[1];
+ });
+ return headers;
+}
+
+export async function prepareStream(stream: Stream) {
+ await setDomainRule(
+ extractDomainsFromStream(stream),
+ buildHeadersFromStream(stream),
+ );
+}
diff --git a/src/components/player/hooks/useSourceSelection.ts b/src/components/player/hooks/useSourceSelection.ts
index bca884f7..b9e167d6 100644
--- a/src/components/player/hooks/useSourceSelection.ts
+++ b/src/components/player/hooks/useSourceSelection.ts
@@ -5,6 +5,7 @@ import {
} from "@movie-web/providers";
import { useAsyncFn } from "react-use";
+import { prepareStream } from "@/backend/extension/streams";
import {
connectServerSideEvents,
makeProviderUrl,
@@ -131,6 +132,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
]);
if (result.stream) {
+ await prepareStream(result.stream[0]);
setCaption(null);
setSource(
convertRunoutputToSource({ stream: result.stream[0] }),
@@ -187,6 +189,7 @@ export function useSourceScraping(sourceId: string | null, routerId: string) {
]);
setSourceId(sourceId);
setCaption(null);
+ await prepareStream(embedResult.stream[0]);
setSource(
convertRunoutputToSource({ stream: embedResult.stream[0] }),
convertProviderCaption(embedResult.stream[0].captions),
diff --git a/src/hooks/useProviderScrape.tsx b/src/hooks/useProviderScrape.tsx
index 21cb985e..d6b48063 100644
--- a/src/hooks/useProviderScrape.tsx
+++ b/src/hooks/useProviderScrape.tsx
@@ -5,6 +5,7 @@ import {
} from "@movie-web/providers";
import { RefObject, useCallback, useEffect, useRef, useState } from "react";
+import { prepareStream } from "@/backend/extension/streams";
import {
connectServerSideEvents,
getCachedMetadata,
@@ -169,6 +170,7 @@ export function useScrape() {
conn.on("update", updateEvent);
conn.on("discoverEmbeds", discoverEmbedsEvent);
const sseOutput = await conn.promise();
+ if (sseOutput) await prepareStream(sseOutput.stream);
return getResult(sseOutput === "" ? null : sseOutput);
}
@@ -184,6 +186,7 @@ export function useScrape() {
discoverEmbeds: discoverEmbedsEvent,
},
});
+ if (output) await prepareStream(output.stream);
return getResult(output);
},
[
From ffea08f3d93a936f4cf2de5a37649bc37512ae0c Mon Sep 17 00:00:00 2001
From: William Oldham
Date: Tue, 9 Jan 2024 21:02:39 +0000
Subject: [PATCH 017/151] Remove ARM-32 bit from Docker build
---
.github/workflows/deploying.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/deploying.yml b/.github/workflows/deploying.yml
index ebf9d131..e07a60a5 100644
--- a/.github/workflows/deploying.yml
+++ b/.github/workflows/deploying.yml
@@ -173,7 +173,7 @@ jobs:
uses: docker/build-push-action@v5
with:
push: true
- platforms: linux/amd64,linux/arm64,linux/arm
+ platforms: linux/amd64,linux/arm64
context: .
labels: ${{ steps.meta.outputs.labels }}
tags: ${{ steps.meta.outputs.tags }}
From 52bc66e7dd934c22913a562757048ec48bde0e58 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Tue, 9 Jan 2024 23:00:54 +0100
Subject: [PATCH 018/151] improve typings
---
src/backend/extension/messaging.ts | 51 ++++++++++++++---------
src/backend/extension/plasmo.ts | 67 ++++++++++++++++++++----------
src/backend/extension/streams.ts | 9 ++--
src/backend/providers/fetchers.ts | 9 +++-
4 files changed, 87 insertions(+), 49 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 3c5480c1..28f80ad2 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -7,18 +7,17 @@ import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
let activeExtension = false;
-export interface ExtensionHello {
- version: string;
-}
-
-function sendMessage(
- message: keyof MessagesMetadata,
- payload: any,
+function sendMessage(
+ message: MessageKey,
+ payload: MessagesMetadata[MessageKey]["req"],
timeout: number = -1,
) {
- return new Promise((resolve) => {
+ return new Promise((resolve) => {
if (timeout >= 0) setTimeout(() => resolve(null), timeout);
- sendToBackgroundViaRelay({
+ sendToBackgroundViaRelay<
+ MessagesMetadata[MessageKey]["req"],
+ MessagesMetadata[MessageKey]["res"]
+ >({
name: message,
body: payload,
})
@@ -34,21 +33,33 @@ function sendMessage(
}
export async function sendExtensionRequest(
- url: string,
- ops: any,
-): Promise {
- return sendMessage("make-request", { url, ...ops });
+ ops: Omit,
+): Promise {
+ return sendMessage("makeRequest", {
+ requestDomain: window.location.origin,
+ ...ops,
+ });
}
export async function setDomainRule(
- domains: string[],
- headers: Record,
-): Promise {
- return sendMessage("prepare-stream", { domains, headers });
+ ops: Omit,
+): Promise {
+ return sendMessage("prepareStream", {
+ requestDomain: window.location.origin,
+ ...ops,
+ });
}
-export async function extensionInfo(): Promise {
- return sendMessage("hello", null, 300);
+export async function extensionInfo(): Promise<
+ MessagesMetadata["hello"]["res"] | null
+> {
+ return sendMessage(
+ "hello",
+ {
+ requestDomain: window.location.origin,
+ },
+ 300,
+ );
}
export function isExtensionActiveCached(): boolean {
@@ -57,7 +68,7 @@ export function isExtensionActiveCached(): boolean {
export async function isExtensionActive(): Promise {
const info = await extensionInfo();
- if (!info) return false;
+ if (!info?.success) return false;
const allowedVersion = isAllowedExtensionVersion(info.version);
if (!allowedVersion) return false;
return true;
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index 8c0093f0..6c37ad14 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -1,6 +1,37 @@
-export interface PlasmoRequestBody {
+export interface ExtensionBaseRequest {
+ requestDomain: string;
+}
+
+export type ExtensionBaseResponse =
+ | ({
+ success: true;
+ } & T)
+ | {
+ success: false;
+ error: string;
+ };
+
+export type ExtensionHelloResponse = ExtensionBaseResponse<{
+ version: string;
+}>;
+
+export interface ExtensionMakeRequest extends ExtensionBaseRequest {
+ url: string;
+ method: string;
+ headers?: Record;
+ body?: string | FormData | URLSearchParams | Record;
+}
+
+export type ExtensionMakeRequestResponse = ExtensionBaseResponse<{
+ status: number;
+ requestHeaders: Record;
+ responseHeaders: Record;
+ data: string | Record;
+}>;
+
+export interface ExtensionPrepareStreamRequest extends ExtensionBaseRequest {
ruleId: number;
- domain: string;
+ targetDomains: string[];
requestHeaders?: Record;
responseHeaders?: Record;
}
@@ -9,28 +40,18 @@ export interface ExtensionHelloReply {
version: string;
}
-export type ExtensionRequestReply =
- | {
- success: true;
- ruleId: number;
- }
- | {
- success: false;
- error: string;
- };
-
-interface MmMetadata {
- "prepare-stream": {
- req: PlasmoRequestBody;
- res: ExtensionRequestReply;
- };
- "make-request": {
- req: PlasmoRequestBody;
- res: ExtensionRequestReply;
- };
+export interface MmMetadata {
hello: {
- req: null;
- res: ExtensionHelloReply;
+ req: ExtensionBaseRequest;
+ res: ExtensionHelloResponse;
+ };
+ makeRequest: {
+ req: ExtensionMakeRequest;
+ res: ExtensionMakeRequestResponse;
+ };
+ prepareStream: {
+ req: ExtensionPrepareStreamRequest;
+ res: ExtensionBaseResponse;
};
}
diff --git a/src/backend/extension/streams.ts b/src/backend/extension/streams.ts
index 8d202992..2afb900d 100644
--- a/src/backend/extension/streams.ts
+++ b/src/backend/extension/streams.ts
@@ -33,8 +33,9 @@ function buildHeadersFromStream(stream: Stream): Record {
}
export async function prepareStream(stream: Stream) {
- await setDomainRule(
- extractDomainsFromStream(stream),
- buildHeadersFromStream(stream),
- );
+ await setDomainRule({
+ ruleId: 1,
+ targetDomains: extractDomainsFromStream(stream),
+ requestHeaders: buildHeadersFromStream(stream),
+ });
}
diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts
index 596e8376..e133199c 100644
--- a/src/backend/providers/fetchers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -54,8 +54,13 @@ export function makeLoadBalancedSimpleProxyFetcher() {
}
export function makeExtensionFetcher() {
- const fetcher: Fetcher = async (a, b) => {
- return sendExtensionRequest(a, b) as any;
+ const fetcher: Fetcher = async (url, ops) => {
+ return sendExtensionRequest({
+ url,
+ method: ops?.method ?? "GET",
+ headers: ops?.headers,
+ body: ops?.body,
+ }) as any;
};
return fetcher;
}
From 4bdb95ed0fd88fb456f03691c5a689c17b381a28 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Tue, 9 Jan 2024 23:35:23 +0100
Subject: [PATCH 019/151] fix
---
src/backend/providers/fetchers.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts
index e133199c..f1dbbfb8 100644
--- a/src/backend/providers/fetchers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -57,9 +57,7 @@ export function makeExtensionFetcher() {
const fetcher: Fetcher = async (url, ops) => {
return sendExtensionRequest({
url,
- method: ops?.method ?? "GET",
- headers: ops?.headers,
- body: ops?.body,
+ ...ops,
}) as any;
};
return fetcher;
From caa82e15a3d5bc2c5eb3e9f3b710b90278d65281 Mon Sep 17 00:00:00 2001
From: Isra
Date: Tue, 9 Jan 2024 21:14:03 -0600
Subject: [PATCH 020/151] Instructions
---
src/assets/locales/en.json | 4 ++--
src/pages/parts/settings/ConnectionsPart.tsx | 11 ++++++++---
2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json
index 9329ec0e..425f6c32 100644
--- a/src/assets/locales/en.json
+++ b/src/assets/locales/en.json
@@ -393,14 +393,14 @@
},
"connections": {
"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",
"urlLabel": "Custom server URL"
},
"title": "Connections",
"workers": {
"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",
"label": "Use custom proxy workers",
"urlLabel": "Worker URLs",
diff --git a/src/pages/parts/settings/ConnectionsPart.tsx b/src/pages/parts/settings/ConnectionsPart.tsx
index 007a6220..11aa8171 100644
--- a/src/pages/parts/settings/ConnectionsPart.tsx
+++ b/src/pages/parts/settings/ConnectionsPart.tsx
@@ -1,10 +1,11 @@
import { Dispatch, SetStateAction, useCallback } from "react";
-import { useTranslation } from "react-i18next";
+import { Trans, useTranslation } from "react-i18next";
import { Button } from "@/components/buttons/Button";
import { Toggle } from "@/components/buttons/Toggle";
import { Icon, Icons } from "@/components/Icon";
import { SettingsCard } from "@/components/layout/SettingsCard";
+import { MwLink } from "@/components/text/Link";
import { AuthInputBox } from "@/components/text-inputs/AuthInputBox";
import { Divider } from "@/components/utils/Divider";
import { Heading1 } from "@/components/utils/Text";
@@ -52,7 +53,9 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
{t("settings.connections.workers.label")}
- {t("settings.connections.workers.description")}
+
+ Google
+
@@ -118,7 +121,9 @@ function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
{t("settings.connections.server.label")}
- {t("settings.connections.server.description")}
+
+ Google
+
From b11a7016be6874956a5f33e4d25ad90cc3064ab4 Mon Sep 17 00:00:00 2001
From: Isra
Date: Tue, 9 Jan 2024 21:18:41 -0600
Subject: [PATCH 021/151] Actual links
---
src/pages/parts/settings/ConnectionsPart.tsx | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/pages/parts/settings/ConnectionsPart.tsx b/src/pages/parts/settings/ConnectionsPart.tsx
index 11aa8171..e9183764 100644
--- a/src/pages/parts/settings/ConnectionsPart.tsx
+++ b/src/pages/parts/settings/ConnectionsPart.tsx
@@ -54,7 +54,9 @@ function ProxyEdit({ proxyUrls, setProxyUrls }: ProxyEditProps) {
- Google
+
+ Proxy documentation
+
@@ -122,7 +124,9 @@ function BackendEdit({ backendUrl, setBackendUrl }: BackendEditProps) {
- Google
+
+ Backend documentation
+
From e1be30dde9ad62760b44300b945556791cad5e13 Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Wed, 10 Jan 2024 18:20:51 +0100
Subject: [PATCH 022/151] Request messaging
---
src/backend/extension/messaging.ts | 5 +++--
src/backend/extension/plasmo.ts | 14 ++++++++------
src/backend/providers/fetchers.ts | 24 ++++++++++++++++++++++--
3 files changed, 33 insertions(+), 10 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 28f80ad2..3d835a0e 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -4,6 +4,7 @@ import {
} from "@plasmohq/messaging";
import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
+import { ExtensionMakeRequestResponse } from "@/backend/extension/plasmo";
let activeExtension = false;
@@ -32,9 +33,9 @@ function sendMessage(
});
}
-export async function sendExtensionRequest(
+export async function sendExtensionRequest(
ops: Omit,
-): Promise {
+): Promise | null> {
return sendMessage("makeRequest", {
requestDomain: window.location.origin,
...ops,
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index 6c37ad14..0a2b3dc5 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -22,11 +22,13 @@ export interface ExtensionMakeRequest extends ExtensionBaseRequest {
body?: string | FormData | URLSearchParams | Record;
}
-export type ExtensionMakeRequestResponse = ExtensionBaseResponse<{
- status: number;
- requestHeaders: Record;
- responseHeaders: Record;
- data: string | Record;
+export type ExtensionMakeRequestResponse = ExtensionBaseResponse<{
+ response: {
+ statusCode: number;
+ headers: Record;
+ finalUrl: string;
+ body: T;
+ };
}>;
export interface ExtensionPrepareStreamRequest extends ExtensionBaseRequest {
@@ -47,7 +49,7 @@ export interface MmMetadata {
};
makeRequest: {
req: ExtensionMakeRequest;
- res: ExtensionMakeRequestResponse;
+ res: ExtensionMakeRequestResponse;
};
prepareStream: {
req: ExtensionPrepareStreamRequest;
diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts
index f1dbbfb8..9db649f5 100644
--- a/src/backend/providers/fetchers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -53,12 +53,32 @@ export function makeLoadBalancedSimpleProxyFetcher() {
return fetcher;
}
+function makeFinalHeaders(
+ readHeaders: string[],
+ headers: Record,
+): Headers {
+ const lowercasedHeaders = readHeaders.map((v) => v.toLowerCase());
+ return new Headers(
+ Object.entries(headers).filter((entry) =>
+ lowercasedHeaders.includes(entry[0].toLowerCase()),
+ ),
+ );
+}
+
export function makeExtensionFetcher() {
const fetcher: Fetcher = async (url, ops) => {
- return sendExtensionRequest({
+ const result = await sendExtensionRequest({
url,
...ops,
- }) as any;
+ });
+ if (!result?.success) throw new Error(`extension error: ${result?.error}`);
+ const res = result.response;
+ return {
+ body: res.body,
+ finalUrl: res.finalUrl,
+ statusCode: res.statusCode,
+ headers: makeFinalHeaders(ops.readHeaders, res.headers),
+ };
};
return fetcher;
}
From d32ef6ed9ae88db294a8c232c65018a65f1b4abc Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Wed, 10 Jan 2024 19:43:54 +0100
Subject: [PATCH 023/151] fix extension not preparing stream on embed selection
---
src/components/player/hooks/useSourceSelection.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/components/player/hooks/useSourceSelection.ts b/src/components/player/hooks/useSourceSelection.ts
index b9e167d6..3016e332 100644
--- a/src/components/player/hooks/useSourceSelection.ts
+++ b/src/components/player/hooks/useSourceSelection.ts
@@ -72,6 +72,7 @@ export function useEmbedScraping(
report([
scrapeSourceOutputToProviderMetric(meta, sourceId, null, "success", null),
]);
+ await prepareStream(result.stream[0]);
setSourceId(sourceId);
setCaption(null);
setSource(
From 3704dfba10ae8ada3573c084848c7e0ebf8fb5c4 Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Wed, 10 Jan 2024 22:04:21 +0100
Subject: [PATCH 024/151] Fix styling bugs, fix player not switching source
after error, fix allowed state in extension, add ip locked sourced for
extension
Co-authored-by: Jip Frijlink
---
src/backend/extension/messaging.ts | 7 +++++--
src/backend/extension/plasmo.ts | 5 +----
src/backend/providers/providers.ts | 1 +
.../player/atoms/settings/SourceSelectingView.tsx | 2 +-
src/stores/player/slices/source.ts | 10 +++++++++-
src/utils/language.ts | 2 +-
6 files changed, 18 insertions(+), 9 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 3d835a0e..4594fb23 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -37,7 +37,7 @@ export async function sendExtensionRequest(
ops: Omit,
): Promise | null> {
return sendMessage("makeRequest", {
- requestDomain: window.location.origin,
+ requestDomain: window.location.origin, // TODO unsafe
...ops,
});
}
@@ -54,13 +54,16 @@ export async function setDomainRule(
export async function extensionInfo(): Promise<
MessagesMetadata["hello"]["res"] | null
> {
- return sendMessage(
+ const message = await sendMessage(
"hello",
{
requestDomain: window.location.origin,
},
300,
);
+ if (!message?.success) return null;
+ if (!message.allowed) return null;
+ return message;
}
export function isExtensionActiveCached(): boolean {
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index 0a2b3dc5..e142ef6a 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -13,6 +13,7 @@ export type ExtensionBaseResponse =
export type ExtensionHelloResponse = ExtensionBaseResponse<{
version: string;
+ allowed: boolean;
}>;
export interface ExtensionMakeRequest extends ExtensionBaseRequest {
@@ -38,10 +39,6 @@ export interface ExtensionPrepareStreamRequest extends ExtensionBaseRequest {
responseHeaders?: Record;
}
-export interface ExtensionHelloReply {
- version: string;
-}
-
export interface MmMetadata {
hello: {
req: ExtensionBaseRequest;
diff --git a/src/backend/providers/providers.ts b/src/backend/providers/providers.ts
index 1a7b484a..ac4a7dfa 100644
--- a/src/backend/providers/providers.ts
+++ b/src/backend/providers/providers.ts
@@ -15,6 +15,7 @@ export function getProviders() {
return makeProviders({
fetcher: makeExtensionFetcher(),
target: targets.BROWSER_EXTENSION,
+ consistentIpForRequests: true,
});
}
diff --git a/src/components/player/atoms/settings/SourceSelectingView.tsx b/src/components/player/atoms/settings/SourceSelectingView.tsx
index 03d0875d..f995308e 100644
--- a/src/components/player/atoms/settings/SourceSelectingView.tsx
+++ b/src/components/player/atoms/settings/SourceSelectingView.tsx
@@ -147,7 +147,7 @@ export function SourceSelectionView({
router.navigate("/")}>
{t("player.menus.sources.title")}
-
+
{sources.map((v) => (
= (set, get) => ({
},
setSourceId(id) {
set((s) => {
+ s.status = playerStatus.PLAYING;
s.sourceId = id;
});
},
@@ -153,6 +154,8 @@ export const createSourceSlice: MakeSlice = (set, get) => ({
s.qualities = qualities as SourceQuality[];
s.currentQuality = loadableStream.quality;
s.captionList = captions;
+ s.interface.error = undefined;
+ s.status = playerStatus.PLAYING;
});
const store = get();
store.redisplaySource(startAt);
@@ -166,7 +169,10 @@ export const createSourceSlice: MakeSlice = (set, get) => ({
automaticQuality: qualityPreferences.quality.automaticQuality,
lastChosenQuality: quality,
});
-
+ set((s) => {
+ s.interface.error = undefined;
+ s.status = playerStatus.PLAYING;
+ });
store.display?.load({
source: loadableStream.stream,
startAt,
@@ -182,6 +188,8 @@ export const createSourceSlice: MakeSlice = (set, get) => ({
if (!selectedQuality) return;
set((s) => {
s.currentQuality = quality;
+ s.status = playerStatus.PLAYING;
+ s.interface.error = undefined;
});
store.display?.load({
source: selectedQuality,
diff --git a/src/utils/language.ts b/src/utils/language.ts
index 6fda7df8..41b8168b 100644
--- a/src/utils/language.ts
+++ b/src/utils/language.ts
@@ -86,7 +86,7 @@ function populateLanguageCode(language: string): string {
* @returns pretty format for language, null if it no info can be found for language
*/
export function getPrettyLanguageNameFromLocale(locale: string): string | null {
- const tag = getTag(populateLanguageCode(locale), true);
+ const tag = getTag(locale, true);
const lang = tag?.language?.Description?.[0] ?? null;
if (!lang) return null;
From 6c7f1aceceab21bd5db888d2e1c2604084f0c0ae Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Thu, 11 Jan 2024 19:16:22 +0100
Subject: [PATCH 025/151] Remove requestDomain
---
src/backend/extension/messaging.ts | 18 +++---------------
src/backend/extension/plasmo.ts | 4 +---
2 files changed, 4 insertions(+), 18 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 4594fb23..6d1f32fd 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -36,31 +36,19 @@ function sendMessage(
export async function sendExtensionRequest(
ops: Omit,
): Promise | null> {
- return sendMessage("makeRequest", {
- requestDomain: window.location.origin, // TODO unsafe
- ...ops,
- });
+ return sendMessage("makeRequest", ops);
}
export async function setDomainRule(
ops: Omit,
): Promise {
- return sendMessage("prepareStream", {
- requestDomain: window.location.origin,
- ...ops,
- });
+ return sendMessage("prepareStream", ops);
}
export async function extensionInfo(): Promise<
MessagesMetadata["hello"]["res"] | null
> {
- const message = await sendMessage(
- "hello",
- {
- requestDomain: window.location.origin,
- },
- 300,
- );
+ const message = await sendMessage("hello", {}, 300);
if (!message?.success) return null;
if (!message.allowed) return null;
return message;
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index e142ef6a..12222b22 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -1,6 +1,4 @@
-export interface ExtensionBaseRequest {
- requestDomain: string;
-}
+export interface ExtensionBaseRequest {}
export type ExtensionBaseResponse =
| ({
From ccbf888946082d339234f06317517a09aa65fa69 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Thu, 11 Jan 2024 23:45:33 +0100
Subject: [PATCH 026/151] firefox support (kinda with manual permission set)
---
src/backend/extension/streams.ts | 2 +-
src/backend/providers/fetchers.ts | 36 ++++++++++++++++++++++---------
src/backend/providers/utils.ts | 29 +++++++++++++++++++++++++
3 files changed, 56 insertions(+), 11 deletions(-)
create mode 100644 src/backend/providers/utils.ts
diff --git a/src/backend/extension/streams.ts b/src/backend/extension/streams.ts
index 2afb900d..daa7a54c 100644
--- a/src/backend/extension/streams.ts
+++ b/src/backend/extension/streams.ts
@@ -34,7 +34,7 @@ function buildHeadersFromStream(stream: Stream): Record {
export async function prepareStream(stream: Stream) {
await setDomainRule({
- ruleId: 1,
+ ruleId: 2,
targetDomains: extractDomainsFromStream(stream),
requestHeaders: buildHeadersFromStream(stream),
});
diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts
index 9db649f5..83e42835 100644
--- a/src/backend/providers/fetchers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -1,9 +1,11 @@
import { Fetcher, makeSimpleProxyFetcher } from "@movie-web/providers";
-import { sendExtensionRequest } from "@/backend/extension/messaging";
+import { setDomainRule } from "@/backend/extension/messaging";
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
import { getProviderApiUrls, getProxyUrls } from "@/utils/proxyUrls";
+import { makeFullUrl } from "./utils";
+
function makeLoadbalancedList(getter: () => string[]) {
let listIndex = -1;
return () => {
@@ -67,17 +69,31 @@ function makeFinalHeaders(
export function makeExtensionFetcher() {
const fetcher: Fetcher = async (url, ops) => {
- const result = await sendExtensionRequest({
- url,
- ...ops,
+ const fullUrl = makeFullUrl(url, ops);
+ const res = await setDomainRule({
+ ruleId: 1,
+ targetDomains: [fullUrl],
+ requestHeaders: ops.headers,
});
- if (!result?.success) throw new Error(`extension error: ${result?.error}`);
- const res = result.response;
+ console.log(res, fullUrl);
+ const response = await fetch(fullUrl, {
+ method: ops.method,
+ headers: ops.headers,
+ body: ops.body as any,
+ });
+ const contentType = response.headers.get("content-type");
+ const body = contentType?.includes("application/json")
+ ? await response.json()
+ : await response.text();
+
return {
- body: res.body,
- finalUrl: res.finalUrl,
- statusCode: res.statusCode,
- headers: makeFinalHeaders(ops.readHeaders, res.headers),
+ body,
+ finalUrl: response.url,
+ statusCode: response.status,
+ headers: makeFinalHeaders(
+ ops.readHeaders,
+ Object.fromEntries(response.headers.entries()),
+ ),
};
};
return fetcher;
diff --git a/src/backend/providers/utils.ts b/src/backend/providers/utils.ts
new file mode 100644
index 00000000..7149046c
--- /dev/null
+++ b/src/backend/providers/utils.ts
@@ -0,0 +1,29 @@
+import { DefaultedFetcherOptions } from "@movie-web/providers";
+
+export function makeFullUrl(
+ url: string,
+ ops?: DefaultedFetcherOptions,
+): string {
+ // glue baseUrl and rest of url together
+ let leftSide = ops?.baseUrl ?? "";
+ let rightSide = url;
+
+ // left side should always end with slash, if its set
+ if (leftSide.length > 0 && !leftSide.endsWith("/")) leftSide += "/";
+
+ // right side should never start with slash
+ if (rightSide.startsWith("/")) rightSide = rightSide.slice(1);
+
+ const fullUrl = leftSide + rightSide;
+ if (!fullUrl.startsWith("http://") && !fullUrl.startsWith("https://"))
+ throw new Error(
+ `Invald URL -- URL doesn't start with a http scheme: '${fullUrl}'`,
+ );
+
+ const parsedUrl = new URL(fullUrl);
+ Object.entries(ops?.query ?? {}).forEach(([k, v]) => {
+ parsedUrl.searchParams.set(k, v as string);
+ });
+
+ return parsedUrl.toString();
+}
From a4b925dc1b7749aa4caed3b4b4c174d38f018795 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Fri, 12 Jan 2024 18:46:51 +0100
Subject: [PATCH 027/151] revert back to makeRequest
---
src/backend/extension/streams.ts | 2 +-
src/backend/providers/fetchers.ts | 38 +++++++++----------------------
src/backend/providers/utils.ts | 29 -----------------------
3 files changed, 12 insertions(+), 57 deletions(-)
delete mode 100644 src/backend/providers/utils.ts
diff --git a/src/backend/extension/streams.ts b/src/backend/extension/streams.ts
index daa7a54c..2afb900d 100644
--- a/src/backend/extension/streams.ts
+++ b/src/backend/extension/streams.ts
@@ -34,7 +34,7 @@ function buildHeadersFromStream(stream: Stream): Record {
export async function prepareStream(stream: Stream) {
await setDomainRule({
- ruleId: 2,
+ ruleId: 1,
targetDomains: extractDomainsFromStream(stream),
requestHeaders: buildHeadersFromStream(stream),
});
diff --git a/src/backend/providers/fetchers.ts b/src/backend/providers/fetchers.ts
index 83e42835..95267595 100644
--- a/src/backend/providers/fetchers.ts
+++ b/src/backend/providers/fetchers.ts
@@ -1,11 +1,9 @@
import { Fetcher, makeSimpleProxyFetcher } from "@movie-web/providers";
-import { setDomainRule } from "@/backend/extension/messaging";
+import { sendExtensionRequest } from "@/backend/extension/messaging";
import { getApiToken, setApiToken } from "@/backend/helpers/providerApi";
import { getProviderApiUrls, getProxyUrls } from "@/utils/proxyUrls";
-import { makeFullUrl } from "./utils";
-
function makeLoadbalancedList(getter: () => string[]) {
let listIndex = -1;
return () => {
@@ -69,31 +67,17 @@ function makeFinalHeaders(
export function makeExtensionFetcher() {
const fetcher: Fetcher = async (url, ops) => {
- const fullUrl = makeFullUrl(url, ops);
- const res = await setDomainRule({
- ruleId: 1,
- targetDomains: [fullUrl],
- requestHeaders: ops.headers,
- });
- console.log(res, fullUrl);
- const response = await fetch(fullUrl, {
- method: ops.method,
- headers: ops.headers,
- body: ops.body as any,
- });
- const contentType = response.headers.get("content-type");
- const body = contentType?.includes("application/json")
- ? await response.json()
- : await response.text();
-
+ const result = (await sendExtensionRequest({
+ url,
+ ...ops,
+ })) as any;
+ if (!result?.success) throw new Error(`extension error: ${result?.error}`);
+ const res = result.response;
return {
- body,
- finalUrl: response.url,
- statusCode: response.status,
- headers: makeFinalHeaders(
- ops.readHeaders,
- Object.fromEntries(response.headers.entries()),
- ),
+ body: res.body,
+ finalUrl: res.finalUrl,
+ statusCode: res.statusCode,
+ headers: makeFinalHeaders(ops.readHeaders, res.headers),
};
};
return fetcher;
diff --git a/src/backend/providers/utils.ts b/src/backend/providers/utils.ts
deleted file mode 100644
index 7149046c..00000000
--- a/src/backend/providers/utils.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import { DefaultedFetcherOptions } from "@movie-web/providers";
-
-export function makeFullUrl(
- url: string,
- ops?: DefaultedFetcherOptions,
-): string {
- // glue baseUrl and rest of url together
- let leftSide = ops?.baseUrl ?? "";
- let rightSide = url;
-
- // left side should always end with slash, if its set
- if (leftSide.length > 0 && !leftSide.endsWith("/")) leftSide += "/";
-
- // right side should never start with slash
- if (rightSide.startsWith("/")) rightSide = rightSide.slice(1);
-
- const fullUrl = leftSide + rightSide;
- if (!fullUrl.startsWith("http://") && !fullUrl.startsWith("https://"))
- throw new Error(
- `Invald URL -- URL doesn't start with a http scheme: '${fullUrl}'`,
- );
-
- const parsedUrl = new URL(fullUrl);
- Object.entries(ops?.query ?? {}).forEach(([k, v]) => {
- parsedUrl.searchParams.set(k, v as string);
- });
-
- return parsedUrl.toString();
-}
From 948843769820630fdc49e323bd64a788d968f7e6 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Sun, 14 Jan 2024 18:19:38 +0100
Subject: [PATCH 028/151] check if extension has permissions
---
src/backend/extension/messaging.ts | 10 +++++--
src/backend/extension/plasmo.ts | 8 ++++++
src/pages/parts/player/MetaPart.tsx | 43 ++++++++++++++++++++++++++---
3 files changed, 55 insertions(+), 6 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 6d1f32fd..2e2747c1 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -34,17 +34,23 @@ function sendMessage(
}
export async function sendExtensionRequest(
- ops: Omit,
+ ops: MessagesMetadata["makeRequest"]["req"],
): Promise | null> {
return sendMessage("makeRequest", ops);
}
export async function setDomainRule(
- ops: Omit,
+ ops: MessagesMetadata["prepareStream"]["req"],
): Promise {
return sendMessage("prepareStream", ops);
}
+export async function sendPage(
+ ops: MessagesMetadata["openPage"]["req"],
+): Promise {
+ return sendMessage("openPage", ops);
+}
+
export async function extensionInfo(): Promise<
MessagesMetadata["hello"]["res"] | null
> {
diff --git a/src/backend/extension/plasmo.ts b/src/backend/extension/plasmo.ts
index 12222b22..c13898be 100644
--- a/src/backend/extension/plasmo.ts
+++ b/src/backend/extension/plasmo.ts
@@ -12,6 +12,7 @@ export type ExtensionBaseResponse =
export type ExtensionHelloResponse = ExtensionBaseResponse<{
version: string;
allowed: boolean;
+ hasPermission: boolean;
}>;
export interface ExtensionMakeRequest extends ExtensionBaseRequest {
@@ -50,6 +51,13 @@ export interface MmMetadata {
req: ExtensionPrepareStreamRequest;
res: ExtensionBaseResponse;
};
+ openPage: {
+ req: ExtensionBaseRequest & {
+ page: string;
+ redirectUrl: string;
+ };
+ res: ExtensionBaseResponse;
+ };
}
interface MpMetadata {}
diff --git a/src/pages/parts/player/MetaPart.tsx b/src/pages/parts/player/MetaPart.tsx
index 6d5b64ef..fb40379a 100644
--- a/src/pages/parts/player/MetaPart.tsx
+++ b/src/pages/parts/player/MetaPart.tsx
@@ -3,7 +3,8 @@ import { useNavigate, useParams } from "react-router-dom";
import { useAsync } from "react-use";
import type { AsyncReturnType } from "type-fest";
-import { isExtensionActive } from "@/backend/extension/messaging";
+import { isAllowedExtensionVersion } from "@/backend/extension/compatibility";
+import { extensionInfo, sendPage } from "@/backend/extension/messaging";
import {
fetchMetadata,
setCachedMetadata,
@@ -43,12 +44,16 @@ export function MetaPart(props: MetaPartProps) {
const navigate = useNavigate();
const { error, value, loading } = useAsync(async () => {
- // check extension
- const isActive = await isExtensionActive();
+ const info = await extensionInfo();
+ const isAllowed = info?.success && isAllowedExtensionVersion(info.version);
+
+ if (isAllowed) {
+ if (!info.hasPermission) throw new Error("extension-no-permission");
+ }
// use api metadata or providers metadata
const providerApiUrl = getLoadbalancedProviderApiUrl();
- if (providerApiUrl && !isActive) {
+ if (providerApiUrl && !isAllowed) {
try {
await fetchMetadata(providerApiUrl);
} catch (err) {
@@ -105,6 +110,36 @@ export function MetaPart(props: MetaPartProps) {
props.onGetMeta?.(meta, epId);
}, []);
+ if (error && error.message === "extension-no-permission") {
+ return (
+
+
+
+ {t("player.metadata.failed.badge")}
+
+ Configure the extension
+
+ You have the browser extension, but we need your permission to get
+ started using the extension.
+
+
+
+
+ );
+ }
+
if (error && error.message === "dmca") {
return (
From fa2b610ea6f3e4fc3d6481ed5f5c2090478adbd4 Mon Sep 17 00:00:00 2001
From: Jorrin
Date: Sun, 14 Jan 2024 22:33:46 +0100
Subject: [PATCH 029/151] fix permission check on domain level
---
src/backend/extension/messaging.ts | 6 ++----
src/pages/parts/player/MetaPart.tsx | 10 ++++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/backend/extension/messaging.ts b/src/backend/extension/messaging.ts
index 2e2747c1..b738184a 100644
--- a/src/backend/extension/messaging.ts
+++ b/src/backend/extension/messaging.ts
@@ -10,7 +10,7 @@ let activeExtension = false;
function sendMessage(
message: MessageKey,
- payload: MessagesMetadata[MessageKey]["req"],
+ payload: MessagesMetadata[MessageKey]["req"] | undefined = undefined,
timeout: number = -1,
) {
return new Promise((resolve) => {
@@ -54,9 +54,7 @@ export async function sendPage(
export async function extensionInfo(): Promise<
MessagesMetadata["hello"]["res"] | null
> {
- const message = await sendMessage("hello", {}, 300);
- if (!message?.success) return null;
- if (!message.allowed) return null;
+ const message = await sendMessage("hello", undefined, 300);
return message;
}
diff --git a/src/pages/parts/player/MetaPart.tsx b/src/pages/parts/player/MetaPart.tsx
index fb40379a..1e18b6d1 100644
--- a/src/pages/parts/player/MetaPart.tsx
+++ b/src/pages/parts/player/MetaPart.tsx
@@ -45,15 +45,17 @@ export function MetaPart(props: MetaPartProps) {
const { error, value, loading } = useAsync(async () => {
const info = await extensionInfo();
- const isAllowed = info?.success && isAllowedExtensionVersion(info.version);
+ const isValidExtension =
+ info?.success && isAllowedExtensionVersion(info.version);
- if (isAllowed) {
- if (!info.hasPermission) throw new Error("extension-no-permission");
+ if (isValidExtension) {
+ if (!info.allowed || !info.hasPermission)
+ throw new Error("extension-no-permission");
}
// use api metadata or providers metadata
const providerApiUrl = getLoadbalancedProviderApiUrl();
- if (providerApiUrl && !isAllowed) {
+ if (providerApiUrl && !isValidExtension) {
try {
await fetchMetadata(providerApiUrl);
} catch (err) {
From 925f3dff199fc6457eb9f97209addf780700e565 Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Tue, 16 Jan 2024 20:28:33 +0100
Subject: [PATCH 030/151] Basic onboarding structure
---
src/components/layout/Stepper.tsx | 25 ++++++++++
src/components/layout/ThinContainer.tsx | 14 ++++++
src/pages/PlayerView.tsx | 32 ++++++++++++-
src/pages/layouts/MinimalPageLayout.tsx | 28 ++++++++++++
src/pages/onboarding/Onboarding.tsx | 48 ++++++++++++++++++++
src/pages/onboarding/OnboardingExtension.tsx | 27 +++++++++++
src/pages/onboarding/OnboardingProxy.tsx | 27 +++++++++++
src/pages/onboarding/onboardingHooks.ts | 22 +++++++++
src/setup/App.tsx | 9 ++++
src/setup/config.ts | 4 ++
src/stores/history/index.ts | 3 +-
src/stores/onboarding/index.tsx | 22 +++++++++
src/utils/onboarding.ts | 23 ++++++++++
13 files changed, 281 insertions(+), 3 deletions(-)
create mode 100644 src/components/layout/Stepper.tsx
create mode 100644 src/pages/layouts/MinimalPageLayout.tsx
create mode 100644 src/pages/onboarding/Onboarding.tsx
create mode 100644 src/pages/onboarding/OnboardingExtension.tsx
create mode 100644 src/pages/onboarding/OnboardingProxy.tsx
create mode 100644 src/pages/onboarding/onboardingHooks.ts
create mode 100644 src/stores/onboarding/index.tsx
create mode 100644 src/utils/onboarding.ts
diff --git a/src/components/layout/Stepper.tsx b/src/components/layout/Stepper.tsx
new file mode 100644
index 00000000..d0c9c499
--- /dev/null
+++ b/src/components/layout/Stepper.tsx
@@ -0,0 +1,25 @@
+export interface StepperProps {
+ current: number;
+ steps: number;
+ className?: string;
+}
+
+export function Stepper(props: StepperProps) {
+ const percentage = (props.current / (props.steps + 1)) * 100;
+
+ return (
+
+
+ {props.current}/{props.steps}
+
+
+
+ );
+}
diff --git a/src/components/layout/ThinContainer.tsx b/src/components/layout/ThinContainer.tsx
index f7f90acb..345afa5c 100644
--- a/src/components/layout/ThinContainer.tsx
+++ b/src/components/layout/ThinContainer.tsx
@@ -1,3 +1,4 @@
+import classNames from "classnames";
import { ReactNode } from "react";
interface ThinContainerProps {
@@ -16,3 +17,16 @@ export function ThinContainer(props: ThinContainerProps) {
);
}
+
+export function CenterContainer(props: ThinContainerProps) {
+ return (
+
+ );
+}
diff --git a/src/pages/PlayerView.tsx b/src/pages/PlayerView.tsx
index aa73bd83..5282d9b3 100644
--- a/src/pages/PlayerView.tsx
+++ b/src/pages/PlayerView.tsx
@@ -1,6 +1,12 @@
import { RunOutput } from "@movie-web/providers";
import { useCallback, useEffect, useState } from "react";
-import { useNavigate, useParams } from "react-router-dom";
+import {
+ Navigate,
+ useLocation,
+ useNavigate,
+ useParams,
+} from "react-router-dom";
+import { useAsync } from "react-use";
import { usePlayer } from "@/components/player/hooks/usePlayer";
import { usePlayerMeta } from "@/components/player/hooks/usePlayerMeta";
@@ -15,9 +21,10 @@ import { ScrapeErrorPart } from "@/pages/parts/player/ScrapeErrorPart";
import { ScrapingPart } from "@/pages/parts/player/ScrapingPart";
import { useLastNonPlayerLink } from "@/stores/history";
import { PlayerMeta, playerStatus } from "@/stores/player/slices/source";
+import { needsOnboarding } from "@/utils/onboarding";
import { parseTimestamp } from "@/utils/timestamp";
-export function PlayerView() {
+export function RealPlayerView() {
const navigate = useNavigate();
const params = useParams<{
media: string;
@@ -109,4 +116,25 @@ export function PlayerView() {
);
}
+export function PlayerView() {
+ const loc = useLocation();
+ const { loading, error, value } = useAsync(() => {
+ return needsOnboarding();
+ });
+
+ if (error) throw new Error("Failed to detect onboarding");
+ if (loading) return null;
+ if (value)
+ return (
+
+ );
+ return ;
+}
+
export default PlayerView;
diff --git a/src/pages/layouts/MinimalPageLayout.tsx b/src/pages/layouts/MinimalPageLayout.tsx
new file mode 100644
index 00000000..6d2cf34d
--- /dev/null
+++ b/src/pages/layouts/MinimalPageLayout.tsx
@@ -0,0 +1,28 @@
+import { Link } from "react-router-dom";
+
+import { BrandPill } from "@/components/layout/BrandPill";
+import { BlurEllipsis } from "@/pages/layouts/SubPageLayout";
+
+export function MinimalPageLayout(props: { children: React.ReactNode }) {
+ return (
+
+
+ {/* Main page */}
+
+
+
+
+
+
{props.children}
+
+ );
+}
diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx
new file mode 100644
index 00000000..439cc87d
--- /dev/null
+++ b/src/pages/onboarding/Onboarding.tsx
@@ -0,0 +1,48 @@
+import { useNavigate } from "react-router-dom";
+
+import { Button } from "@/components/buttons/Button";
+import { Stepper } from "@/components/layout/Stepper";
+import { CenterContainer } from "@/components/layout/ThinContainer";
+import { Modal, ModalCard, useModal } from "@/components/overlays/Modal";
+import { Heading2, Paragraph } from "@/components/utils/Text";
+import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
+import { useRedirectBack } from "@/pages/onboarding/onboardingHooks";
+import { PageTitle } from "@/pages/parts/util/PageTitle";
+
+export function OnboardingPage() {
+ const navigate = useNavigate();
+ const skipModal = useModal("skip");
+ const { skipAndRedirect } = useRedirectBack();
+
+ return (
+
+
+
+
+
+ Lorem ipsum
+ Lorem ipsum Lorem ipsum Lorem ipsum
+
+
+
+
+
+
+
+ Lorem ipsum
+ Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
+
+
+
+
+
+ );
+}
diff --git a/src/pages/onboarding/OnboardingExtension.tsx b/src/pages/onboarding/OnboardingExtension.tsx
new file mode 100644
index 00000000..8ee85be7
--- /dev/null
+++ b/src/pages/onboarding/OnboardingExtension.tsx
@@ -0,0 +1,27 @@
+import { useNavigate } from "react-router-dom";
+
+import { Button } from "@/components/buttons/Button";
+import { Stepper } from "@/components/layout/Stepper";
+import { CenterContainer } from "@/components/layout/ThinContainer";
+import { Heading2, Paragraph } from "@/components/utils/Text";
+import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
+import { PageTitle } from "@/pages/parts/util/PageTitle";
+
+export function OnboardingExtensionPage() {
+ const navigate = useNavigate();
+
+ return (
+
+
+
+
+ Lorem ipsum
+ Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
+
+
+
+
+ );
+}
diff --git a/src/pages/onboarding/OnboardingProxy.tsx b/src/pages/onboarding/OnboardingProxy.tsx
new file mode 100644
index 00000000..45d22aea
--- /dev/null
+++ b/src/pages/onboarding/OnboardingProxy.tsx
@@ -0,0 +1,27 @@
+import { useNavigate } from "react-router-dom";
+
+import { Button } from "@/components/buttons/Button";
+import { Stepper } from "@/components/layout/Stepper";
+import { CenterContainer } from "@/components/layout/ThinContainer";
+import { Heading2, Paragraph } from "@/components/utils/Text";
+import { MinimalPageLayout } from "@/pages/layouts/MinimalPageLayout";
+import { PageTitle } from "@/pages/parts/util/PageTitle";
+
+export function OnboardingProxyPage() {
+ const navigate = useNavigate();
+
+ return (
+
+
+
+
+ Lorem ipsum
+ Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
+
+
+
+
+ );
+}
diff --git a/src/pages/onboarding/onboardingHooks.ts b/src/pages/onboarding/onboardingHooks.ts
new file mode 100644
index 00000000..e80234e7
--- /dev/null
+++ b/src/pages/onboarding/onboardingHooks.ts
@@ -0,0 +1,22 @@
+import { useCallback } from "react";
+import { useNavigate } from "react-router-dom";
+
+import { useQueryParam } from "@/hooks/useQueryParams";
+import { useOnboardingStore } from "@/stores/onboarding";
+
+export function useRedirectBack() {
+ const [url] = useQueryParam("redirect");
+ const navigate = useNavigate();
+ const setSkipped = useOnboardingStore((s) => s.setSkipped);
+
+ const redirectBack = useCallback(() => {
+ navigate(url ?? "/");
+ }, [navigate, url]);
+
+ const skipAndRedirect = useCallback(() => {
+ setSkipped(true);
+ redirectBack();
+ }, [redirectBack, setSkipped]);
+
+ return { redirectBack, skipAndRedirect };
+}
diff --git a/src/setup/App.tsx b/src/setup/App.tsx
index afa5f8ba..37c55e0f 100644
--- a/src/setup/App.tsx
+++ b/src/setup/App.tsx
@@ -19,6 +19,9 @@ import { DmcaPage, shouldHaveDmcaPage } from "@/pages/Dmca";
import { NotFoundPage } from "@/pages/errors/NotFoundPage";
import { HomePage } from "@/pages/HomePage";
import { LoginPage } from "@/pages/Login";
+import { OnboardingPage } from "@/pages/onboarding/Onboarding";
+import { OnboardingExtensionPage } from "@/pages/onboarding/OnboardingExtension";
+import { OnboardingProxyPage } from "@/pages/onboarding/OnboardingProxy";
import { RegisterPage } from "@/pages/Register";
import { Layout } from "@/setup/Layout";
import { useHistoryListener } from "@/stores/history";
@@ -119,6 +122,12 @@ function App() {
} />
} />
} />
+ } />
+ }
+ />
+ } />
{shouldHaveDmcaPage() ? (
} />
diff --git a/src/setup/config.ts b/src/setup/config.ts
index 2e1634a4..d6aca1cb 100644
--- a/src/setup/config.ts
+++ b/src/setup/config.ts
@@ -19,6 +19,7 @@ interface Config {
DISALLOWED_IDS: string;
TURNSTILE_KEY: string;
CDN_REPLACEMENTS: string;
+ HAS_ONBOARDING: string;
}
export interface RuntimeConfig {
@@ -34,6 +35,7 @@ export interface RuntimeConfig {
DISALLOWED_IDS: string[];
TURNSTILE_KEY: string | null;
CDN_REPLACEMENTS: Array;
+ HAS_ONBOARDING: boolean;
}
const env: Record = {
@@ -49,6 +51,7 @@ const env: Record = {
DISALLOWED_IDS: import.meta.env.VITE_DISALLOWED_IDS,
TURNSTILE_KEY: import.meta.env.VITE_TURNSTILE_KEY,
CDN_REPLACEMENTS: import.meta.env.VITE_CDN_REPLACEMENTS,
+ HAS_ONBOARDING: import.meta.env.VITE_HAS_ONBOARDING,
};
// loads from different locations, in order: environment (VITE_{KEY}), window (public/config.js)
@@ -82,6 +85,7 @@ export function conf(): RuntimeConfig {
.split(",")
.map((v) => v.trim()),
NORMAL_ROUTER: getKey("NORMAL_ROUTER", "false") === "true",
+ HAS_ONBOARDING: getKey("HAS_ONBOARDING", "false") === "true",
TURNSTILE_KEY: turnstileKey.length > 0 ? turnstileKey : null,
DISALLOWED_IDS: getKey("DISALLOWED_IDS", "")
.split(",")
diff --git a/src/stores/history/index.ts b/src/stores/history/index.ts
index c90a7309..c1f507ee 100644
--- a/src/stores/history/index.ts
+++ b/src/stores/history/index.ts
@@ -46,7 +46,8 @@ export function useLastNonPlayerLink() {
(v) =>
!v.path.startsWith("/media") && // cannot be a player link
location.pathname !== v.path && // cannot be current link
- !v.path.startsWith("/s/"), // cannot be a quick search link
+ !v.path.startsWith("/s/") && // cannot be a quick search link
+ !v.path.startsWith("/onboarding"), // cannot be an onboarding link
);
return route?.path ?? "/";
}, [routes, location]);
diff --git a/src/stores/onboarding/index.tsx b/src/stores/onboarding/index.tsx
new file mode 100644
index 00000000..17d1965d
--- /dev/null
+++ b/src/stores/onboarding/index.tsx
@@ -0,0 +1,22 @@
+import { create } from "zustand";
+import { persist } from "zustand/middleware";
+import { immer } from "zustand/middleware/immer";
+
+export interface OnboardingStore {
+ skipped: boolean;
+ setSkipped(v: boolean): void;
+}
+
+export const useOnboardingStore = create(
+ persist(
+ immer((set) => ({
+ skipped: false,
+ setSkipped(v) {
+ set((s) => {
+ s.skipped = v;
+ });
+ },
+ })),
+ { name: "__MW::onboarding" },
+ ),
+);
diff --git a/src/utils/onboarding.ts b/src/utils/onboarding.ts
new file mode 100644
index 00000000..7289fd1c
--- /dev/null
+++ b/src/utils/onboarding.ts
@@ -0,0 +1,23 @@
+import { isExtensionActive } from "@/backend/extension/messaging";
+import { conf } from "@/setup/config";
+import { useAuthStore } from "@/stores/auth";
+import { useOnboardingStore } from "@/stores/onboarding";
+
+export async function needsOnboarding(): Promise {
+ // if onboarding is dislabed, no onboarding needed
+ if (!conf().HAS_ONBOARDING) return false;
+
+ // if extension is active and working, no onboarding needed
+ const extensionActive = await isExtensionActive();
+ if (extensionActive) return false;
+
+ // if there is any custom proxy urls, no onboarding needed
+ const proxyUrls = useAuthStore.getState().proxySet;
+ if (proxyUrls) return false;
+
+ // if onboarding has been skipped, no onboarding needed
+ const skipped = useOnboardingStore.getState().skipped;
+ if (skipped) return false;
+
+ return true;
+}
From a226f3347cb77affffca21dd00fb512f7bc0388b Mon Sep 17 00:00:00 2001
From: mrjvs
Date: Tue, 16 Jan 2024 22:07:21 +0100
Subject: [PATCH 031/151] Add onboarding functionality
---
src/pages/onboarding/Onboarding.tsx | 4 +-
src/pages/onboarding/OnboardingExtension.tsx | 55 +++++++++++++++++++-
src/pages/onboarding/OnboardingProxy.tsx | 27 ++++++++--
src/pages/onboarding/onboardingHooks.ts | 10 ++--
src/stores/onboarding/index.tsx | 10 ++--
src/utils/onboarding.ts | 6 +--
6 files changed, 92 insertions(+), 20 deletions(-)
diff --git a/src/pages/onboarding/Onboarding.tsx b/src/pages/onboarding/Onboarding.tsx
index 439cc87d..3247a7ee 100644
--- a/src/pages/onboarding/Onboarding.tsx
+++ b/src/pages/onboarding/Onboarding.tsx
@@ -12,7 +12,7 @@ import { PageTitle } from "@/pages/parts/util/PageTitle";
export function OnboardingPage() {
const navigate = useNavigate();
const skipModal = useModal("skip");
- const { skipAndRedirect } = useRedirectBack();
+ const { completeAndRedirect } = useRedirectBack();
return (
@@ -25,7 +25,7 @@ export function OnboardingPage() {
-