+2
-2
@@ -4,10 +4,10 @@
|
||||
<selectionStates>
|
||||
<SelectionState runConfigName="app">
|
||||
<option name="selectionMode" value="DROPDOWN" />
|
||||
<DropdownSelection timestamp="2026-01-05T05:19:59.214925354Z">
|
||||
<DropdownSelection timestamp="2026-01-25T13:45:42.378164664Z">
|
||||
<Target type="DEFAULT_BOOT">
|
||||
<handle>
|
||||
<DeviceId pluginId="LocalEmulator" identifier="path=/home/ward/.android/avd/Television_4K.avd" />
|
||||
<DeviceId pluginId="LocalEmulator" identifier="path=/home/ward/.android/avd/Pixel_9.avd" />
|
||||
</handle>
|
||||
</Target>
|
||||
</DropdownSelection>
|
||||
|
||||
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "us.materialio.app"
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
versionCode 192
|
||||
versionName "1.13.8"
|
||||
versionCode 193
|
||||
versionName "1.13.9"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
aaptOptions {
|
||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||
|
||||
@@ -91,7 +91,11 @@
|
||||
|
||||
|
||||
|
||||
<release version="1.13.8" date="2026-1-22">
|
||||
|
||||
<release version="1.13.9" date="2026-1-26">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.13.9</url>
|
||||
</release>
|
||||
<release version="1.13.8" date="2026-1-22">
|
||||
<url>https://github.com/Materialious/Materialious/releases/tag/1.13.8</url>
|
||||
</release>
|
||||
<release version="1.13.7" date="2026-1-21">
|
||||
|
||||
Generated
+32
-3
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.13.8",
|
||||
"version": "1.13.9",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "Materialious",
|
||||
"version": "1.13.8",
|
||||
"version": "1.13.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@capacitor-community/electron": "^5.0.0",
|
||||
@@ -19,7 +19,8 @@
|
||||
"electron-updater": "^6.3.4",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"jsdom": "^27.4.0",
|
||||
"jsonfile": "^6.2.0"
|
||||
"jsonfile": "^6.2.0",
|
||||
"youtubei.js": "^16.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^40.0.0",
|
||||
@@ -84,6 +85,12 @@
|
||||
"integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@bufbuild/protobuf": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.11.0.tgz",
|
||||
"integrity": "sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==",
|
||||
"license": "(Apache-2.0 AND BSD-3-Clause)"
|
||||
},
|
||||
"node_modules/@capacitor-community/electron": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor-community/electron/-/electron-5.0.1.tgz",
|
||||
@@ -4607,6 +4614,15 @@
|
||||
"integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/meriyah": {
|
||||
"version": "6.1.4",
|
||||
"resolved": "https://registry.npmjs.org/meriyah/-/meriyah-6.1.4.tgz",
|
||||
"integrity": "sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
|
||||
@@ -6589,6 +6605,19 @@
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/youtubei.js": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-16.0.1.tgz",
|
||||
"integrity": "sha512-3802bCAGkBc2/G5WUTc0l/bO5mPYJbQAHL04d9hE9PnrDHoBUT8MN721Yqt4RCNncAXdHcfee9VdJy3Fhq1r5g==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.0.0",
|
||||
"meriyah": "^6.1.4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Materialious",
|
||||
"version": "1.13.8",
|
||||
"version": "1.13.9",
|
||||
"description": "Modern material design for Invidious.",
|
||||
"author": {
|
||||
"name": "Ward Pearce",
|
||||
@@ -32,7 +32,8 @@
|
||||
"electron-updater": "^6.3.4",
|
||||
"electron-window-state": "^5.0.3",
|
||||
"jsdom": "^27.4.0",
|
||||
"jsonfile": "^6.2.0"
|
||||
"jsonfile": "^6.2.0",
|
||||
"youtubei.js": "^16.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^40.0.0",
|
||||
@@ -44,4 +45,4 @@
|
||||
"capacitor",
|
||||
"electron"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import electronIsDev from 'electron-is-dev';
|
||||
import unhandled from 'electron-unhandled';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import type { IGetChallengeResponse } from 'youtubei.js';
|
||||
|
||||
import BG, { buildURL, GOOG_API_KEY, USER_AGENT, WebPoSignalOutput } from 'bgutils-js';
|
||||
import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup';
|
||||
@@ -74,91 +75,96 @@ app.on('activate', async function () {
|
||||
});
|
||||
|
||||
// Place all ipc or other electron api calls and custom functionality under this line
|
||||
ipcMain.handle('generatePoToken', async (_, requestKey: string, visitorData: string) => {
|
||||
const youtubeUrl = 'https://www.youtube.com/';
|
||||
ipcMain.handle(
|
||||
'generatePoToken',
|
||||
async (_, requestKey: string, visitorData: string, challenge: IGetChallengeResponse) => {
|
||||
const youtubeUrl = 'https://www.youtube.com/';
|
||||
|
||||
const dom = new JSDOM(
|
||||
'<!DOCTYPE html><html lang="en"><head><title>YouTube</title></head><body></body></html>',
|
||||
{
|
||||
url: youtubeUrl,
|
||||
referrer: youtubeUrl,
|
||||
origin: youtubeUrl,
|
||||
USER_AGENT
|
||||
const dom = new JSDOM(
|
||||
'<!DOCTYPE html><html lang="en"><head><title>YouTube</title></head><body></body></html>',
|
||||
{
|
||||
url: youtubeUrl,
|
||||
referrer: youtubeUrl,
|
||||
origin: youtubeUrl,
|
||||
USER_AGENT
|
||||
}
|
||||
);
|
||||
|
||||
Object.assign(globalThis, {
|
||||
window: dom.window,
|
||||
document: dom.window.document,
|
||||
location: dom.window.location,
|
||||
origin: dom.window.origin
|
||||
});
|
||||
|
||||
if (!Reflect.has(globalThis, 'navigator')) {
|
||||
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator });
|
||||
}
|
||||
);
|
||||
|
||||
Object.assign(globalThis, {
|
||||
window: dom.window,
|
||||
document: dom.window.document,
|
||||
location: dom.window.location,
|
||||
origin: dom.window.origin
|
||||
});
|
||||
if (!challenge.bg_challenge) {
|
||||
throw new Error('No BotGuard Token');
|
||||
}
|
||||
|
||||
if (!Reflect.has(globalThis, 'navigator')) {
|
||||
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator });
|
||||
}
|
||||
const interpreterUrl =
|
||||
challenge.bg_challenge.interpreter_url
|
||||
.private_do_not_access_or_else_trusted_resource_url_wrapped_value;
|
||||
const interpreterHash = challenge.bg_challenge.interpreter_hash;
|
||||
|
||||
const challengeResponse = await fetch(buildURL('Create', true), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json+protobuf',
|
||||
'x-goog-api-key': GOOG_API_KEY,
|
||||
'x-user-agent': 'grpc-web-javascript/0.1'
|
||||
},
|
||||
body: JSON.stringify([requestKey])
|
||||
});
|
||||
if (!interpreterUrl || !interpreterHash) {
|
||||
throw new Error(
|
||||
`Could not get integrity token. Interpreter Hash: ${challenge.bg_challenge?.interpreter_hash}`
|
||||
);
|
||||
}
|
||||
|
||||
const challengeResponseData = await challengeResponse.json();
|
||||
const bgChallenge = BG.Challenge.parseChallengeData(challengeResponseData);
|
||||
const interpreterResponse = await fetch(`https:${interpreterUrl}`, {
|
||||
headers: {
|
||||
'user-agent': USER_AGENT
|
||||
}
|
||||
});
|
||||
|
||||
if (!bgChallenge) throw new Error('Unable to parse challenge data');
|
||||
if (!interpreterResponse.ok) {
|
||||
throw new Error('Unable to fetch interpreter');
|
||||
}
|
||||
|
||||
const interpreterJavascript =
|
||||
bgChallenge.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
|
||||
const interpreterJavascript = await interpreterResponse.text();
|
||||
|
||||
if (!interpreterJavascript) {
|
||||
throw new Error(
|
||||
`Could not get integrity token. Interpreter Hash: ${bgChallenge.interpreterHash}`
|
||||
if (interpreterJavascript) {
|
||||
new Function(interpreterJavascript)();
|
||||
} else throw new Error('Could not load VM');
|
||||
|
||||
const botguardClient = await BG.BotGuardClient.create({
|
||||
program: challenge.bg_challenge.program,
|
||||
globalName: challenge.bg_challenge.global_name,
|
||||
globalObj: globalThis
|
||||
});
|
||||
|
||||
const webPoSignalOutput: WebPoSignalOutput = [];
|
||||
const botguardResponse = await botguardClient.snapshot({ webPoSignalOutput });
|
||||
|
||||
const integrityTokenResponse = await fetch(buildURL('GenerateIT', true), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json+protobuf',
|
||||
'x-goog-api-key': GOOG_API_KEY,
|
||||
'x-user-agent': 'grpc-web-javacript/0.1'
|
||||
},
|
||||
body: JSON.stringify([requestKey, botguardResponse])
|
||||
});
|
||||
|
||||
const integrityTokenResponseData = await integrityTokenResponse.json();
|
||||
const integrityToken = integrityTokenResponseData[0] as string | undefined;
|
||||
|
||||
if (!integrityToken) {
|
||||
throw new Error(`Could not get integrity token. Interpreter Hash: ${interpreterHash}`);
|
||||
}
|
||||
|
||||
const integrityTokenBasedMinter = await BG.WebPoMinter.create(
|
||||
{ integrityToken },
|
||||
webPoSignalOutput
|
||||
);
|
||||
return await integrityTokenBasedMinter.mintAsWebsafeString(decodeURIComponent(visitorData));
|
||||
}
|
||||
if (interpreterJavascript) {
|
||||
new Function(interpreterJavascript)();
|
||||
} else throw new Error('Could not load VM');
|
||||
|
||||
const botguardClient = await BG.BotGuardClient.create({
|
||||
program: bgChallenge.program,
|
||||
globalName: bgChallenge.globalName,
|
||||
globalObj: globalThis
|
||||
});
|
||||
|
||||
const webPoSignalOutput: WebPoSignalOutput = [];
|
||||
const botguardResponse = await botguardClient.snapshot({ webPoSignalOutput });
|
||||
|
||||
const integrityTokenResponse = await fetch(buildURL('GenerateIT', true), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json+protobuf',
|
||||
'x-goog-api-key': GOOG_API_KEY,
|
||||
'x-user-agent': 'grpc-web-javacript/0.1'
|
||||
},
|
||||
body: JSON.stringify([requestKey, botguardResponse])
|
||||
});
|
||||
|
||||
const integrityTokenResponseData = await integrityTokenResponse.json();
|
||||
const integrityToken = integrityTokenResponseData[0] as string | undefined;
|
||||
|
||||
if (!integrityToken) {
|
||||
throw new Error(
|
||||
`Could not get integrity token. Interpreter Hash: ${bgChallenge.interpreterHash}`
|
||||
);
|
||||
}
|
||||
|
||||
const integrityTokenBasedMinter = await BG.WebPoMinter.create(
|
||||
{ integrityToken },
|
||||
webPoSignalOutput
|
||||
);
|
||||
return await integrityTokenBasedMinter.mintAsWebsafeString(decodeURIComponent(visitorData));
|
||||
});
|
||||
);
|
||||
|
||||
ipcMain.handle('setAllowInsecureSSL', async (_, allow) => {
|
||||
allowInsecureSSL = allow;
|
||||
|
||||
@@ -2,8 +2,8 @@ const { contextBridge, ipcRenderer } = require('electron');
|
||||
require('./rt/electron-rt');
|
||||
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
generatePoToken: (requestKey: string, visitorData: string) =>
|
||||
ipcRenderer.invoke('generatePoToken', requestKey, visitorData),
|
||||
generatePoToken: (requestKey: string, visitorData: string, challenge: any) =>
|
||||
ipcRenderer.invoke('generatePoToken', requestKey, visitorData, challenge),
|
||||
setAllowInsecureSSL: async (allow: boolean) => {
|
||||
return await ipcRenderer.invoke('setAllowInsecureSSL', allow);
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "materialious",
|
||||
"version": "1.13.8",
|
||||
"version": "1.13.9",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "npm run patch:github && vite dev",
|
||||
|
||||
Vendored
+6
-3
@@ -1,6 +1,5 @@
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
import type { IGetChallengeResponse } from 'youtubei.js';
|
||||
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
@@ -11,7 +10,11 @@ declare global {
|
||||
}
|
||||
interface Window {
|
||||
electronAPI: {
|
||||
generatePoToken: (requestKey: string, visitorData: string) => Promise<string>;
|
||||
generatePoToken: (
|
||||
requestKey: string,
|
||||
visitorData: string,
|
||||
challenge: IGetChallengeResponse
|
||||
) => Promise<string>;
|
||||
setAllowInsecureSSL: (allowInsecureSSL: boolean) => Promoise<boolean>;
|
||||
doUpdateCheck: (disableAutoUpdate: boolean) => Promise<void>;
|
||||
};
|
||||
|
||||
@@ -1,45 +1,49 @@
|
||||
import { BG, buildURL, GOOG_API_KEY, type WebPoSignalOutput } from 'bgutils-js';
|
||||
import { BG, buildURL, GOOG_API_KEY, USER_AGENT, type WebPoSignalOutput } from 'bgutils-js';
|
||||
import type { IGetChallengeResponse } from 'youtubei.js';
|
||||
|
||||
export async function androidPoTokenMinter(
|
||||
requestKey: string,
|
||||
visitorData: string
|
||||
visitorData: string,
|
||||
challenge: IGetChallengeResponse
|
||||
): Promise<string> {
|
||||
const challengeResponse = await fetch(buildURL('Create', true), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json+protobuf',
|
||||
'x-goog-api-key': GOOG_API_KEY,
|
||||
'x-user-agent': 'grpc-web-javascript/0.1'
|
||||
},
|
||||
body: JSON.stringify([requestKey])
|
||||
});
|
||||
if (!challenge.bg_challenge) {
|
||||
throw new Error('No BotGuard Token');
|
||||
}
|
||||
|
||||
const challengeResponseData = await challengeResponse.json();
|
||||
const bgChallenge = BG.Challenge.parseChallengeData(challengeResponseData);
|
||||
const interpreterUrl =
|
||||
challenge.bg_challenge.interpreter_url
|
||||
.private_do_not_access_or_else_trusted_resource_url_wrapped_value;
|
||||
const interpreterHash = challenge.bg_challenge.interpreter_hash;
|
||||
|
||||
if (!bgChallenge) throw new Error('Unable to parse challenge data');
|
||||
|
||||
const interpreterJavascript =
|
||||
bgChallenge.interpreterJavascript.privateDoNotAccessOrElseSafeScriptWrappedValue;
|
||||
|
||||
if (!interpreterJavascript) {
|
||||
if (!interpreterUrl || !interpreterHash) {
|
||||
throw new Error(
|
||||
`Could not get integrity token. Interpreter Hash: ${bgChallenge.interpreterHash}`
|
||||
`Could not get integrity token. Interpreter Hash: ${challenge.bg_challenge?.interpreter_hash}`
|
||||
);
|
||||
}
|
||||
|
||||
if (!document.getElementById(bgChallenge.interpreterHash)) {
|
||||
if (!document.getElementById(interpreterHash)) {
|
||||
const interpreterResponse = await fetch(`https:${interpreterUrl}`, {
|
||||
headers: {
|
||||
'user-agent': USER_AGENT
|
||||
}
|
||||
});
|
||||
if (!interpreterResponse.ok) {
|
||||
throw new Error('Unable to fetch interpreter');
|
||||
}
|
||||
|
||||
const interpreterJavascript = await interpreterResponse.text();
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.type = 'text/javascript';
|
||||
script.id = bgChallenge.interpreterHash;
|
||||
script.id = interpreterHash;
|
||||
script.textContent = interpreterJavascript;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
const botguardClient = await BG.BotGuardClient.create({
|
||||
globalObj: globalThis,
|
||||
globalName: bgChallenge.globalName,
|
||||
program: bgChallenge.program
|
||||
program: challenge.bg_challenge.program,
|
||||
globalName: challenge.bg_challenge.global_name,
|
||||
globalObj: globalThis
|
||||
});
|
||||
|
||||
const webPoSignalOutput: WebPoSignalOutput = [];
|
||||
@@ -59,9 +63,7 @@ export async function androidPoTokenMinter(
|
||||
const integrityToken = integrityTokenResponseData[0] as string | undefined;
|
||||
|
||||
if (!integrityToken) {
|
||||
throw new Error(
|
||||
`Could not get integrity token. Interpreter Hash: ${bgChallenge.interpreterHash}`
|
||||
);
|
||||
throw new Error(`Could not get integrity token. Interpreter Hash: ${interpreterHash}`);
|
||||
}
|
||||
|
||||
const integrityTokenBasedMinter = await BG.WebPoMinter.create(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { SynciousProgressModel } from './model';
|
||||
import type { ApiExntendedProgressModel } from './model';
|
||||
import { getVideoProgress } from '.';
|
||||
|
||||
const videoIds: string[] = [];
|
||||
const pendingResolves = new Map<string, (result: SynciousProgressModel | undefined) => void>();
|
||||
const pendingResolves = new Map<string, (result: ApiExntendedProgressModel | undefined) => void>();
|
||||
|
||||
let timeout: ReturnType<typeof setTimeout> | null = null;
|
||||
const DEBOUNCE_MS = 1000;
|
||||
@@ -15,10 +15,10 @@ async function processBatches(): Promise<void> {
|
||||
batches.push(videoIds.splice(0, BATCH_SIZE));
|
||||
}
|
||||
|
||||
const results: SynciousProgressModel[] = [];
|
||||
const results: ApiExntendedProgressModel[] = [];
|
||||
|
||||
for (const batch of batches) {
|
||||
const res: SynciousProgressModel[] = await getVideoProgress(batch.join(','));
|
||||
const res: ApiExntendedProgressModel[] = await getVideoProgress(batch.join(','));
|
||||
results.push(...res);
|
||||
|
||||
// Resolve pending promises for this batch
|
||||
@@ -33,10 +33,12 @@ async function processBatches(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
export function queueSyncious(videoId: string): Promise<SynciousProgressModel | undefined> {
|
||||
export function queueGetWatchProgress(
|
||||
videoId: string
|
||||
): Promise<ApiExntendedProgressModel | undefined> {
|
||||
videoIds.push(videoId);
|
||||
|
||||
const promise = new Promise<SynciousProgressModel | undefined>((resolve) => {
|
||||
const promise = new Promise<ApiExntendedProgressModel | undefined>((resolve) => {
|
||||
pendingResolves.set(videoId, resolve);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { patchYoutubeJs } from '$lib/patches/youtubejs';
|
||||
import { getVideoTYjs } from '$lib/api/youtubejs';
|
||||
import { Capacitor } from '@capacitor/core';
|
||||
import { get } from 'svelte/store';
|
||||
import {
|
||||
@@ -27,7 +27,7 @@ import type {
|
||||
ReturnYTDislikes,
|
||||
SearchSuggestion,
|
||||
Subscription,
|
||||
SynciousProgressModel,
|
||||
ApiExntendedProgressModel,
|
||||
Video,
|
||||
VideoPlay
|
||||
} from './model';
|
||||
@@ -86,13 +86,13 @@ export async function getVideo(
|
||||
fetchOptions?: RequestInit
|
||||
): Promise<VideoPlay> {
|
||||
if (get(playerYouTubeJsAlways) && Capacitor.isNativePlatform()) {
|
||||
return await patchYoutubeJs(videoId);
|
||||
return await getVideoTYjs(videoId);
|
||||
}
|
||||
|
||||
const resp = await fetch(setRegion(buildPath(`videos/${videoId}?local=${local}`)), fetchOptions);
|
||||
|
||||
if (!resp.ok && get(playerYouTubeJsFallback) && Capacitor.isNativePlatform()) {
|
||||
return await patchYoutubeJs(videoId);
|
||||
return await getVideoTYjs(videoId);
|
||||
} else {
|
||||
await fetchErrorHandle(resp);
|
||||
}
|
||||
@@ -447,7 +447,7 @@ function buildApiExtendedAuthHeaders(): Record<string, Record<string, string>> {
|
||||
export async function getVideoProgress(
|
||||
videoId: string,
|
||||
fetchOptions: RequestInit = {}
|
||||
): Promise<SynciousProgressModel[]> {
|
||||
): Promise<ApiExntendedProgressModel[]> {
|
||||
const resp = await fetchErrorHandle(
|
||||
await fetch(`${get(synciousInstanceStore)}/video/${encodeURIComponent(videoId)}`, {
|
||||
...buildApiExtendedAuthHeaders(),
|
||||
|
||||
@@ -285,7 +285,7 @@ export interface DeArrow {
|
||||
videoDuration: number;
|
||||
}
|
||||
|
||||
export interface SynciousProgressModel {
|
||||
export interface ApiExntendedProgressModel {
|
||||
time: number;
|
||||
video_id: string;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ Platform.shim.eval = async (
|
||||
return new Function(code)();
|
||||
};
|
||||
|
||||
export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
|
||||
export async function getVideoTYjs(videoId: string): Promise<VideoPlay> {
|
||||
if (!Capacitor.isNativePlatform()) {
|
||||
throw new Error('Platform not supported');
|
||||
}
|
||||
@@ -82,7 +82,8 @@ export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
|
||||
throw new Error('Unable to pull video info from youtube.js');
|
||||
}
|
||||
|
||||
poTokenCacheStore.set(await platformMinter(requestKey, videoId));
|
||||
const challengeResponse = await youtube.getAttestationChallenge('ENGAGEMENT_TYPE_UNBOUND');
|
||||
poTokenCacheStore.set(await platformMinter(requestKey, videoId, challengeResponse));
|
||||
|
||||
let dashUri: string | undefined;
|
||||
|
||||
@@ -90,7 +91,7 @@ export async function patchYoutubeJs(videoId: string): Promise<VideoPlay> {
|
||||
// https://github.com/LuanRT/googlevideo/issues/42
|
||||
if (video.streaming_data)
|
||||
video.streaming_data.adaptive_formats = video.streaming_data.adaptive_formats.filter(
|
||||
(format) => format.xtags !== 'CgcKAnZiEgEx'
|
||||
(format) => !format.xtags
|
||||
);
|
||||
|
||||
const adaptiveFormats: AdaptiveFormats[] = [];
|
||||
@@ -44,7 +44,7 @@
|
||||
synciousStore
|
||||
} from '../store';
|
||||
import { setStatusBarColor } from '../theme';
|
||||
import { patchYoutubeJs } from '$lib/patches/youtubejs';
|
||||
import { getVideoTYjs } from '$lib/api/youtubejs';
|
||||
import {
|
||||
goToNextVideo,
|
||||
goToPreviousVideo,
|
||||
@@ -568,7 +568,7 @@
|
||||
|
||||
async function reloadVideo() {
|
||||
showVideoRetry = false;
|
||||
data.video = await patchYoutubeJs(data.video.videoId);
|
||||
data.video = await getVideoTYjs(data.video.videoId);
|
||||
await loadVideo();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
synciousInstanceStore,
|
||||
synciousStore
|
||||
} from '../store';
|
||||
import { queueSyncious } from '$lib/api/apiExtended';
|
||||
import { queueGetWatchProgress } from '$lib/api/apiExtended';
|
||||
|
||||
interface Props {
|
||||
video: VideoBase | Video | Notification | PlaylistPageVideo;
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
if (get(synciousStore) && get(synciousInstanceStore) && get(authStore)) {
|
||||
try {
|
||||
progress = (await queueSyncious(video.videoId))?.time?.toString() ?? undefined;
|
||||
progress = (await queueGetWatchProgress(video.videoId))?.time?.toString() ?? undefined;
|
||||
} catch {
|
||||
// Continue regardless of error
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -3,7 +3,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
LATEST_VERSION = "1.13.8"
|
||||
LATEST_VERSION = "1.13.9"
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user