diff --git a/materialious/android/app/build.gradle b/materialious/android/app/build.gradle index d38fd1dc..13c0966c 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 144 - versionName "1.10.3" + versionCode 145 + versionName "1.10.4" 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 143dcf23..4a989ac0 100644 --- a/materialious/electron/materialious.metainfo.xml +++ b/materialious/electron/materialious.metainfo.xml @@ -61,7 +61,11 @@ - + + + https://github.com/Materialious/Materialious/releases/tag/1.10.4 + + https://github.com/Materialious/Materialious/releases/tag/1.10.3 diff --git a/materialious/electron/package-lock.json b/materialious/electron/package-lock.json index b6da36fe..4aa19bba 100644 --- a/materialious/electron/package-lock.json +++ b/materialious/electron/package-lock.json @@ -1,12 +1,12 @@ { "name": "Materialious", - "version": "1.10.3", + "version": "1.10.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "Materialious", - "version": "1.10.3", + "version": "1.10.4", "license": "MIT", "dependencies": { "@capacitor-community/electron": "^5.0.0", @@ -22,7 +22,7 @@ "jsonfile": "^6.1.0" }, "devDependencies": { - "electron": "^37.2.5", + "electron": "^37.2.6", "electron-builder": "^26.0.12", "electron-rebuild": "^3.2.9", "typescript": "^5.9.2" @@ -2492,9 +2492,9 @@ } }, "node_modules/electron": { - "version": "37.2.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-37.2.5.tgz", - "integrity": "sha512-719ZqEp43rj6xDJMICm4CIXl8keFFgvVNO9Ix6OtjNjrh9HtYlP/1WiYeRohnXj06aLyGx5NCzrHbG7j3BxO9w==", + "version": "37.2.6", + "resolved": "https://registry.npmjs.org/electron/-/electron-37.2.6.tgz", + "integrity": "sha512-Ns6xyxE+hIK5UlujtRlw7w4e2Ju/ImCWXf1Q/PoOhc0N3/6SN6YW7+ujCarsHbxWnolbW+1RlkHtdklUJpjbPA==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/materialious/electron/package.json b/materialious/electron/package.json index cec59282..ef0c204f 100644 --- a/materialious/electron/package.json +++ b/materialious/electron/package.json @@ -1,6 +1,6 @@ { "name": "Materialious", - "version": "1.10.3", + "version": "1.10.4", "description": "Modern material design for Invidious.", "author": { "name": "Ward Pearce", @@ -35,7 +35,7 @@ "jsonfile": "^6.1.0" }, "devDependencies": { - "electron": "^37.2.5", + "electron": "^37.2.6", "electron-builder": "^26.0.12", "electron-rebuild": "^3.2.9", "typescript": "^5.9.2" diff --git a/materialious/package-lock.json b/materialious/package-lock.json index a6504995..d45f9e95 100644 --- a/materialious/package-lock.json +++ b/materialious/package-lock.json @@ -30,7 +30,7 @@ "material-dynamic-colors": "^1.1.1", "media-captions": "^1.0.4", "mousetrap": "^1.6.5", - "peerjs": "^1.5.4", + "peerjs": "^1.5.5", "shaka-player": "^4.11.7", "sponsorblock-api": "^0.2.4", "svelte-infinite-loading": "^1.4.0", @@ -57,7 +57,7 @@ "eslint-plugin-svelte": "^3.11.0", "patch-package": "^8.0.0", "prettier": "^3.3.3", - "prettier-plugin-svelte": "^3.2.7", + "prettier-plugin-svelte": "^3.4.0", "svelte": "^5.19.7", "svelte-check": "^4.0.0", "tslib": "^2.7.0", @@ -9620,9 +9620,9 @@ } }, "node_modules/peerjs": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.5.4.tgz", - "integrity": "sha512-yFsoLMnurJKlQbx6kVSBpOp+AlNldY1JQS2BrSsHLKCZnq6t7saHleuHM5svuLNbQkUJXHLF3sKOJB1K0xulOw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.5.5.tgz", + "integrity": "sha512-viMUCPDL6CSfOu0ZqVcFqbWRXNHIbv2lPqNbrBIjbFYrflebOjItJ4hPfhjnuUCstqciHVu9vVJ7jFqqKi/EuQ==", "license": "MIT", "dependencies": { "@msgpack/msgpack": "^2.8.0", @@ -9949,9 +9949,9 @@ } }, "node_modules/prettier-plugin-svelte": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz", - "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.4.0.tgz", + "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "dev": true, "license": "MIT", "peerDependencies": { diff --git a/materialious/package.json b/materialious/package.json index 902ad842..049e3f1f 100644 --- a/materialious/package.json +++ b/materialious/package.json @@ -1,6 +1,6 @@ { "name": "materialious", - "version": "1.10.3", + "version": "1.10.4", "private": true, "scripts": { "dev": "vite dev", @@ -32,7 +32,7 @@ "eslint-plugin-svelte": "^3.11.0", "patch-package": "^8.0.0", "prettier": "^3.3.3", - "prettier-plugin-svelte": "^3.2.7", + "prettier-plugin-svelte": "^3.4.0", "svelte": "^5.19.7", "svelte-check": "^4.0.0", "tslib": "^2.7.0", @@ -62,11 +62,11 @@ "material-dynamic-colors": "^1.1.1", "media-captions": "^1.0.4", "mousetrap": "^1.6.5", - "peerjs": "^1.5.4", + "peerjs": "^1.5.5", "shaka-player": "^4.11.7", "sponsorblock-api": "^0.2.4", "svelte-infinite-loading": "^1.4.0", "svelte-persisted-store": "^0.12.0", "youtubei.js": "^15.0.0" } -} +} \ No newline at end of file diff --git a/materialious/src/lib/android/youtube/dash.ts b/materialious/src/lib/android/youtube/dash.ts new file mode 100644 index 00000000..a17d0d02 --- /dev/null +++ b/materialious/src/lib/android/youtube/dash.ts @@ -0,0 +1,53 @@ +export async function dashManifestDomainInclusion(manifestUrl: string): Promise { + /* If on android, must manually format dash manifest to include URL. */ + + // Must fetch the headers of the request + // using our custom android proxy logic + const respIvg = await fetch(manifestUrl, { + method: 'GET', + headers: { + __custom_return: 'json-headers', + __redirect: 'manual' + } + }); + + if (!respIvg.ok) { + throw Error('Unable to make request to Invidious'); + } + + const ivgHeaders = await respIvg.json(); + // If location isn't present, then use base manifest URL. + const companionUrl = 'location' in ivgHeaders ? ivgHeaders['location'] : manifestUrl; + + const respCompanion = await fetch(companionUrl, { + method: 'GET' + }); + + if (!respCompanion.ok) { + throw Error('Unable to make request to Companion'); + } + + const manifestText = await respCompanion.text(); + + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(manifestText, 'application/xml'); + + const baseUrlElements = xmlDoc.getElementsByTagName('BaseURL'); + + for (let i = 0; i < baseUrlElements.length; i++) { + const baseUrlElement = baseUrlElements[i]; + const baseUrlValue = baseUrlElement.textContent; + + if (baseUrlValue && (baseUrlValue.startsWith('/') || !baseUrlValue.includes('://'))) { + const companionUrlObj = new URL(companionUrl); + const baseDomain = `${companionUrlObj.protocol}//${companionUrlObj.host}`; + const resolvedUrl = new URL(baseUrlValue, baseDomain).href; + baseUrlElement.textContent = resolvedUrl; + } + } + + const serializer = new XMLSerializer(); + const updatedManifest = serializer.serializeToString(xmlDoc); + + return `data:application/dash+xml;base64,${btoa(updatedManifest)}`; +} diff --git a/materialious/src/lib/components/Player.svelte b/materialious/src/lib/components/Player.svelte index 1c3cf068..d5ec5a24 100644 --- a/materialious/src/lib/components/Player.svelte +++ b/materialious/src/lib/components/Player.svelte @@ -49,12 +49,13 @@ import { getDynamicTheme, setStatusBarColor } from '../theme'; import { injectSABR } from '$lib/sabr'; import { patchYoutubeJs } from '$lib/patches/youtubejs'; - import { playbackRates } from '$lib/const'; + import { playbackRates } from '$lib/player'; import { EndTimeElement } from '$lib/shaka-elements/endTime'; import { loadEntirePlaylist } from '$lib/playlist'; import { goto } from '$app/navigation'; import { unsafeRandomItem } from '$lib/misc'; import type { PlayerEvents } from '$lib/player'; + import { dashManifestDomainInclusion } from '$lib/android/youtube/dash'; interface Props { data: { video: VideoPlay; content: PhasedDescription; playlistId: string | null }; @@ -400,7 +401,16 @@ dashUrl += '?local=true'; } - await player.load(dashUrl, await getLastPlayPos()); + if ( + Capacitor.getPlatform() === 'android' && + $playerProxyVideosStore && + !data.video.fallbackPatch + ) { + const manifest = await dashManifestDomainInclusion(dashUrl); + await player.load(manifest, await getLastPlayPos()); + } else { + await player.load(dashUrl, await getLastPlayPos()); + } } else { if (data.video.fallbackPatch === 'youtubejs') { if (!data.video.dashUrl) { diff --git a/materialious/src/lib/components/Settings/Player.svelte b/materialious/src/lib/components/Settings/Player.svelte index 860f95d7..2318d014 100644 --- a/materialious/src/lib/components/Settings/Player.svelte +++ b/materialious/src/lib/components/Settings/Player.svelte @@ -20,7 +20,7 @@ playerYouTubeJsAlways, playerYouTubeJsFallback } from '../../store'; - import { playbackRates } from '$lib/const'; + import { playbackRates } from '$lib/player'; let defaultLanguage = $state(get(playerDefaultLanguage)); @@ -49,9 +49,11 @@ switch (localVideoFallback) { case 'enabled': playerYouTubeJsFallback.set(true); + playerYouTubeJsAlways.set(false); break; case 'disabled': playerYouTubeJsFallback.set(false); + playerYouTubeJsAlways.set(false); break; case 'always': playerYouTubeJsAlways.set(true); diff --git a/materialious/src/lib/const.ts b/materialious/src/lib/const.ts deleted file mode 100644 index 71d1d354..00000000 --- a/materialious/src/lib/const.ts +++ /dev/null @@ -1 +0,0 @@ -export const playbackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3]; diff --git a/materialious/src/lib/css/global.css b/materialious/src/lib/css/global.css index 807c4742..b7e04b12 100644 --- a/materialious/src/lib/css/global.css +++ b/materialious/src/lib/css/global.css @@ -12,7 +12,6 @@ nav.top { padding-top: calc(var(--safe-area-inset-top) + 1rem) !important; - height: 100px; padding-bottom: 1em; } diff --git a/materialious/src/lib/i18n/locales/de.json b/materialious/src/lib/i18n/locales/de.json index 5feaeef2..b1c7440c 100644 --- a/materialious/src/lib/i18n/locales/de.json +++ b/materialious/src/lib/i18n/locales/de.json @@ -74,7 +74,8 @@ "title": "Teilen", "materialiousLink": "Materialious-Link kopieren", "invidiousRedirect": "Invidious-Weiterleitungslink kopieren", - "youtubeLink": "YouTube-Link kopieren" + "youtubeLink": "YouTube-Link kopieren", + "includeTimestamp": "Mit Zeitstempel" }, "download": "Herunterladen", "downloadSteps": { diff --git a/materialious/src/lib/i18n/locales/gsw.json b/materialious/src/lib/i18n/locales/gsw.json index 397b4732..ef22d905 100644 --- a/materialious/src/lib/i18n/locales/gsw.json +++ b/materialious/src/lib/i18n/locales/gsw.json @@ -156,7 +156,8 @@ "title": "Teile", "materialiousLink": "Materialious-Link kopiere", "youtubeLink": "YouTube-Link kopiere", - "invidiousRedirect": "Invidious-Wiiterleitigslink kopiere" + "invidiousRedirect": "Invidious-Wiiterleitigslink kopiere", + "includeTimestamp": "Mit Ziitstempel" }, "download": "Abelade", "downloadSteps": { diff --git a/materialious/src/lib/player.ts b/materialious/src/lib/player.ts index b2a8cd84..cbb32cbc 100644 --- a/materialious/src/lib/player.ts +++ b/materialious/src/lib/player.ts @@ -1,6 +1,6 @@ export interface PlayerEvent { type: 'pause' | 'seek' | 'change-video' | 'play' | 'playlist' | 'goto'; - path?: string, + path?: string; time?: number; videoId?: string; playlistId?: string; @@ -9,3 +9,5 @@ export interface PlayerEvent { export interface PlayerEvents { events: PlayerEvent[]; } + +export const playbackRates = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.25, 2.5, 2.75, 3]; diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index 7ae99272..97a5f6ab 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -239,6 +239,12 @@ box-shadow: none !important; } + {:else if Capacitor.getPlatform() === 'android'} + {/if} diff --git a/update_versions.py b/update_versions.py index 407d6046..bb5f0e80 100644 --- a/update_versions.py +++ b/update_versions.py @@ -3,7 +3,7 @@ import os import re from datetime import datetime -LATEST_VERSION = "1.10.3" +LATEST_VERSION = "1.10.4" RELEASE_DATE = datetime.now().strftime("%Y-%-m-%d") # Format: YYYY-M-D WORKING_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "materialious")