diff --git a/.github/workflows/pull-web.yml b/.github/workflows/pull-web.yml index eda5b384..c9687972 100644 --- a/.github/workflows/pull-web.yml +++ b/.github/workflows/pull-web.yml @@ -1,24 +1,26 @@ name: Check web on: - pull_request: - branches: ["main"] + pull_request: + branches: ["main"] jobs: - web-check: - runs-on: ubuntu-latest - defaults: - run: - working-directory: ./materialious + web-check: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./materialious - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: latest - - name: Install modules - run: npm install - - name: Check linting - run: npm run check - - name: Attempt to build codebase - run: npm run build + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: latest + - name: Install modules + run: npm install + - name: Run svelte checks + run: npm run check + - name: Check linting + run: npm run eslint + - name: Attempt to build codebase + run: npm run build diff --git a/README.md b/README.md index 5c220347..87839ccb 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ - Sync your watch progress between Invidious sessions. - Watch sync parties. - Sponsorblock built-in. -- Return YouTube dislikes built-in. +- [Return YouTube Dislike](https://github.com/Anarios/return-youtube-dislike) (RYD) built-in. - [DeArrow](https://github.com/ajayyy/DeArrow) built-in (With local processing fallback). - No ads. - No tracking. diff --git a/docs/DOCKER.md b/docs/DOCKER.md index abc221d1..28b4f882 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -1,5 +1,14 @@ # Setup -For security reasons regarding CORS, your hosted instance of Materialious must serve as the value for the `Access-Control-Allow-Origin` header on Invidious. + +### CORS +To assure browsers they are allowed to access your Materialious instance +despite their default [same-origin policy][wp-sop], the instance's webserver +needs to send [cross-origin resource sharing (CORS)][wp-cors] headers in its +response to the browser's `OPTIONS` request. The `Access-Control-Allow-Origin` +header of that response must be set to the public origin URI of your instance. + + [wp-sop]: https://en.wikipedia.org/wiki/Same-origin_policy + [wp-cors]: https://en.wikipedia.org/wiki/Cross-origin_resource_sharing Invidious doesn't provide a simple way to modify CORS, so this must be done with your reverse proxy. @@ -169,7 +178,7 @@ services: # URL to your proxied Companion instance VITE_DEFAULT_COMPANION_INSTANCE: "https://companion.materialio.us" - # URL TO RYD + # URL TO RYD (Return YouTube Dislike / https://github.com/Anarios/return-youtube-dislike) # Leave blank to disable completely. VITE_DEFAULT_RETURNYTDISLIKES_INSTANCE: "https://returnyoutubedislikeapi.com" diff --git a/materialious/android/app/build.gradle b/materialious/android/app/build.gradle index 3706b7b2..bb9936a1 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 171 - versionName "1.11.10" + versionCode 172 + versionName "1.12.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/materialious.metainfo.xml b/materialious/electron/materialious.metainfo.xml index 0d79aaa7..c03446d4 100644 --- a/materialious/electron/materialious.metainfo.xml +++ b/materialious/electron/materialious.metainfo.xml @@ -68,7 +68,11 @@ - + + + https://github.com/Materialious/Materialious/releases/tag/1.12.0 + + https://github.com/Materialious/Materialious/releases/tag/1.11.10 diff --git a/materialious/electron/package-lock.json b/materialious/electron/package-lock.json index 375a33a1..b633e070 100644 --- a/materialious/electron/package-lock.json +++ b/materialious/electron/package-lock.json @@ -1,17 +1,17 @@ { "name": "Materialious", - "version": "1.11.9", + "version": "1.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Materialious", - "version": "1.11.9", + "version": "1.12.0", "license": "MIT", "dependencies": { "@capacitor-community/electron": "^5.0.0", "bgutils-js": "^3.2.0", - "chokidar": "~4.0.3", + "chokidar": "~5.0.0", "electron-is-dev": "~2.0.0", "electron-serve": "~3.0.0", "electron-unhandled": "^4.0.1", @@ -21,7 +21,7 @@ "jsonfile": "^6.2.0" }, "devDependencies": { - "electron": "^39.2.3", + "electron": "^39.2.4", "electron-builder": "^26.0.12", "electron-rebuild": "^3.2.9", "typescript": "^5.9.3" @@ -1902,15 +1902,15 @@ } }, "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" @@ -2584,9 +2584,9 @@ } }, "node_modules/electron": { - "version": "39.2.3", - "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.3.tgz", - "integrity": "sha512-j7k7/bj3cNA29ty54FzEMRUoqirE+RBQPhPFP+XDuM93a1l2WcDPiYumxKWz+iKcXxBJLFdMIAlvtLTB/RfCkg==", + "version": "39.2.4", + "resolved": "https://registry.npmjs.org/electron/-/electron-39.2.4.tgz", + "integrity": "sha512-KxPtwpFceQKSxRtUY39piHLYhJMMyHfOhc70e6zRnKGrbRdK6hzEqssth8IGjlKOdkeT4KCvIEngnNraYk39+g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4989,12 +4989,12 @@ } }, "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "license": "MIT", "engines": { - "node": ">= 14.18.0" + "node": ">= 20.19.0" }, "funding": { "type": "individual", diff --git a/materialious/electron/package.json b/materialious/electron/package.json index 82a01dc1..88863bf8 100644 --- a/materialious/electron/package.json +++ b/materialious/electron/package.json @@ -1,6 +1,6 @@ { "name": "Materialious", - "version": "1.11.10", + "version": "1.12.0", "description": "Modern material design for Invidious.", "author": { "name": "Ward Pearce", @@ -24,7 +24,7 @@ "dependencies": { "@capacitor-community/electron": "^5.0.0", "bgutils-js": "^3.2.0", - "chokidar": "~4.0.3", + "chokidar": "~5.0.0", "electron-is-dev": "~2.0.0", "electron-serve": "~3.0.0", "electron-unhandled": "^4.0.1", @@ -34,7 +34,7 @@ "jsonfile": "^6.2.0" }, "devDependencies": { - "electron": "^39.2.3", + "electron": "^39.2.4", "electron-builder": "^26.0.12", "electron-rebuild": "^3.2.9", "typescript": "^5.9.3" diff --git a/materialious/eslint.config.js b/materialious/eslint.config.js index 51e84bb1..72ad1f90 100644 --- a/materialious/eslint.config.js +++ b/materialious/eslint.config.js @@ -57,7 +57,7 @@ export default ts.config( '.DS_Store', 'node_modules', '/build', - '/.svelte-kit', + '**/.svelte-kit/*', '/package', '.env', '.env.*', @@ -65,7 +65,14 @@ export default ts.config( // Ignore files for PNPM, NPM and YARN 'pnpm-lock.yaml', 'package-lock.json', - 'yarn.lock' + 'yarn.lock', + // Ignore our nodejs android code + '**/nodejs-android/*', + // Ignore electron code from capacitorjs + '**/electron/*', + // Ignore build files + '**/build/*', + '**/android/app/src/main/assets/*' ] } ); diff --git a/materialious/package-lock.json b/materialious/package-lock.json index f9746cad..578b800b 100644 --- a/materialious/package-lock.json +++ b/materialious/package-lock.json @@ -1,12 +1,12 @@ { "name": "materialious", - "version": "1.11.9", + "version": "1.12.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "materialious", - "version": "1.11.9", + "version": "1.12.0", "hasInstallScript": true, "dependencies": { "@capacitor-community/electron": "^5.0.1", @@ -15,7 +15,7 @@ "@capacitor/app": "^7.1.0", "@capacitor/browser": "^7.0.0", "@capacitor/clipboard": "^7.0.0", - "@capacitor/core": "^7.4.3", + "@capacitor/core": "^7.4.4", "@capacitor/preferences": "^7.0.2", "@capacitor/screen-orientation": "^7.0.0", "@capacitor/share": "^7.0.2", @@ -28,7 +28,7 @@ "fuse.js": "^7.0.0", "googlevideo": "^4.0.4", "he": "^1.2.0", - "human-number": "^2.0.7", + "human-number": "^2.0.8", "i18next": "^25.6.3", "iso-3166": "^4.4.0", "iso-639-1": "^3.1.5", @@ -36,7 +36,7 @@ "media-captions": "^1.0.4", "mousetrap": "^1.6.5", "peerjs": "^1.5.5", - "shaka-player": "^4.16.9", + "shaka-player": "^4.16.11", "sponsorblock-api": "^0.2.4", "svelte-infinite-loading": "^1.4.0", "youtubei.js": "^16.0.1" @@ -59,12 +59,12 @@ "patch-package": "^8.0.1", "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", - "svelte": "^5.43.5", + "svelte": "^5.45.2", "svelte-check": "^4.3.3", "tslib": "^2.7.0", "typescript": "^5.9.3", "typescript-eslint": "^8.47.0", - "vite": "^7.2.4" + "vite": "^7.2.6" } }, "node_modules/@babel/code-frame": { @@ -2067,9 +2067,9 @@ } }, "node_modules/@capacitor/core": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.4.3.tgz", - "integrity": "sha512-wCWr8fQ9Wxn0466vPg7nMn0tivbNVjNy1yL4GvDSIZuZx7UpU2HeVGNe9QjN/quEd+YLRFeKEBLBw619VqUiNg==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-7.4.4.tgz", + "integrity": "sha512-xzjxpr+d2zwTpCaN0k+C6wKSZzWFAb9OVEUtmO72ihjr/NEDoLvsGl4WLfjWPcCO2zOy0b2X52tfRWjECFUjtw==", "license": "MIT", "dependencies": { "tslib": "^2.1.0" @@ -5664,10 +5664,9 @@ } }, "node_modules/devalue": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz", - "integrity": "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==", - "dev": true, + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.5.0.tgz", + "integrity": "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w==", "license": "MIT" }, "node_modules/dezalgo": { @@ -6281,9 +6280,9 @@ } }, "node_modules/esrap": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.1.2.tgz", - "integrity": "sha512-DgvlIQeowRNyvLPWW4PT7Gu13WznY288Du086E751mwwbsgr29ytBiYeLzAGIo0qk3Ujob0SDk8TiSaM5WQzNg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.0.tgz", + "integrity": "sha512-WBmtxe7R9C5mvL4n2le8nMUe4mD5V9oiK2vJpQ9I3y20ENPUomPcphBXE8D1x/Bm84oN1V+lOfgXxtqmxTp3Xg==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -7331,9 +7330,9 @@ } }, "node_modules/human-number": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/human-number/-/human-number-2.0.7.tgz", - "integrity": "sha512-oRlIx8WSLqpGutVzCq72WipnfH1+OaSoxiPc5l2eMxjqgGow3K4jzCxAHkS93nPxFDa0vXUKaDrmdIAKLwBlHQ==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/human-number/-/human-number-2.0.8.tgz", + "integrity": "sha512-0OikVKOKQR86Plj4Oyszl4TNYu4a9dsKeZKaZw6uHw+7zCDXZ3E3ldG/3ZRddwRajYljdZsMKFcvrNNXHR6wVg==", "license": "MIT", "dependencies": { "round-to": "~5.0.0" @@ -10997,9 +10996,9 @@ } }, "node_modules/shaka-player": { - "version": "4.16.10", - "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-4.16.10.tgz", - "integrity": "sha512-FJJk3rbV6IQ/gmdB6EZ4q4VuCKXdWG1pf7dPuqfZi6lNWIvymT4YWE+Hv5qkBwJRtT0L/8p/EFJKMhwE4AMTMQ==", + "version": "4.16.11", + "resolved": "https://registry.npmjs.org/shaka-player/-/shaka-player-4.16.11.tgz", + "integrity": "sha512-e87a3KtI69duaAm1omY2HwN9hq72ZN0j6mc4aBQgTrfJIBG8hZAw34tEPo6oqGR3IBpK86ASTmtrdUXCzt6yjg==", "license": "Apache-2.0", "engines": { "node": ">=18" @@ -11692,9 +11691,9 @@ } }, "node_modules/svelte": { - "version": "5.43.5", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.43.5.tgz", - "integrity": "sha512-HQoZArIewxQVNedseDsgMgnRSC4XOXczxXLF9rOJaPIJkg58INOPUiL8aEtzqZIXNSZJyw8NmqObwg/voajiHQ==", + "version": "5.45.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.45.2.tgz", + "integrity": "sha512-yyXdW2u3H0H/zxxWoGwJoQlRgaSJLp+Vhktv12iRw2WRDlKqUPT54Fi0K/PkXqrdkcQ98aBazpy0AH4BCBVfoA==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.4", @@ -11705,8 +11704,9 @@ "aria-query": "^5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", + "devalue": "^5.5.0", "esm-env": "^1.2.1", - "esrap": "^2.1.0", + "esrap": "^2.2.0", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", @@ -12500,9 +12500,9 @@ } }, "node_modules/vite": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", - "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz", + "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/materialious/package.json b/materialious/package.json index d9a7c54e..725be7eb 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -1,6 +1,6 @@ { "name": "materialious", - "version": "1.11.10", + "version": "1.12.0", "private": true, "scripts": { "dev": "vite dev", @@ -32,12 +32,12 @@ "patch-package": "^8.0.1", "prettier": "^3.6.2", "prettier-plugin-svelte": "^3.4.0", - "svelte": "^5.43.5", + "svelte": "^5.45.2", "svelte-check": "^4.3.3", "tslib": "^2.7.0", "typescript": "^5.9.3", "typescript-eslint": "^8.47.0", - "vite": "^7.2.4" + "vite": "^7.2.6" }, "type": "module", "dependencies": { @@ -47,7 +47,7 @@ "@capacitor/app": "^7.1.0", "@capacitor/browser": "^7.0.0", "@capacitor/clipboard": "^7.0.0", - "@capacitor/core": "^7.4.3", + "@capacitor/core": "^7.4.4", "@capacitor/preferences": "^7.0.2", "@capacitor/screen-orientation": "^7.0.0", "@capacitor/share": "^7.0.2", @@ -60,7 +60,7 @@ "fuse.js": "^7.0.0", "googlevideo": "^4.0.4", "he": "^1.2.0", - "human-number": "^2.0.7", + "human-number": "^2.0.8", "i18next": "^25.6.3", "iso-3166": "^4.4.0", "iso-639-1": "^3.1.5", @@ -68,7 +68,7 @@ "media-captions": "^1.0.4", "mousetrap": "^1.6.5", "peerjs": "^1.5.5", - "shaka-player": "^4.16.9", + "shaka-player": "^4.16.11", "sponsorblock-api": "^0.2.4", "svelte-infinite-loading": "^1.4.0", "youtubei.js": "^16.0.1" diff --git a/materialious/src/lib/android/http/androidRequests.ts b/materialious/src/lib/android/http/androidRequests.ts index d2ef206b..aed4e375 100644 --- a/materialious/src/lib/android/http/androidRequests.ts +++ b/materialious/src/lib/android/http/androidRequests.ts @@ -47,7 +47,7 @@ if (Capacitor.getPlatform() === 'android') { if (needsProxying(args[1])) { args[1] = corsProxyUrl + args[1]; } - /* @ts-ignore */ + // @ts-expect-error args have any type return originalXhrOpen.apply(this, args); }; } diff --git a/materialious/src/lib/api/index.ts b/materialious/src/lib/api/index.ts index ba55ed85..b6d067c1 100644 --- a/materialious/src/lib/api/index.ts +++ b/materialious/src/lib/api/index.ts @@ -52,7 +52,9 @@ export async function fetchErrorHandle(response: Response): Promise { try { const json = await response.json(); message = 'errorBacktrace' in json ? json.errorBacktrace : json.error; - } catch {} + } catch { + // Continue regardless of error + } throw Error(message); } diff --git a/materialious/src/lib/api/model.ts b/materialious/src/lib/api/model.ts index 3c4dbbcf..9e372e0e 100644 --- a/materialious/src/lib/api/model.ts +++ b/materialious/src/lib/api/model.ts @@ -248,7 +248,7 @@ export interface HashTag { videoCount: number; } -export interface Notification extends VideoBase {} +export type Notification = VideoBase; export interface Feed { notifications: Notification[]; diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index 09bc217d..40d0d20a 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -63,6 +63,7 @@ let snackBarAlert = $state(''); let originalOrigination: ScreenOrientationResult | undefined; + // eslint-disable-next-line no-undef let watchProgressTimeout: NodeJS.Timeout; let showVideoRetry = $state(false); @@ -303,7 +304,9 @@ try { document.getElementsByClassName('shaka-ad-info')[0].remove(); - } catch {} + } catch { + // Continue regardless of error + } if (!data.video.liveNow) { if (watchProgressTimeout) { @@ -525,7 +528,7 @@ console.error('Player error:', error); }); - player.getNetworkingEngine()?.registerResponseFilter((type, response, _) => { + player.getNetworkingEngine()?.registerResponseFilter((type, response) => { if ( type !== shaka.net.NetworkingEngine.RequestType.SEGMENT || !response.uri.includes('/api/timedtext') @@ -746,12 +749,16 @@ if (playerPos && Number(playerPos) > toSetTime) { toSetTime = Number(playerPos); } - } catch {} + } catch { + // Continue regardless of error + } if ($synciousStore && $synciousInstanceStore && $authStore) { try { toSetTime = (await getVideoProgress(data.video.videoId))[0].time; - } catch {} + } catch { + // Continue regardless of error + } } return toSetTime; @@ -769,7 +776,9 @@ ) { try { localStorage.setItem(`v_${data.video.videoId}`, playerElement.currentTime.toString()); - } catch {} + } catch { + // Continue regardless of error + } if (synciousEnabled) { saveVideoProgress(data.video.videoId, playerElement.currentTime); @@ -777,7 +786,9 @@ } else { try { localStorage.removeItem(`v_${data.video.videoId}`); - } catch {} + } catch { + // Continue regardless of error + } if (synciousEnabled) { deleteVideoProgress(data.video.videoId); @@ -799,7 +810,9 @@ try { savePlayerPos(); - } catch (error) {} + } catch { + // Continue regardless of error + } Mousetrap.unbind(['left', 'right', 'space', 'c', 'f', 'shift+left', 'shift+right']); diff --git a/materialious/src/lib/components/Search.svelte b/materialious/src/lib/components/Search.svelte index 69ea7af0..bf97e207 100644 --- a/materialious/src/lib/components/Search.svelte +++ b/materialious/src/lib/components/Search.svelte @@ -24,6 +24,7 @@ let showSearchBox = $state(false); + // eslint-disable-next-line no-undef let debounceTimer: NodeJS.Timeout; function debouncedSearch(event: any) { if (!searchSuggestions) return; diff --git a/materialious/src/lib/components/SyncParty.svelte b/materialious/src/lib/components/SyncParty.svelte index ebd41295..b7e6848f 100644 --- a/materialious/src/lib/components/SyncParty.svelte +++ b/materialious/src/lib/components/SyncParty.svelte @@ -22,12 +22,14 @@ events.events.forEach((event) => { if (event.type === 'change-video' && event.videoId) { currentUrl.pathname = resolve(`/watch/[videoId]`, { videoId: event.videoId }); + // eslint-disable-next-line svelte/no-navigation-without-resolve goto(currentUrl); } else if (event.type === 'goto' && event.path && event.path !== $page.url.pathname) { if (blockedPages.includes(event.path.replace('/', ''))) { ui('#sync-party-private-page'); } else { currentUrl.pathname = event.path; + // eslint-disable-next-line svelte/no-navigation-without-resolve goto(currentUrl); } } diff --git a/materialious/src/lib/components/Thumbnail.svelte b/materialious/src/lib/components/Thumbnail.svelte index c7f5ba2c..6753e44c 100644 --- a/materialious/src/lib/components/Thumbnail.svelte +++ b/materialious/src/lib/components/Thumbnail.svelte @@ -96,7 +96,9 @@ break; } } - } catch {} + } catch { + // Continue regardless of error + } } const img = await insecureRequestImageHandler(imageSrc); @@ -107,7 +109,9 @@ if (get(synciousStore) && get(synciousInstanceStore) && get(authStore)) { try { progress = (await queueSyncious(video.videoId))?.time?.toString() ?? undefined; - } catch {} + } catch { + // Continue regardless of error + } } }); @@ -156,6 +160,7 @@
+ (); for (const cue of transcript.cues) { const roundedTime = Math.ceil(cue.startTime); @@ -98,7 +101,7 @@
@@ -131,7 +134,7 @@ {:else if transcript} {#if transcript.cues.length > 0} {#if transcriptCues.length > 0} - {#each transcriptCues as cue} + {#each transcriptCues as cue (cue)}
{$_('contributors')}
- {#each ghContributors as contributor} + {#each ghContributors as contributor (contributor)} {#if contributor.type === 'User'}
diff --git a/materialious/src/lib/components/settings/Player.svelte b/materialious/src/lib/components/settings/Player.svelte index 467c1707..20676192 100644 --- a/materialious/src/lib/components/settings/Player.svelte +++ b/materialious/src/lib/components/settings/Player.svelte @@ -73,7 +73,7 @@ onchange={() => playerDefaultLanguage.set(defaultLanguage)} > - {#each languageNames as language} + {#each languageNames as language (language)} @@ -113,7 +113,7 @@ bind:value={$playerDefaultPlaybackSpeed} onchange={onSpeedChange} > - {#each playbackRates as speed} + {#each playbackRates as speed (speed)} {/each} @@ -304,7 +304,7 @@ playerStatisticsByDefault.set(!playerStatisticsByDefault)} + onclick={() => playerStatisticsByDefault.set(!$playerStatisticsByDefault)} role="switch" /> diff --git a/materialious/src/lib/components/settings/Settings.svelte b/materialious/src/lib/components/settings/Settings.svelte index 9ae42643..8811cb30 100644 --- a/materialious/src/lib/components/settings/Settings.svelte +++ b/materialious/src/lib/components/settings/Settings.svelte @@ -128,6 +128,7 @@ {/each} {#if !$isAndroidTvStore} + diff --git a/materialious/src/lib/components/watch/Comment.svelte b/materialious/src/lib/components/watch/Comment.svelte index 825d7bb8..d0745475 100644 --- a/materialious/src/lib/components/watch/Comment.svelte +++ b/materialious/src/lib/components/watch/Comment.svelte @@ -29,7 +29,9 @@ sort_by: 'top', source: 'youtube' }); - } catch {} + } catch { + // Continue regardless of error + } } function commentTimestamps(html: string): string { @@ -71,7 +73,9 @@ {comment.publishedText}

+ {@html commentTimestamps(comment.contentHtml)} +

thumb_up {numberWithCommas(comment.likeCount)}

@@ -95,7 +99,7 @@ {/if} {#if replies} - {#each replies.comments as reply} + {#each replies.comments as reply (reply)} {/each} {/if} diff --git a/materialious/src/lib/components/watch/Description.svelte b/materialious/src/lib/components/watch/Description.svelte index 7fc490c3..5dbe0f0e 100644 --- a/materialious/src/lib/components/watch/Description.svelte +++ b/materialious/src/lib/components/watch/Description.svelte @@ -28,7 +28,9 @@
+ {@html description} +
{#if video.keywords && video.keywords.length > 0} diff --git a/materialious/src/lib/css/global.css b/materialious/src/lib/css/global.css index 88e959ac..c6db56f2 100644 --- a/materialious/src/lib/css/global.css +++ b/materialious/src/lib/css/global.css @@ -71,6 +71,11 @@ dialog { justify-content: center; } +menu { + left: auto; + right: 0; +} + @media screen and (max-width: 1000px) { menu.mobile { position: fixed !important; diff --git a/materialious/src/lib/externalSettings.ts b/materialious/src/lib/externalSettings.ts index f96d310e..a956ee93 100644 --- a/materialious/src/lib/externalSettings.ts +++ b/materialious/src/lib/externalSettings.ts @@ -237,7 +237,9 @@ function setStores(toSet: Record) { let userOverwritten: boolean = false; try { userOverwritten = localStorage.getItem(store.name) !== null; - } catch {} + } catch { + // Continue regardless of error + } const paramValue = toSet[store.name]; if (typeof paramValue !== 'undefined' && !userOverwritten) { @@ -284,7 +286,7 @@ export function bookmarkletSaveToUrl(): string { const url = new URL(location.origin); persistedStores.forEach((store) => { - let value = get(store.store); + const value = get(store.store); if (value !== null && value !== undefined) { url.searchParams.set(store.name, value.toString()); } diff --git a/materialious/src/lib/i18n/index.ts b/materialious/src/lib/i18n/index.ts index b03c0e4f..91eb65e0 100644 --- a/materialious/src/lib/i18n/index.ts +++ b/materialious/src/lib/i18n/index.ts @@ -46,7 +46,9 @@ async function loadDayjsLocale(localeName: string) { try { const { default: locale } = await import(`dayjs/locale/${localeName}`); dayjs.locale(locale); - } catch {} + } catch { + // Continue regardless of error + } } export async function initI18n(selectedLocale: string = getUserLocale()): Promise { diff --git a/materialious/src/lib/i18n/locales/de.json b/materialious/src/lib/i18n/locales/de.json index cddd42ee..5214269b 100644 --- a/materialious/src/lib/i18n/locales/de.json +++ b/materialious/src/lib/i18n/locales/de.json @@ -77,7 +77,8 @@ "materialiousLink": "Materialious-Link kopieren", "invidiousRedirect": "Invidious-Weiterleitungslink kopieren", "youtubeLink": "YouTube-Link kopieren", - "includeTimestamp": "Mit Zeitstempel" + "includeTimestamp": "Mit Zeitstempel", + "copiedSuccess": "In Zwischenablage kopiert" }, "download": "Herunterladen", "downloadSteps": { @@ -178,7 +179,8 @@ "companionUrl": "Companion URL", "expandChapters": "Kapitel standardmäßig ausklappen", "displayThumbnailAvatars": "Vorschaubild-Avatare (Langsam)", - "about": "Über" + "about": "Über", + "androidNativeShare": "Natives Teilen nutzen" }, "subscribe": "Abonnieren", "recommendedVideos": "Vorgeschlagene Videos", @@ -200,5 +202,8 @@ "duration": "Dauer", "sortBy": "Sortieren nach", "features": "Eigenschaften" - } + }, + "newest": "Neuste", + "oldest": "Älteste", + "popular": "Populär" } diff --git a/materialious/src/lib/i18n/locales/gsw.json b/materialious/src/lib/i18n/locales/gsw.json index 15f512a8..3f3da4a9 100644 --- a/materialious/src/lib/i18n/locales/gsw.json +++ b/materialious/src/lib/i18n/locales/gsw.json @@ -87,7 +87,8 @@ "displayThumbnailAvatars": "Vorschaubild-Avatar (Langsam)", "expandDescription": "Beschriibig standardmässig erwiitere", "disableAutoUpdate": "Automatischi Updates deaktiviere", - "about": "Über" + "about": "Über", + "androidNativeShare": "Nativs Teile bruche" }, "videos": "Videos", "cancel": "Abbreche", @@ -160,7 +161,8 @@ "materialiousLink": "Materialious-Link kopiere", "youtubeLink": "YouTube-Link kopiere", "invidiousRedirect": "Invidious-Wiiterleitigslink kopiere", - "includeTimestamp": "Mit Ziitstempel" + "includeTimestamp": "Mit Ziitstempel", + "copiedSuccess": "I d Zwüscheablaag kopiert" }, "download": "Abelade", "downloadSteps": { @@ -200,5 +202,8 @@ "duration": "Duur", "sortBy": "Sortiere nach", "features": "Eigeschafte" - } + }, + "newest": "Neusti", + "oldest": "Ältisti", + "popular": "Populär" } diff --git a/materialious/src/lib/i18n/locales/hu.json b/materialious/src/lib/i18n/locales/hu.json index 84274c18..f81f56da 100644 --- a/materialious/src/lib/i18n/locales/hu.json +++ b/materialious/src/lib/i18n/locales/hu.json @@ -108,7 +108,8 @@ }, "logout": "Kijelentkezés", "companionUrl": "Kiegészítő webcím", - "about": "Névjegy" + "about": "Névjegy", + "androidNativeShare": "Natív megosztás használata" }, "enabled": "Engedélyezve", "donate": "Adományozás", @@ -122,7 +123,8 @@ "title": "Megosztás", "materialiousLink": "Materialious-hivatkozás megosztása", "youtubeLink": "Youtube-hivatkozás másolása", - "invidiousRedirect": "Invidious átirányítási hivatkozás másolása" + "invidiousRedirect": "Invidious átirányítási hivatkozás másolása", + "copiedSuccess": "Vágólapra másolva" }, "audioOnly": "Csak hang", "theatreMode": "Szélesvásznú mód", diff --git a/materialious/src/lib/i18n/locales/lv.json b/materialious/src/lib/i18n/locales/lv.json index 573c4a62..2dbf7b00 100644 --- a/materialious/src/lib/i18n/locales/lv.json +++ b/materialious/src/lib/i18n/locales/lv.json @@ -44,8 +44,8 @@ "theme": { "theme": "Motīvs", "color": "Krāsa", - "darkMode": "Tumšais režīms", - "lightMode": "Gaišais režīms", + "darkMode": "Tumšais motīvs", + "lightMode": "Gaišais motīvs", "AmoledTheme": "AMOLED motīvs" }, "player": { @@ -55,7 +55,10 @@ "youtubeJsAlways": "Vienmēr izmantot", "localVideoFallback": "Vietējais video ieguves rezerves variants", "youtubeJsFallback": "Vietējais video apstrādes rezerves variants", - "alwaysLoopVideo": "Vienmēr atskaņot (malt) uz riņķi video" + "alwaysLoopVideo": "Vienmēr atskaņot (malt) uz riņķi video", + "miniPlayer": "Mini atskaņotājs", + "playerStatistics": "Rādīt atskaņotāja statistiku pēc noklusējuma", + "autoPlayNextByDefault": "Automātiski atskaņot nākamo video pēc noklusējuma" }, "deArrow": { "titleOnly": "Tikai virsrakstu", diff --git a/materialious/src/lib/images.ts b/materialious/src/lib/images.ts index fbdb92a4..120ea792 100644 --- a/materialious/src/lib/images.ts +++ b/materialious/src/lib/images.ts @@ -1,41 +1,42 @@ -import { get } from "svelte/store"; -import type { Image } from "./api/model"; -import { instanceStore } from "./store"; +import { get } from 'svelte/store'; +import type { Image } from './api/model'; +import { instanceStore } from './store'; export function getBestThumbnail( - images: Image[] | null, - maxWidthDimension: number = 480, - maxHeightDimension = 360 + images: Image[] | null, + maxWidthDimension: number = 480, + maxHeightDimension = 360 ): string { - if (images && images.length > 0) { - const imagesFiltered = images.filter( - (image) => image.width < maxWidthDimension && image.height < maxHeightDimension - ); + if (images && images.length > 0) { + const imagesFiltered = images.filter( + (image) => image.width < maxWidthDimension && image.height < maxHeightDimension + ); - if (imagesFiltered.length === 0) { - return images[0].url; - } + if (imagesFiltered.length === 0) { + return images[0].url; + } - imagesFiltered.sort((a, b) => { - return b.width * b.height - a.width * a.height; - }); + imagesFiltered.sort((a, b) => { + return b.width * b.height - a.width * a.height; + }); - return imagesFiltered[0].url; - } else { - return ''; - } + return imagesFiltered[0].url; + } else { + return ''; + } } - export function proxyGoogleImage(source: string): string { - if (source.startsWith('//')) source = `https:${source}`; + if (source.startsWith('//')) source = `https:${source}`; - let path: string | undefined; - try { - path = new URL(source).pathname; - } catch { } + let path: string | undefined; + try { + path = new URL(source).pathname; + } catch { + // Continue regardless of error + } - if (typeof path === 'undefined') return ''; + if (typeof path === 'undefined') return ''; - return `${get(instanceStore)}/ggpht${path}`; -} \ No newline at end of file + return `${get(instanceStore)}/ggpht${path}`; +} diff --git a/materialious/src/lib/letterCasing.ts b/materialious/src/lib/letterCasing.ts index 9c1c97ab..3091fbbf 100644 --- a/materialious/src/lib/letterCasing.ts +++ b/materialious/src/lib/letterCasing.ts @@ -1,61 +1,55 @@ -import { get } from "svelte/store"; -import { interfaceForceCase } from "./store"; +import { get } from 'svelte/store'; +import { interfaceForceCase } from './store'; export type TitleCase = 'uppercase' | 'lowercase' | 'sentence case' | 'title case' | null; -export const titleCases: TitleCase[] = [ - 'lowercase', - 'uppercase', - 'title case', - 'sentence case' -]; +export const titleCases: TitleCase[] = ['lowercase', 'uppercase', 'title case', 'sentence case']; export function letterCase(text: string, caseTypeOverwrite?: TitleCase): string { - const casing = caseTypeOverwrite ? caseTypeOverwrite : get(interfaceForceCase); - if (!casing) return text; + const casing = caseTypeOverwrite ? caseTypeOverwrite : get(interfaceForceCase); + if (!casing) return text; - switch (casing) { - case 'lowercase': - return text.toLowerCase(); - case 'uppercase': - return text.toUpperCase(); - case 'sentence case': - return sentenceCase(text); - default: - return titleCase(text); - } + switch (casing) { + case 'lowercase': + return text.toLowerCase(); + case 'uppercase': + return text.toUpperCase(); + case 'sentence case': + return sentenceCase(text); + default: + return titleCase(text); + } } export function sentenceCase(text: string): string { - let sentences: string[] = text.match(/[^.!?]*[.!?]*/g) || []; + const sentences: string[] = text.match(/[^.!?]*[.!?]*/g) || []; - let casedSentences: string[] = sentences.map(sentence => { - sentence = sentence.trim(); - if (sentence.length === 0) return ''; - return sentence.charAt(0).toUpperCase() + sentence.slice(1).toLowerCase(); - }); + const casedSentences: string[] = sentences.map((sentence) => { + sentence = sentence.trim(); + if (sentence.length === 0) return ''; + return sentence.charAt(0).toUpperCase() + sentence.slice(1).toLowerCase(); + }); - return casedSentences.join(' '); + return casedSentences.join(' '); } export function titleCase(text: string): string { - if (!text) return ''; + if (!text) return ''; - let words: string[] = text.split(/(\s+)/).filter(word => word.trim().length > 0); + const words: string[] = text.split(/(\s+)/).filter((word) => word.trim().length > 0); - let titleCasedWords: string[] = words.map(word => { - if (word.length === 0) return ''; + const titleCasedWords: string[] = words.map((word) => { + if (word.length === 0) return ''; - const firstChar = word.charAt(0); - const restOfWord = word.slice(1).toLowerCase(); + const firstChar = word.charAt(0); + const restOfWord = word.slice(1).toLowerCase(); - // Capitalize if the first character is a letter - if (/[a-zA-Z]/.test(firstChar)) { - return firstChar.toUpperCase() + restOfWord; - } + // Capitalize if the first character is a letter + if (/[a-zA-Z]/.test(firstChar)) { + return firstChar.toUpperCase() + restOfWord; + } - return word; - }); + return word; + }); - return titleCasedWords.join(' '); + return titleCasedWords.join(' '); } - diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index 34ce933d..c2239271 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -1,10 +1,9 @@ import { pushState } from '$app/navigation'; import { resolve } from '$app/paths'; -import { page } from '$app/stores'; import he from 'he'; import type Peer from 'peerjs'; import { get } from 'svelte/store'; -import { instanceStore, interfaceAllowInsecureRequests, isAndroidTvStore } from './store'; +import { interfaceAllowInsecureRequests, isAndroidTvStore } from './store'; import type { Channel, HashTag, @@ -14,9 +13,10 @@ import type { Video, VideoBase } from './api/model'; +import { page } from '$app/state'; export function isVideoID(videoId: string): boolean { - var regExp = /^[a-zA-Z0-9_-]{11}$/; + const regExp = /^[a-zA-Z0-9_-]{11}$/; return regExp.test(videoId); } @@ -34,15 +34,15 @@ export function unsafeRandomItem(array: any[]): any { } export function setWindowQueryFlag(key: string, value: string) { - const currentPage = get(page); - currentPage.url.searchParams.set(key, value); - pushState(currentPage.url, currentPage.state); + page.url.searchParams.set(key, value); + // eslint-disable-next-line svelte/no-navigation-without-resolve + pushState(page.url, page.state); } export function removeWindowQueryFlag(key: string) { - const currentPage = get(page); - currentPage.url.searchParams.delete(key); - pushState(currentPage.url, currentPage.state); + page.url.searchParams.delete(key); + // eslint-disable-next-line svelte/no-navigation-without-resolve + pushState(page.url, page.state); } let PeerInstance: typeof Peer; diff --git a/materialious/src/lib/patches/youtubejs.ts b/materialious/src/lib/patches/youtubejs.ts index c0351ef5..7cdc50f3 100644 --- a/materialious/src/lib/patches/youtubejs.ts +++ b/materialious/src/lib/patches/youtubejs.ts @@ -12,7 +12,7 @@ import { interfaceRegionStore, poTokenCacheStore } from '$lib/store'; import { Capacitor } from '@capacitor/core'; import { USER_AGENT } from 'bgutils-js'; import { get } from 'svelte/store'; -import type { Types, Misc } from 'youtubei.js'; +import type { Types } from 'youtubei.js'; import { Innertube, UniversalCache, Utils, YT, YTNodes, Platform } from 'youtubei.js'; Platform.shim.eval = async ( diff --git a/materialious/src/lib/theme.ts b/materialious/src/lib/theme.ts index 082e01bd..6fce9a29 100644 --- a/materialious/src/lib/theme.ts +++ b/materialious/src/lib/theme.ts @@ -8,7 +8,7 @@ import { darkModeStore, interfaceAmoledTheme } from './store'; export async function getDynamicTheme(mode?: string): Promise> { const givenSettings = await ui('theme'); - // @ts-ignore + // @ts-expect-error Works as expected const themes: string = givenSettings[mode ? mode : (ui('mode') as string)]; const themeVars: Record = {}; themes.split(';').forEach((keyVar) => { diff --git a/materialious/src/lib/watch.ts b/materialious/src/lib/watch.ts index f79562b3..5a8195d0 100644 --- a/materialious/src/lib/watch.ts +++ b/materialious/src/lib/watch.ts @@ -62,7 +62,9 @@ export async function getWatchDetails(videoId: string, url: URL) { returnYTDislikes = get(returnYtDislikesStore) ? getDislikes(videoId, { priority: 'low' }) : null; - } catch {} + } catch { + // Continue regardless of error + } } const playlistId = url.searchParams.get('playlist'); diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index 0b13229d..0d4a2981 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -119,7 +119,9 @@ async function login() { if (!$isAndroidTvStore) { + // eslint-disable-next-line svelte/prefer-svelte-reactivity const path = new URL(`${get(instanceStore)}/authorize_token`); + // eslint-disable-next-line svelte/prefer-svelte-reactivity const searchParams = new URLSearchParams({ scopes: ':feed,:subscriptions*,:playlists*,:history*,:notifications*' }); @@ -207,7 +209,9 @@ const colorPalette = await colorTheme.getColorPalette(); themeHex = convertToHexColorCode(colorPalette.primary); await ui('theme', themeHex); - } catch {} + } catch { + // Continue regardless of error + } } } @@ -262,6 +266,7 @@ + {@html webManifestLink} {#if Capacitor.getPlatform() === 'android' && !$isAndroidTvStore} @@ -284,7 +289,7 @@ > - {#each getPages() as navPage} + {#each getPages() as navPage (navPage)} {#if !navPage.requiresAuth || isLoggedIn} {navPage.icon} @@ -361,7 +366,7 @@