More progress
This commit is contained in:
Generated
+11
-11
@@ -41,7 +41,7 @@
|
||||
"svelte-infinite-loading": "^1.4.0",
|
||||
"svelte-persisted-store": "^0.12.0",
|
||||
"terser": "^5.34.1",
|
||||
"youtubei.js": "^12.2.0"
|
||||
"youtubei.js": "^13.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
@@ -7241,17 +7241,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz",
|
||||
"integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==",
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.0",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
@@ -15092,16 +15092,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/youtubei.js": {
|
||||
"version": "12.2.0",
|
||||
"resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-12.2.0.tgz",
|
||||
"integrity": "sha512-G+50qrbJCToMYhu8jbaHiS3Vf+RRul+CcDbz3hEGwHkGPh+zLiWwD6SS+YhYF+2/op4ZU5zDYQJrGqJ+wKh7Gw==",
|
||||
"version": "13.1.0",
|
||||
"resolved": "https://registry.npmjs.org/youtubei.js/-/youtubei.js-13.1.0.tgz",
|
||||
"integrity": "sha512-uL4TyojAYET0c5NGFD7+ScCod/k8Pc/B+D5tLrunFcz1GaBjRMOGRPcNGaRmnhwisegU7ibtw0iUxCN+BZ0ang==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/LuanRT"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bufbuild/protobuf": "^2.0.0",
|
||||
"jintr": "^3.2.0",
|
||||
"jintr": "^3.2.1",
|
||||
"tslib": "^2.5.0",
|
||||
"undici": "^5.19.1"
|
||||
}
|
||||
|
||||
@@ -74,6 +74,6 @@
|
||||
"svelte-infinite-loading": "^1.4.0",
|
||||
"svelte-persisted-store": "^0.12.0",
|
||||
"terser": "^5.34.1",
|
||||
"youtubei.js": "^12.2.0"
|
||||
"youtubei.js": "^13.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||
import { NavigationBar } from '@hugotomazi/capacitor-navigation-bar';
|
||||
import { type Page } from '@sveltejs/kit';
|
||||
import GoogleVideo, { Protos } from 'googlevideo';
|
||||
import 'shaka-player/dist/controls.css';
|
||||
import shaka from 'shaka-player/dist/shaka-player.ui';
|
||||
import { SponsorBlock, type Category, type Segment } from 'sponsorblock-api';
|
||||
@@ -51,6 +50,8 @@
|
||||
let sponsorBlockElements: Element[] = [];
|
||||
let watchProgressTimeout: NodeJS.Timeout;
|
||||
|
||||
const HTTP_IN_HEX = 0x68747470;
|
||||
|
||||
let player: shaka.Player;
|
||||
let playerElement: HTMLMediaElement;
|
||||
|
||||
@@ -121,7 +122,6 @@
|
||||
url.searchParams.set('ump', '1');
|
||||
url.searchParams.set('srfvp', '1');
|
||||
url.searchParams.set('pot', get(poTokenCacheStore));
|
||||
request.headers = {};
|
||||
delete headers.Range;
|
||||
}
|
||||
}
|
||||
@@ -133,107 +133,46 @@
|
||||
request.uris[0] = url.toString();
|
||||
});
|
||||
|
||||
networkingEngine.registerResponseFilter(async (type, response) => {
|
||||
let mediaData = new Uint8Array(0);
|
||||
networkingEngine.registerResponseFilter(async (type, response, context) => {
|
||||
if (
|
||||
response.data &&
|
||||
response.data.byteLength > 4 &&
|
||||
new DataView(
|
||||
response.data as ArrayBufferLike & { BYTES_PER_ELEMENT?: undefined }
|
||||
).getUint32(0) === HTTP_IN_HEX
|
||||
) {
|
||||
// Interpret the response data as a URL string.
|
||||
const responseAsString = shaka.util.StringUtils.fromUTF8(response.data);
|
||||
|
||||
const handleRedirect = async (redirectData: Protos.SabrRedirect) => {
|
||||
const redirectRequest = shaka.net.NetworkingEngine.makeRequest(
|
||||
[redirectData.url!],
|
||||
player!.getConfiguration().streaming.retryParameters
|
||||
);
|
||||
const requestOperation = player!.getNetworkingEngine()!.request(type, redirectRequest);
|
||||
const retryParameters = player.getConfiguration().streaming.retryParameters;
|
||||
|
||||
// Make another request for the redirect URL.
|
||||
const uris = [responseAsString];
|
||||
const redirectRequest = shaka.net.NetworkingEngine.makeRequest(uris, retryParameters);
|
||||
const requestOperation = networkingEngine.request(type, redirectRequest, context);
|
||||
const redirectResponse = await requestOperation.promise;
|
||||
|
||||
// Modify the original response to contain the results of the redirect
|
||||
// response.
|
||||
response.data = redirectResponse.data;
|
||||
response.headers = redirectResponse.headers;
|
||||
response.uri = redirectResponse.uri;
|
||||
};
|
||||
} else {
|
||||
const url = new URL(response.uri);
|
||||
|
||||
const handleMediaData = async (data: Uint8Array) => {
|
||||
const combinedLength = mediaData.length + data.length;
|
||||
const tempMediaData = new Uint8Array(combinedLength);
|
||||
|
||||
tempMediaData.set(mediaData);
|
||||
tempMediaData.set(data, mediaData.length);
|
||||
|
||||
mediaData = tempMediaData;
|
||||
};
|
||||
|
||||
if (type === shaka.net.NetworkingEngine.RequestType.SEGMENT) {
|
||||
// Fix positioning for auto-generated subtitles
|
||||
if (
|
||||
response.data &&
|
||||
response.data.byteLength > 4 &&
|
||||
new DataView(
|
||||
response.data as ArrayBufferLike & {
|
||||
BYTES_PER_ELEMENT?: never;
|
||||
}
|
||||
).getUint32(0) === 0x68747470
|
||||
url.hostname.endsWith('.youtube.com') &&
|
||||
url.pathname === '/api/timedtext' &&
|
||||
url.searchParams.get('caps') === 'asr' &&
|
||||
url.searchParams.get('kind') === 'asr' &&
|
||||
url.searchParams.get('fmt') === 'vtt'
|
||||
) {
|
||||
const googUmp = new GoogleVideo.UMP(
|
||||
new GoogleVideo.ChunkedDataBuffer([new Uint8Array(response.data as ArrayBuffer)])
|
||||
);
|
||||
const stringBody = new TextDecoder().decode(response.data);
|
||||
// position:0% for LTR text and position:100% for RTL text
|
||||
const cleaned = stringBody.replaceAll(/ align:start position:(?:10)?0%$/gm, '');
|
||||
|
||||
let redirect: Protos.SabrRedirect | undefined;
|
||||
|
||||
googUmp.parse((part) => {
|
||||
try {
|
||||
const data = part.data.chunks[0];
|
||||
switch (part.type) {
|
||||
case 20: {
|
||||
const mediaHeader = Protos.MediaHeader.decode(data);
|
||||
console.info('[MediaHeader]:', mediaHeader);
|
||||
break;
|
||||
}
|
||||
case 21: {
|
||||
handleMediaData(part.data.split(1).remainingBuffer.chunks[0]);
|
||||
break;
|
||||
}
|
||||
case 43: {
|
||||
redirect = Protos.SabrRedirect.decode(data);
|
||||
console.info('[SABRRedirect]:', redirect);
|
||||
break;
|
||||
}
|
||||
case 58: {
|
||||
const streamProtectionStatus = Protos.StreamProtectionStatus.decode(data);
|
||||
switch (streamProtectionStatus.status) {
|
||||
case 1:
|
||||
console.info('[StreamProtectionStatus]: Ok');
|
||||
break;
|
||||
case 2:
|
||||
console.error('[StreamProtectionStatus]: Attestation pending');
|
||||
break;
|
||||
case 3:
|
||||
console.error('[StreamProtectionStatus]: Attestation required');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('An error occurred while processing the part:', error);
|
||||
}
|
||||
});
|
||||
|
||||
if (redirect) return handleRedirect(redirect);
|
||||
|
||||
if (mediaData.length) response.data = mediaData;
|
||||
} else {
|
||||
const url = new URL(response.uri);
|
||||
if (
|
||||
url.hostname.endsWith('.youtube.com') &&
|
||||
url.pathname === '/api/timedtext' &&
|
||||
url.searchParams.get('caps') === 'asr' &&
|
||||
url.searchParams.get('kind') === 'asr' &&
|
||||
url.searchParams.get('fmt') === 'vtt'
|
||||
) {
|
||||
const stringBody = new TextDecoder().decode(response.data);
|
||||
// position:0% for LTR text and position:100% for RTL text
|
||||
const cleaned = stringBody.replaceAll(/ align:start position:(?:10)?0%$/gm, '');
|
||||
|
||||
response.data = new TextEncoder().encode(cleaned).buffer as ArrayBuffer;
|
||||
}
|
||||
response.data = new TextEncoder().encode(cleaned).buffer as ArrayBuffer;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user