From 98fc8e3b9d247f6388539029e4ec756540db0a59 Mon Sep 17 00:00:00 2001 From: MiepHD <63968466+MiepHD@users.noreply.github.com> Date: Sun, 13 Aug 2023 18:01:19 +0200 Subject: [PATCH] Changed to a dependency --- package.json | 2 +- plugins/bypass-age-restrictions/front.js | 1294 +--------------------- yarn.lock | 10 +- 3 files changed, 8 insertions(+), 1298 deletions(-) diff --git a/package.json b/package.json index d69bdc9a..3e525829 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "md5": "^2.3.0", "mpris-service": "^2.1.2", "node-fetch": "^2.6.9", - "simple-youtube-age-restriction-bypass": "https://gitpkg.now.sh/api/pkg.tgz?url=zerodytrash/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.4", + "simple-youtube-age-restriction-bypass": "https://gitpkg.now.sh/api/pkg.tgz?url=MiepHD/Simple-YouTube-Age-Restriction-Bypass&commit=v2.5.5", "vudio": "^2.1.1", "youtubei.js": "^4.3.0", "ytpl": "^2.3.0" diff --git a/plugins/bypass-age-restrictions/front.js b/plugins/bypass-age-restrictions/front.js index 0f2d94d6..1ec536f6 100644 --- a/plugins/bypass-age-restrictions/front.js +++ b/plugins/bypass-age-restrictions/front.js @@ -1,1294 +1,4 @@ module.exports = () => { - // ==UserScript== - // @name Simple YouTube Age Restriction Bypass - // @description Watch age restricted videos on YouTube without login and without age verification 😎 - // @description:de Schaue YouTube Videos mit Altersbeschränkungen ohne Anmeldung und ohne dein Alter zu bestätigen 😎 - // @description:fr Regardez des vidéos YouTube avec des restrictions d'âge sans vous inscrire et sans confirmer votre âge 😎 - // @description:it Guarda i video con restrizioni di età su YouTube senza login e senza verifica dell'età 😎 - // @icon https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/raw/v2.5.4/src/extension/icon/icon_64.png - // @version 2.5.9 - // @author Zerody (https://github.com/zerodytrash) - // @namespace https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/ - // @supportURL https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/issues - // @updateURL https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/raw/main/dist/Simple-YouTube-Age-Restriction-Bypass.user.js - // @license MIT - // @match https://www.youtube.com/* - // @match https://www.youtube-nocookie.com/* - // @match https://m.youtube.com/* - // @match https://music.youtube.com/* - // @grant none - // @run-at document-start - // @compatible chrome - // @compatible firefox - // @compatible opera - // @compatible edge - // @compatible safari - // ==/UserScript== - - /* - This is a transpiled version to achieve a clean code base and better browser compatibility. - You can find the nicely readable source code at https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass - */ - - (function iife(ranOnce) { - // Trick to get around the sandbox restrictions in Greasemonkey (Firefox) - // Inject code into the main window if criteria match - if (this !== window && !ranOnce) { - window.eval('(' + iife.toString() + ')(true);'); - return; - } - - // Script configuration variables - const UNLOCKABLE_PLAYABILITY_STATUSES = ['AGE_VERIFICATION_REQUIRED', 'AGE_CHECK_REQUIRED', 'CONTENT_CHECK_REQUIRED', 'LOGIN_REQUIRED']; - const VALID_PLAYABILITY_STATUSES = ['OK', 'LIVE_STREAM_OFFLINE']; - - // These are the proxy servers that are sometimes required to unlock videos with age restrictions. - // You can host your own account proxy instance. See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/tree/main/account-proxy - // To learn what information is transferred, please read: https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass#privacy - const ACCOUNT_PROXY_SERVER_HOST = 'https://youtube-proxy.zerody.one'; - const VIDEO_PROXY_SERVER_HOST = 'https://ny.4everproxy.com'; - - // User needs to confirm the unlock process on embedded player? - let ENABLE_UNLOCK_CONFIRMATION_EMBED = true; - - // Show notification? - let ENABLE_UNLOCK_NOTIFICATION = true; - - // Disable content warnings? - let SKIP_CONTENT_WARNINGS = true; - - // Some Innertube bypass methods require the following authentication headers of the currently logged in user. - const GOOGLE_AUTH_HEADER_NAMES = ['Authorization', 'X-Goog-AuthUser', 'X-Origin']; - - /** - * The SQP parameter length is different for blurred thumbnails. - * They contain much less information, than normal thumbnails. - * The thumbnail SQPs tend to have a long and a short version. - */ - const BLURRED_THUMBNAIL_SQP_LENGTHS = [ - 32, // Mobile (SHORT) - 48, // Desktop Playlist (SHORT) - 56, // Desktop (SHORT) - 68, // Mobile (LONG) - 72, // Mobile Shorts - 84, // Desktop Playlist (LONG) - 88, // Desktop (LONG) - ]; - - // small hack to prevent tree shaking on these exports - var Config = window[Symbol()] = { - UNLOCKABLE_PLAYABILITY_STATUSES, - VALID_PLAYABILITY_STATUSES, - ACCOUNT_PROXY_SERVER_HOST, - VIDEO_PROXY_SERVER_HOST, - ENABLE_UNLOCK_CONFIRMATION_EMBED, - ENABLE_UNLOCK_NOTIFICATION, - SKIP_CONTENT_WARNINGS, - GOOGLE_AUTH_HEADER_NAMES, - BLURRED_THUMBNAIL_SQP_LENGTHS, - }; - - function isGoogleVideoUrl(url) { - return url.host.includes('.googlevideo.com'); - } - - function isGoogleVideoUnlockRequired(googleVideoUrl, lastProxiedGoogleVideoId) { - const urlParams = new URLSearchParams(googleVideoUrl.search); - const hasGcrFlag = urlParams.get('gcr'); - const wasUnlockedByAccountProxy = urlParams.get('id') === lastProxiedGoogleVideoId; - - return hasGcrFlag && wasUnlockedByAccountProxy; - } - - const nativeJSONParse = window.JSON.parse; - const nativeXMLHttpRequestOpen = window.XMLHttpRequest.prototype.open; - - const isDesktop = window.location.host !== 'm.youtube.com'; - const isMusic = window.location.host === 'music.youtube.com'; - const isEmbed = window.location.pathname.indexOf('/embed/') === 0; - const isConfirmed = window.location.search.includes('unlock_confirmed'); - - class Deferred { - constructor() { - return Object.assign( - new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; - }), - this, - ); - } - } - - function createElement(tagName, options) { - const node = document.createElement(tagName); - options && Object.assign(node, options); - return node; - } - - function isObject(obj) { - return obj !== null && typeof obj === 'object'; - } - - function findNestedObjectsByAttributeNames(object, attributeNames) { - var results = []; - - // Does the current object match the attribute conditions? - if (attributeNames.every((key) => typeof object[key] !== 'undefined')) { - results.push(object); - } - - // Diggin' deeper for each nested object (recursive) - Object.keys(object).forEach((key) => { - if (object[key] && typeof object[key] === 'object') { - results.push(...findNestedObjectsByAttributeNames(object[key], attributeNames)); - } - }); - - return results; - } - - function pageLoaded() { - if (document.readyState === 'complete') return Promise.resolve(); - - const deferred = new Deferred(); - - window.addEventListener('load', deferred.resolve, { once: true }); - - return deferred; - } - - function createDeepCopy(obj) { - return nativeJSONParse(JSON.stringify(obj)); - } - - function getYtcfgValue(name) { - var _window$ytcfg; - return (_window$ytcfg = window.ytcfg) === null || _window$ytcfg === void 0 ? void 0 : _window$ytcfg.get(name); - } - - function getSignatureTimestamp() { - return ( - getYtcfgValue('STS') - || (() => { - var _document$querySelect; - // STS is missing on embedded player. Retrieve from player base script as fallback... - const playerBaseJsPath = (_document$querySelect = document.querySelector('script[src*="/base.js"]')) === null || _document$querySelect === void 0 - ? void 0 - : _document$querySelect.src; - - if (!playerBaseJsPath) return; - - const xmlhttp = new XMLHttpRequest(); - xmlhttp.open('GET', playerBaseJsPath, false); - xmlhttp.send(null); - - return parseInt(xmlhttp.responseText.match(/signatureTimestamp:([0-9]*)/)[1]); - })() - ); - } - - function isUserLoggedIn() { - // LOGGED_IN doesn't exist on embedded page, use DELEGATED_SESSION_ID or SESSION_INDEX as fallback - if (typeof getYtcfgValue('LOGGED_IN') === 'boolean') return getYtcfgValue('LOGGED_IN'); - if (typeof getYtcfgValue('DELEGATED_SESSION_ID') === 'string') return true; - if (parseInt(getYtcfgValue('SESSION_INDEX')) >= 0) return true; - - return false; - } - - function getCurrentVideoStartTime(currentVideoId) { - // Check if the URL corresponds to the requested video - // This is not the case when the player gets preloaded for the next video in a playlist. - if (window.location.href.includes(currentVideoId)) { - var _ref; - // "t"-param on youtu.be urls - // "start"-param on embed player - // "time_continue" when clicking "watch on youtube" on embedded player - const urlParams = new URLSearchParams(window.location.search); - const startTimeString = (_ref = urlParams.get('t') || urlParams.get('start') || urlParams.get('time_continue')) === null || _ref === void 0 - ? void 0 - : _ref.replace('s', ''); - - if (startTimeString && !isNaN(startTimeString)) { - return parseInt(startTimeString); - } - } - - return 0; - } - - function setUrlParams(params) { - const urlParams = new URLSearchParams(window.location.search); - for (const paramName in params) { - urlParams.set(paramName, params[paramName]); - } - window.location.search = urlParams; - } - - function waitForElement(elementSelector, timeout) { - const deferred = new Deferred(); - - const checkDomInterval = setInterval(() => { - const elem = document.querySelector(elementSelector); - if (elem) { - clearInterval(checkDomInterval); - deferred.resolve(elem); - } - }, 100); - - if (timeout) { - setTimeout(() => { - clearInterval(checkDomInterval); - deferred.reject(); - }, timeout); - } - - return deferred; - } - - function parseRelativeUrl(url) { - if (typeof url !== 'string') { - return null; - } - - if (url.indexOf('/') === 0) { - url = window.location.origin + url; - } - - try { - return url.indexOf('https://') === 0 ? new window.URL(url) : null; - } catch { - return null; - } - } - - function isWatchNextObject(parsedData) { - var _parsedData$currentVi; - if ( - !(parsedData !== null && parsedData !== void 0 && parsedData.contents) - || !(parsedData !== null && parsedData !== void 0 && (_parsedData$currentVi = parsedData.currentVideoEndpoint) !== null && _parsedData$currentVi !== void 0 - && (_parsedData$currentVi = _parsedData$currentVi.watchEndpoint) !== null && _parsedData$currentVi !== void 0 && _parsedData$currentVi.videoId) - ) return false; - return !!parsedData.contents.twoColumnWatchNextResults || !!parsedData.contents.singleColumnWatchNextResults; - } - - function isWatchNextSidebarEmpty(parsedData) { - var _parsedData$contents2, _content$find; - if (isDesktop) { - var _parsedData$contents; - // WEB response layout - const result = (_parsedData$contents = parsedData.contents) === null || _parsedData$contents === void 0 - || (_parsedData$contents = _parsedData$contents.twoColumnWatchNextResults) === null || _parsedData$contents === void 0 - || (_parsedData$contents = _parsedData$contents.secondaryResults) === null || _parsedData$contents === void 0 - || (_parsedData$contents = _parsedData$contents.secondaryResults) === null || _parsedData$contents === void 0 - ? void 0 - : _parsedData$contents.results; - return !result; - } - - // MWEB response layout - const content = (_parsedData$contents2 = parsedData.contents) === null || _parsedData$contents2 === void 0 - || (_parsedData$contents2 = _parsedData$contents2.singleColumnWatchNextResults) === null || _parsedData$contents2 === void 0 - || (_parsedData$contents2 = _parsedData$contents2.results) === null || _parsedData$contents2 === void 0 - || (_parsedData$contents2 = _parsedData$contents2.results) === null || _parsedData$contents2 === void 0 - ? void 0 - : _parsedData$contents2.contents; - const result = content === null || content === void 0 || (_content$find = content.find((e) => { - var _e$itemSectionRendere; - return ((_e$itemSectionRendere = e.itemSectionRenderer) === null || _e$itemSectionRendere === void 0 ? void 0 : _e$itemSectionRendere.targetId) - === 'watch-next-feed'; - })) === null - || _content$find === void 0 - ? void 0 - : _content$find.itemSectionRenderer; - return typeof result !== 'object'; - } - - function isPlayerObject(parsedData) { - return (parsedData === null || parsedData === void 0 ? void 0 : parsedData.videoDetails) - && (parsedData === null || parsedData === void 0 ? void 0 : parsedData.playabilityStatus); - } - - function isEmbeddedPlayerObject(parsedData) { - return typeof (parsedData === null || parsedData === void 0 ? void 0 : parsedData.previewPlayabilityStatus) === 'object'; - } - - function isAgeRestricted(playabilityStatus) { - var _playabilityStatus$er; - if (!(playabilityStatus !== null && playabilityStatus !== void 0 && playabilityStatus.status)) return false; - if (playabilityStatus.desktopLegacyAgeGateReason) return true; - if (Config.UNLOCKABLE_PLAYABILITY_STATUSES.includes(playabilityStatus.status)) return true; - - // Fix to detect age restrictions on embed player - // see https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/issues/85#issuecomment-946853553 - return ( - isEmbed - && ((_playabilityStatus$er = playabilityStatus.errorScreen) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.playerErrorMessageRenderer) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.reason) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.runs) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.find((x) => x.navigationEndpoint)) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.navigationEndpoint) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.urlEndpoint) === null || _playabilityStatus$er === void 0 - || (_playabilityStatus$er = _playabilityStatus$er.url) === null || _playabilityStatus$er === void 0 - ? void 0 - : _playabilityStatus$er.includes('/2802167')) - ); - } - - function isSearchResult(parsedData) { - var _parsedData$contents3, _parsedData$contents4, _parsedData$onRespons; - return ( - typeof (parsedData === null || parsedData === void 0 || (_parsedData$contents3 = parsedData.contents) === null || _parsedData$contents3 === void 0 - ? void 0 - : _parsedData$contents3.twoColumnSearchResultsRenderer) === 'object' // Desktop initial results - || (parsedData === null || parsedData === void 0 || (_parsedData$contents4 = parsedData.contents) === null || _parsedData$contents4 === void 0 - || (_parsedData$contents4 = _parsedData$contents4.sectionListRenderer) === null || _parsedData$contents4 === void 0 - ? void 0 - : _parsedData$contents4.targetId) === 'search-feed' // Mobile initial results - || (parsedData === null || parsedData === void 0 || (_parsedData$onRespons = parsedData.onResponseReceivedCommands) === null || _parsedData$onRespons === void 0 - || (_parsedData$onRespons = _parsedData$onRespons.find((x) => x.appendContinuationItemsAction)) === null || _parsedData$onRespons === void 0 - || (_parsedData$onRespons = _parsedData$onRespons.appendContinuationItemsAction) === null || _parsedData$onRespons === void 0 - ? void 0 - : _parsedData$onRespons.targetId) === 'search-feed' // Desktop & Mobile scroll continuation - ); - } - - function attach$3(obj, prop, onCall) { - if (!obj || typeof obj[prop] !== 'function') { - return; - } - - let original = obj[prop]; - - obj[prop] = function() { - try { - onCall(arguments); - } catch {} - original.apply(this, arguments); - }; - } - - // Intercept, inspect and modify JSON-based communication to unlock player responses by hijacking the JSON.parse function - function attach$2(onJsonDataReceived) { - window.JSON.parse = function() { - const data = nativeJSONParse.apply(this, arguments); - return isObject(data) ? onJsonDataReceived(data) : data; - }; - } - - const logPrefix = '%cSimple-YouTube-Age-Restriction-Bypass:'; - const logPrefixStyle = 'background-color: #1e5c85; color: #fff; font-size: 1.2em;'; - const logSuffix = '\uD83D\uDC1E You can report bugs at: https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/issues'; - - function error(err, msg) { - console.error(logPrefix, logPrefixStyle, msg, err, getYtcfgDebugString(), '\n\n', logSuffix); - if (window.SYARB_CONFIG) { - window.dispatchEvent( - new CustomEvent('SYARB_LOG_ERROR', { - detail: { - message: (msg ? msg + '; ' : '') + (err && err.message ? err.message : ''), - stack: err && err.stack ? err.stack : null, - }, - }), - ); - } - } - - function info(msg) { - console.info(logPrefix, logPrefixStyle, msg); - if (window.SYARB_CONFIG) { - window.dispatchEvent( - new CustomEvent('SYARB_LOG_INFO', { - detail: { - message: msg, - }, - }), - ); - } - } - - function getYtcfgDebugString() { - try { - return ( - `InnertubeConfig: ` - + `innertubeApiKey: ${getYtcfgValue('INNERTUBE_API_KEY')} ` - + `innertubeClientName: ${getYtcfgValue('INNERTUBE_CLIENT_NAME')} ` - + `innertubeClientVersion: ${getYtcfgValue('INNERTUBE_CLIENT_VERSION')} ` - + `loggedIn: ${getYtcfgValue('LOGGED_IN')} ` - ); - } catch (err) { - return `Failed to access config: ${err}`; - } - } - - function attach$1(onRequestCreate) { - if (typeof window.Request !== 'function') { - return; - } - - window.Request = new Proxy(window.Request, { - construct(target, args) { - const [url, options] = args; - try { - const parsedUrl = parseRelativeUrl(url); - const modifiedUrl = onRequestCreate(parsedUrl, options); - - if (modifiedUrl) { - args[0] = modifiedUrl.toString(); - } - } catch (err) { - error(err, `Failed to intercept Request()`); - } - - return Reflect.construct(...arguments); - }, - }); - } - - function attach(onXhrOpenCalled) { - XMLHttpRequest.prototype.open = function(method, url) { - try { - let parsedUrl = parseRelativeUrl(url); - - if (parsedUrl) { - const modifiedUrl = onXhrOpenCalled(method, parsedUrl, this); - - if (modifiedUrl) { - arguments[1] = modifiedUrl.toString(); - } - } - } catch (err) { - error(err, `Failed to intercept XMLHttpRequest.open()`); - } - - nativeXMLHttpRequestOpen.apply(this, arguments); - }; - } - - const localStoragePrefix = 'SYARB_'; - - function set(key, value) { - localStorage.setItem(localStoragePrefix + key, JSON.stringify(value)); - } - - function get(key) { - try { - return JSON.parse(localStorage.getItem(localStoragePrefix + key)); - } catch { - return null; - } - } - - function getPlayer$1(payload, useAuth) { - return sendInnertubeRequest('v1/player', payload, useAuth); - } - - function getNext$1(payload, useAuth) { - return sendInnertubeRequest('v1/next', payload, useAuth); - } - - function sendInnertubeRequest(endpoint, payload, useAuth) { - const xmlhttp = new XMLHttpRequest(); - xmlhttp.open('POST', `/youtubei/${endpoint}?key=${getYtcfgValue('INNERTUBE_API_KEY')}&prettyPrint=false`, false); - - if (useAuth && isUserLoggedIn()) { - xmlhttp.withCredentials = true; - Config.GOOGLE_AUTH_HEADER_NAMES.forEach((headerName) => { - xmlhttp.setRequestHeader(headerName, get(headerName)); - }); - } - - xmlhttp.send(JSON.stringify(payload)); - return nativeJSONParse(xmlhttp.responseText); - } - - var innertube = { - getPlayer: getPlayer$1, - getNext: getNext$1, - }; - - let nextResponseCache = {}; - - function getGoogleVideoUrl(originalUrl) { - return Config.VIDEO_PROXY_SERVER_HOST + '/direct/' + btoa(originalUrl.toString()); - } - - function getPlayer(payload) { - // Also request the /next response if a later /next request is likely. - if (!nextResponseCache[payload.videoId] && !isMusic && !isEmbed) { - payload.includeNext = 1; - } - - return sendRequest('getPlayer', payload); - } - - function getNext(payload) { - // Next response already cached? => Return cached content - if (nextResponseCache[payload.videoId]) { - return nextResponseCache[payload.videoId]; - } - - return sendRequest('getNext', payload); - } - - function sendRequest(endpoint, payload) { - const queryParams = new URLSearchParams(payload); - const proxyUrl = `${Config.ACCOUNT_PROXY_SERVER_HOST}/${endpoint}?${queryParams}&client=js`; - - try { - const xmlhttp = new XMLHttpRequest(); - xmlhttp.open('GET', proxyUrl, false); - xmlhttp.send(null); - - const proxyResponse = nativeJSONParse(xmlhttp.responseText); - - // Mark request as 'proxied' - proxyResponse.proxied = true; - - // Put included /next response in the cache - if (proxyResponse.nextResponse) { - nextResponseCache[payload.videoId] = proxyResponse.nextResponse; - delete proxyResponse.nextResponse; - } - - return proxyResponse; - } catch (err) { - error(err, 'Proxy API Error'); - return { errorMessage: 'Proxy Connection failed' }; - } - } - - var proxy = { - getPlayer, - getNext, - getGoogleVideoUrl, - }; - - function getUnlockStrategies$1(videoId, lastPlayerUnlockReason) { - var _getYtcfgValue$client; - const clientName = getYtcfgValue('INNERTUBE_CLIENT_NAME') || 'WEB'; - const clientVersion = getYtcfgValue('INNERTUBE_CLIENT_VERSION') || '2.20220203.04.00'; - const hl = getYtcfgValue('HL'); - const userInterfaceTheme = (_getYtcfgValue$client = getYtcfgValue('INNERTUBE_CONTEXT').client.userInterfaceTheme) !== null && _getYtcfgValue$client !== void 0 - ? _getYtcfgValue$client - : document.documentElement.hasAttribute('dark') - ? 'USER_INTERFACE_THEME_DARK' - : 'USER_INTERFACE_THEME_LIGHT'; - - return [ - /** - * Retrieve the sidebar and video description by just adding `racyCheckOk` and `contentCheckOk` params - * This strategy can be used to bypass content warnings - */ - { - name: 'Content Warning Bypass', - skip: !lastPlayerUnlockReason || !lastPlayerUnlockReason.includes('CHECK_REQUIRED'), - optionalAuth: true, - payload: { - context: { - client: { - clientName, - clientVersion, - hl, - userInterfaceTheme, - }, - }, - videoId, - racyCheckOk: true, - contentCheckOk: true, - }, - endpoint: innertube, - }, - /** - * Retrieve the sidebar and video description from an account proxy server. - * Session cookies of an age-verified Google account are stored on server side. - * See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/tree/main/account-proxy - */ - { - name: 'Account Proxy', - payload: { - videoId, - clientName, - clientVersion, - hl, - userInterfaceTheme, - isEmbed: +isEmbed, - isConfirmed: +isConfirmed, - }, - endpoint: proxy, - }, - ]; - } - - function getUnlockStrategies(videoId, reason) { - const clientName = getYtcfgValue('INNERTUBE_CLIENT_NAME') || 'WEB'; - const clientVersion = getYtcfgValue('INNERTUBE_CLIENT_VERSION') || '2.20220203.04.00'; - const signatureTimestamp = getSignatureTimestamp(); - const startTimeSecs = getCurrentVideoStartTime(videoId); - const hl = getYtcfgValue('HL'); - - return [ - /** - * Retrieve the video info by just adding `racyCheckOk` and `contentCheckOk` params - * This strategy can be used to bypass content warnings - */ - { - name: 'Content Warning Bypass', - skip: !reason || !reason.includes('CHECK_REQUIRED'), - optionalAuth: true, - payload: { - context: { - client: { - clientName: clientName, - clientVersion: clientVersion, - hl, - }, - }, - playbackContext: { - contentPlaybackContext: { - signatureTimestamp, - }, - }, - videoId, - startTimeSecs, - racyCheckOk: true, - contentCheckOk: true, - }, - endpoint: innertube, - }, - /** - * Retrieve the video info by using the TVHTML5 Embedded client - * This client has no age restrictions in place (2022-03-28) - * See https://github.com/zerodytrash/YouTube-Internal-Clients - */ - { - name: 'TV Embedded Player', - requiresAuth: false, - payload: { - context: { - client: { - clientName: 'TVHTML5_SIMPLY_EMBEDDED_PLAYER', - clientVersion: '2.0', - clientScreen: 'WATCH', - hl, - }, - thirdParty: { - embedUrl: 'https://www.youtube.com/', - }, - }, - playbackContext: { - contentPlaybackContext: { - signatureTimestamp, - }, - }, - videoId, - startTimeSecs, - racyCheckOk: true, - contentCheckOk: true, - }, - endpoint: innertube, - }, - /** - * Retrieve the video info by using the WEB_CREATOR client in combination with user authentication - * Requires that the user is logged in. Can bypass the tightened age verification in the EU. - * See https://github.com/yt-dlp/yt-dlp/pull/600 - */ - { - name: 'Creator + Auth', - requiresAuth: true, - payload: { - context: { - client: { - clientName: 'WEB_CREATOR', - clientVersion: '1.20210909.07.00', - hl, - }, - }, - playbackContext: { - contentPlaybackContext: { - signatureTimestamp, - }, - }, - videoId, - startTimeSecs, - racyCheckOk: true, - contentCheckOk: true, - }, - endpoint: innertube, - }, - /** - * Retrieve the video info from an account proxy server. - * Session cookies of an age-verified Google account are stored on server side. - * See https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/tree/main/account-proxy - */ - { - name: 'Account Proxy', - payload: { - videoId, - reason, - clientName, - clientVersion, - signatureTimestamp, - startTimeSecs, - hl, - isEmbed: +isEmbed, - isConfirmed: +isConfirmed, - }, - endpoint: proxy, - }, - ]; - } - - var buttonTemplate = - '