From e0299c03bdbd8c8bd142b7b99b414b96cfc91815 Mon Sep 17 00:00:00 2001 From: WardPearce Date: Sat, 25 Jan 2025 09:05:53 +1300 Subject: [PATCH] Moved to dependency free nodejs mobile request proxy --- materialious/android/app/build.gradle | 4 +- materialious/electron/package.json | 2 +- materialious/package.json | 4 +- materialious/src/lib/components/Player.svelte | 12 +- materialious/src/lib/patches/youtubejs.ts | 2 +- materialious/static/nodejs-android/index.js | 112 +++++++++++++++++- .../static/nodejs-android/package-lock.json | 44 +------ .../static/nodejs-android/package.json | 7 +- update_versions.py | 2 +- 9 files changed, 125 insertions(+), 64 deletions(-) diff --git a/materialious/android/app/build.gradle b/materialious/android/app/build.gradle index 55e505f3..63e2f67d 100644 --- a/materialious/android/app/build.gradle +++ b/materialious/android/app/build.gradle @@ -7,8 +7,8 @@ android { applicationId "us.materialio.app" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 81 - versionName "1.6.30" + versionCode 82 + versionName "1.7.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/materialious/electron/package.json b/materialious/electron/package.json index 8fee234d..6840beff 100644 --- a/materialious/electron/package.json +++ b/materialious/electron/package.json @@ -1,6 +1,6 @@ { "name": "Materialious", - "version": "1.6.30", + "version": "1.7.0", "description": "Modern material design for Invidious.", "author": { "name": "Ward Pearce", diff --git a/materialious/package.json b/materialious/package.json index 2a57b7b4..582dbe11 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -1,6 +1,6 @@ { "name": "materialious", - "version": "1.6.30", + "version": "1.7.0", "private": true, "scripts": { "dev": "vite dev", @@ -75,4 +75,4 @@ "vidstack": "^1.12.9", "youtubei.js": "^12.2.0" } -} +} \ No newline at end of file diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index 634626eb..cb09dacd 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -2,7 +2,7 @@ import 'vidstack/bundle'; import { page } from '$app/stores'; - import { getBestThumbnail, proxyGoogleImage } from '$lib/images'; + import { getBestThumbnail } from '$lib/images'; import { padTime, videoLength } from '$lib/time'; import { Capacitor } from '@capacitor/core'; import { ScreenOrientation, type ScreenOrientationResult } from '@capacitor/screen-orientation'; @@ -366,7 +366,11 @@ await loadPlayerPos(); }); - if (Capacitor.getPlatform() === 'android' && data.video.adaptiveFormats.length > 0) { + if ( + Capacitor.getPlatform() === 'android' && + data.video.adaptiveFormats.length > 0 && + data.video.fallbackPatch === undefined + ) { if (get(playerAndroidBgPlayer)) { const highestBitrateAudio = data.video.adaptiveFormats .filter((format) => format.type.startsWith('audio/')) @@ -605,9 +609,7 @@ > {#if !audioMode} - {/if} diff --git a/materialious/src/lib/patches/youtubejs.ts b/materialious/src/lib/patches/youtubejs.ts index 89ac4d2a..8bbd08cc 100644 --- a/materialious/src/lib/patches/youtubejs.ts +++ b/materialious/src/lib/patches/youtubejs.ts @@ -16,7 +16,7 @@ async function getPo(identifier: string): Promise { const requestKey = 'O43z0dpjhgX20SCx4KAo'; const bgConfig = { - fetch: fetch, + fetch: Capacitor.getPlatform() === 'android' ? capacitorFetch : fetch, globalObj: window, requestKey, identifier diff --git a/materialious/static/nodejs-android/index.js b/materialious/static/nodejs-android/index.js index db5bc1cc..41465795 100644 --- a/materialious/static/nodejs-android/index.js +++ b/materialious/static/nodejs-android/index.js @@ -1,5 +1,109 @@ -const corsAnywhere = require('cors-anywhere'); +const http = require('http'); +const https = require('https'); -corsAnywhere.createServer({ - originWhitelist: [], -}).listen(3000, 'localhost'); \ No newline at end of file +const HOST = 'localhost'; +const PORT = 3000; +const MAX_REDIRECTS = 5; +const ORIGIN = `https://${HOST}`; + +function setCorsHeaders(res) { + res.setHeader('Access-Control-Allow-Origin', ORIGIN); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', '*'); + res.setHeader('Access-Control-Allow-Credentials', 'true'); +} + +function fetchWithRedirects(targetUrl, options, redirectCount = 0) { + return new Promise((resolve, reject) => { + const httpClient = targetUrl.protocol.startsWith('https') ? https : http; + + const req = httpClient.request(targetUrl, options, (res) => { + if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) { + if (redirectCount >= MAX_REDIRECTS) { + return reject(new Error('Too many redirects')); + } + + let redirectHeaderLocation = res.headers.location; + + // Handle relative URLs + if (redirectHeaderLocation.startsWith('/')) { + redirectHeaderLocation = targetUrl.host + redirectHeaderLocation; + } + + // Add http:// if missing from the Location header + if (!redirectHeaderLocation.startsWith('http')) { + redirectHeaderLocation = 'http://' + redirectHeaderLocation; + } + + try { + // Attempt to create the redirect URL + let redirectUrl = new URL(redirectHeaderLocation); + return resolve(fetchWithRedirects(redirectUrl, options, redirectCount + 1)); + } catch (error) { + // Catch invalid URL errors + return reject(new Error(`Invalid URL in redirect: ${error.message}`)); + } + } + resolve(res); // Resolve with the final response if not a redirect + }); + + req.on('error', reject); + req.end(); + }); +} + + +const server = http.createServer(async (req, res) => { + setCorsHeaders(res); + + if (req.method === 'OPTIONS') { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + return res.end(); + } + + if (!req.url || req.url === '/') { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + return res.end('No URL provided to fetch.'); + } + + const targetUrl = req.url.slice(1); // Remove leading '/' + let parsedTarget; + try { + if (!targetUrl.startsWith('http')) { + targetUrl = 'http://' + targetUrl; + } + parsedTarget = new URL(targetUrl); + } catch (error) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + return res.end(`Invalid URL: ${error.message}`); + } + + const options = { + method: req.method, + headers: { + ...req.headers, + host: parsedTarget.hostname, // Ensure correct host header + }, + }; + + try { + const proxyRes = await fetchWithRedirects(parsedTarget, options); + res.writeHead(proxyRes.statusCode, { + ...proxyRes.headers, + 'Access-Control-Allow-Origin': ORIGIN, + 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', + 'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Credentials': 'true', + }); + + proxyRes.pipe(res); // Pipe response data back to the client + } catch (error) { + console.error('Proxy error:', error); + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end(`Error: ${error.message}`); + } +}); + +server.listen(PORT, () => { + console.log(`Server is running on http://${HOST}:${PORT}`); +}); diff --git a/materialious/static/nodejs-android/package-lock.json b/materialious/static/nodejs-android/package-lock.json index 2ce1406a..140d2606 100644 --- a/materialious/static/nodejs-android/package-lock.json +++ b/materialious/static/nodejs-android/package-lock.json @@ -6,49 +6,7 @@ "packages": { "": { "name": "cors-patch", - "version": "0.0.1", - "dependencies": { - "cors-anywhere": "^0.4.4" - } - }, - "node_modules/cors-anywhere": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cors-anywhere/-/cors-anywhere-0.4.4.tgz", - "integrity": "sha512-8OBFwnzMgR4mNrAeAyOLB2EruS2z7u02of2bOu7i9kKYlZG+niS7CTHLPgEXKWW2NAOJWRry9RRCaL9lJRjNqg==", - "dependencies": { - "http-proxy": "1.11.1", - "proxy-from-env": "0.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha512-DOFqA1MF46fmZl2xtzXR3MPCRsXqgoFqdXcrCVYM3JNnfUeHTm/fh/v/iU7gBFpwkuBmoJPAm5GuhdDfSEJMJA==" - }, - "node_modules/http-proxy": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.11.1.tgz", - "integrity": "sha512-qz7jZarkVG3G6GMq+4VRJPSN4NkIjL4VMTNhKGd8jc25BumeJjWWvnY3A7OkCGa8W1TTxbaK3dcE0ijFalITVA==", - "dependencies": { - "eventemitter3": "1.x.x", - "requires-port": "0.x.x" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/proxy-from-env": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-0.0.1.tgz", - "integrity": "sha512-B9Hnta3CATuMS0q6kt5hEezOPM+V3dgaRewkFtFoaRQYTVNsHqUvFXmndH06z3QO1ZdDnRELv5vfY6zAj/gG7A==" - }, - "node_modules/requires-port": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-0.0.1.tgz", - "integrity": "sha512-AzPDCliPoWDSvEVYRQmpzuPhGGEnPrQz9YiOEvn+UdB9ixBpw+4IOZWtwctmpzySLZTy7ynpn47V14H4yaowtA==" + "version": "0.0.1" } } } diff --git a/materialious/static/nodejs-android/package.json b/materialious/static/nodejs-android/package.json index 7741a1dd..dfd11e64 100644 --- a/materialious/static/nodejs-android/package.json +++ b/materialious/static/nodejs-android/package.json @@ -1,8 +1,5 @@ { "name": "cors-patch", "version": "0.0.1", - "main": "./index.js", - "dependencies": { - "cors-anywhere": "^0.4.4" - } -} \ No newline at end of file + "main": "./index.js" +} diff --git a/update_versions.py b/update_versions.py index 83e6e2a9..a68d8ac8 100644 --- a/update_versions.py +++ b/update_versions.py @@ -5,7 +5,7 @@ import json import os import re -LATEST_VERSION = "1.6.30" +LATEST_VERSION = "1.7.0" WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious") ROOT_PACKAGE = os.path.join(WORKING_DIR, "package.json")