From 3a6a7e897462404d3cb546a135029830e94285a9 Mon Sep 17 00:00:00 2001 From: kevinpfeifer Date: Wed, 11 Aug 2021 02:15:27 +0200 Subject: [PATCH] get urls directly, see https://github.com/TeamNewPipe/NewPipeExtractor/issues/562 --- react/modules/remote/API.js | 42 +++++----- react/modules/remote/Decrypt.js | 127 ------------------------------ react/modules/remote/Extractor.js | 23 +----- 3 files changed, 23 insertions(+), 169 deletions(-) delete mode 100644 react/modules/remote/Decrypt.js diff --git a/react/modules/remote/API.js b/react/modules/remote/API.js index 80bcaf9..02c21a1 100644 --- a/react/modules/remote/API.js +++ b/react/modules/remote/API.js @@ -11,7 +11,6 @@ import { import { settings } from "../../modules/storage/SettingsStorage"; import { getHttpResponse, getUrl } from "./HTTP"; -import { enableDecryption, signatureTimestamp, isDecryptionWorking } from "./Decrypt"; export const headers_simple = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0"}; const headers_ytm = { @@ -37,13 +36,6 @@ async function getConfig(path) { configuration = extractConfiguration(response); - let baseUrl = configuration - .WEB_PLAYER_CONTEXT_CONFIGS - .WEB_PLAYER_CONTEXT_CONFIG_ID_MUSIC_WATCH - .jsUrl - - enableDecryption({baseUrl}); - apiKey = configuration .WEB_PLAYER_CONTEXT_CONFIGS .WEB_PLAYER_CONTEXT_CONFIG_ID_MUSIC_WATCH @@ -55,7 +47,25 @@ function getRequestBody() { context: { client: { clientName: "WEB_REMIX", - clientVersion: "0.1", + clientVersion: "1.20210630.00.00" + } + } + }; + + if (settings.transmitLanguage) { + body.context.client["gl"] = getGL(); + body.context.client["hl"] = getHL(); + } + + return body; +} + +function getRequestBodyStream() { + let body = { + context: { + client: { + clientName: "ANDROID", + clientVersion: "16.02" } } }; @@ -205,11 +215,6 @@ export async function fetchAudioInfo({videoId, playlistId, controllerCallback}) let body = getRequestBody(); body.context["user"] = { lockedSafetyMode: settings.safetyMode } body["videoId"] = videoId; - - if (!isDecryptionWorking()) - await enableDecryption({videoId}); - - body["playbackContext"] = {contentPlaybackContext: {signatureTimestamp: signatureTimestamp}}; if (playlistId) body["playlistId"] = playlistId; @@ -226,17 +231,12 @@ export async function fetchAudioInfo({videoId, playlistId, controllerCallback}) } export async function fetchAudioStream({videoId, controllerCallback}) { - let url = "https://music.youtube.com/youtubei/v1/player?key=" + apiKey; + let url = "https://youtubei.googleapis.com/youtubei/v1/player?key=" + apiKey; - let body = getRequestBody(); + let body = getRequestBodyStream(); body.context["user"] = { lockedSafetyMode: settings.safetyMode } body["videoId"] = videoId; - if (!isDecryptionWorking()) - await enableDecryption({videoId}); - - body["playbackContext"] = {contentPlaybackContext: {signatureTimestamp: signatureTimestamp}}; - let response = await getHttpResponse(url, { method: "POST", headers: headers_ytm, diff --git a/react/modules/remote/Decrypt.js b/react/modules/remote/Decrypt.js deleted file mode 100644 index 6131331..0000000 --- a/react/modules/remote/Decrypt.js +++ /dev/null @@ -1,127 +0,0 @@ -import { getHttpResponse } from "./HTTP"; -import { headers_simple } from "./API"; - -const REGEXES = [ - "(?:\\b|[^a-zA-Z0-9$])([a-zA-Z0-9$]{2})\\s*=\\s*function\\(\\s*a\\s*\\)\\s*\\{\\s*a\\s*=\\s*a\\.split\\(\\s*\"\"\\s*\\)", - "([\\w$]+)\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;", - "\\b([\\w$]{2})\\s*=\\s*function\\((\\w+)\\)\\{\\s*\\2=\\s*\\2\\.split\\(\"\"\\)\\s*;", - "yt\\.akamaized\\.net/\\)\\s*\\|\\|\\s*.*?\\s*c\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(", - "\\bc\\s*&&\\s*d\\.set\\([^,]+\\s*,\\s*(:encodeURIComponent\\s*\\()([a-zA-Z0-9$]+)\\(" -]; - -const domain = "https://www.youtube.com"; -const function_name = "decryptSignature"; - -var functionString = null; -export var signatureTimestamp = null; - -async function fetchBaseJsLocation(videoId) { - let watch = domain + "/watch?v=" + videoId; - let watchResponse = await getHttpResponse(watch, { - method: "GET", - headers: headers_simple - }, "text"); - - let location = extractLocation(watchResponse); - - return location; -} - -function extractLocation(response) { - let searchTerm; - if (response.indexOf('"js":') != -1) { - searchTerm = '"js":'; - } else if (response.indexOf('"jsUrl":') != -1) { - searchTerm = '"jsUrl":'; - } else { - return null; - } - - let jsIndex = response.indexOf(searchTerm); - - let side = response.substring(jsIndex + searchTerm.length); - let ind1x = side.indexOf(","); - let ind2x = side.indexOf("}"); - - let result; - if (ind1x < ind2x) - result = side.substring(0, ind1x); - else - result = side.substring(0, ind2x); - - return result.replace(/\\/g, '').replace(/\"/g, ''); -} - -async function fetchBaseJs(location) { - let playerUrl = domain + location; - let playerCode = await getHttpResponse(playerUrl, { - method: "GET", - headers: headers_simple - }, "text"); - - return playerCode; -} - -function extractTimestamp(code) { - code = code.substring(code.indexOf("d.sts=\"") + 7); - code = code.substring(0, code.indexOf("\"")); - return code; -} - -function getSignatureTimestamp() { - if (!signatureTimestamp) - return signatureTimestamp; - - extractTimestamp(); -} - -function getFunction(code) { - let decryptionFunctionName; - for (let i = 0; i < REGEXES.length; i++) { - let pattern = new RegExp(REGEXES[i]); - let result = pattern.exec(code); - - if (result != undefined) { - if (result[1] != undefined) { - decryptionFunctionName = result[1]; - break; - } - } - } - - let functionPattern = "(" + decryptionFunctionName.split("$").join("\\$") + "=function\\([a-zA-Z0-9_]+\\)\\{.+?\\})"; - let decryptionFunction = "var " + new RegExp(functionPattern).exec(code)[1] + ";"; - let helperObjectName = new RegExp(";([A-Za-z0-9_\\$]{2})\\...\\(").exec(decryptionFunction)[1]; - let helperPattern = "(var " + helperObjectName.split("$").join("\\$") + "=\\{.+?\\}\\};)"; - let helperObject = new RegExp(helperPattern).exec(code.split("\n").join("")); - let callerFunction = "function " + function_name + "(a){return " + decryptionFunctionName + "(a);}"; - - return (helperObject + decryptionFunction + callerFunction).replace(";,", ";"); -} - -function setFunction(fnString) { - const gEval = function(){ (1, eval)(fnString); }; - gEval(); -} - -export function isDecryptionWorking() { - return functionString != null -} - -export async function enableDecryption({videoId, baseUrl}) { - if (isDecryptionWorking()) - return; - - if (videoId) - baseUrl = await fetchBaseJsLocation(); - - let playerCode = await fetchBaseJs(baseUrl); - - functionString = getFunction(playerCode); - signatureTimestamp = extractTimestamp(playerCode); - setFunction(functionString); -} - -export async function getSignature(videoId, signature) { - return decryptSignature(signature); -} \ No newline at end of file diff --git a/react/modules/remote/Extractor.js b/react/modules/remote/Extractor.js index c86da72..aa890c9 100644 --- a/react/modules/remote/Extractor.js +++ b/react/modules/remote/Extractor.js @@ -1,8 +1,6 @@ import { msToMin, msToMMSS, textToSec } from "../utils/Time"; import Track from "../models/music/track"; import Playlist from "../models/music/playlist"; -import { decodeNestedURI } from "../utils/Decoder"; -import { getSignature } from "./Decrypt"; import { hackTracks } from "../../components/collections/FlatEntries"; export function extractConfiguration(html) { @@ -688,26 +686,9 @@ export function digestBrowseResults(json, browseId) { } export async function digestStreams(parse) { - let videoId = parse.videoDetails.videoId; - for (let i = 0; i < parse.streamingData.adaptiveFormats.length; i++) { - if (parse.streamingData.adaptiveFormats[i].mimeType.split("/")[0] == "audio") { - if (parse.streamingData.adaptiveFormats[i].signatureCipher) { - let signatureCipher = parse.streamingData.adaptiveFormats[i].signatureCipher; - - let sigArray = decodeNestedURI(signatureCipher).split("&"); - let stream = sigArray[2].slice(4); - let s = await getSignature(videoId, sigArray[0].substring(2)); - - for (let j = 0; j < sigArray.length; j++) - if (j != 0 & j != 2) - stream += "&" + sigArray[j]; - - stream += "&sig=" + s; - return stream; - } else - return parse.streamingData.adaptiveFormats[i].url; - } + if (parse.streamingData.adaptiveFormats[i].mimeType.split("/")[0] == "audio") + return parse.streamingData.adaptiveFormats[i].url; } }