Professional Documents
Culture Documents
// The following proxies are currently used as fallback if the innertube age-
gate bypass doesn't work...
// You can host your own account proxy instance. See
https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-Bypass/tree/main/
account-proxy
const ACCOUNT_PROXY_SERVER_HOST = "https://youtube-proxy.zerody.one";
const VIDEO_PROXY_SERVER_HOST = "https://phx.4everproxy.com";
let wrappedPlayerResponse;
let wrappedNextResponse;
let lastProxiedGoogleVideoUrlParams;
let responseCache = {};
function init() {
document.body.append(node);
pageLoad.resolve();
}
pageLoad.then(_show);
function _show() {
if (isPolymer) {
node.duration = duration * 1000;
node.show(message);
} else {
nMobileText.innerHTML = message;
node.setAttribute('dir', 'in');
setTimeout(() => {
node.setAttribute('dir', 'out');
}, duration * 1000 + 225);
}
}
}
return { show };
})();
wrappedPlayerResponse = inspectJsonData(playerResponse);
if (typeof chainedPlayerSetter === "function")
chainedPlayerSetter(wrappedPlayerResponse);
},
get: () => {
if (typeof chainedPlayerGetter === "function") try { return
chainedPlayerGetter() } catch (err) { };
return wrappedPlayerResponse || {};
},
configurable: true,
});
function isGoogleVideo() {
return method === "GET" && url.host.indexOf(".googlevideo.com") >
0;
}
function hasGcrFlag() {
return urlParams.get("gcr") !== null;
}
function isUnlockedByAccountProxy() {
return urlParams.get("id") !== null && urlParams.get("id") ===
lastProxiedGoogleVideoUrlParams?.get("id");
}
function inspectJsonData(parsedData) {
// If YouTube does JSON.parse(null) or similar weird things
if (typeof parsedData !== "object" || parsedData === null) return
parsedData;
try {
// Unlock #1: Array based in "&pbj=1" AJAX response on any navigation
(does not seem to be used anymore)
if (Array.isArray(parsedData)) {
const { playerResponse } = parsedData.find(e => typeof
e.playerResponse === "object") || {};
if (playerResponse &&
isAgeRestricted(playerResponse.playabilityStatus)) {
playerResponseArrayItem.playerResponse =
unlockPlayerResponse(playerResponse);
// Unlock #3: Initial page data structure and response from the
'/youtubei/v1/player' endpoint
if (parsedData.playabilityStatus && parsedData.videoDetails &&
isAgeRestricted(parsedData.playabilityStatus)) {
parsedData = unlockPlayerResponse(parsedData);
}
return parsedData;
}
function isAgeRestricted(playabilityStatus) {
if (!playabilityStatus?.status) return false;
return !!playabilityStatus.desktopLegacyAgeGateReason ||
UNLOCKABLE_PLAYER_STATES.includes(playabilityStatus.status);
}
function isWatchNextObject(parsedData) {
if (!parsedData?.contents || !
parsedData?.currentVideoEndpoint?.watchEndpoint?.videoId) return false;
return !!parsedData.contents.twoColumnWatchNextResults || !!
parsedData.contents.singleColumnWatchNextResults;
}
function isWatchNextSidebarEmpty(contents) {
const secondaryResults =
contents.twoColumnWatchNextResults?.secondaryResults?.secondaryResults;
if (secondaryResults?.results) return false;
return !!itemSectionRenderer;
}
function isLoggedIn() {
setInnertubeConfigFromYtcfg();
return INNERTUBE_CONFIG.LOGGED_IN;
}
function unlockPlayerResponse(playerResponse) {
const videoId = playerResponse.videoDetails.videoId;
const reason = playerResponse.playabilityStatus?.status;
const unlockedPayerResponse = getUnlockedPlayerResponse(videoId, reason);
// if the video info was retrieved via proxy, store the URL params from the
url- or signatureCipher-attribute to detect later if the requested video files are
from this unlock.
// => see isUnlockedByAccountProxy()
if (unlockedPayerResponse.proxied &&
unlockedPayerResponse.streamingData?.adaptiveFormats) {
const cipherText =
unlockedPayerResponse.streamingData.adaptiveFormats.find(x =>
x.signatureCipher)?.signatureCipher;
const videoUrl = cipherText ? new
URLSearchParams(cipherText).get("url") :
unlockedPayerResponse.streamingData.adaptiveFormats.find(x => x.url)?.url;
return unlockedPayerResponse;
}
function unlockNextResponse(nextResponse) {
const { videoId, playlistId, index: playlistIndex } =
nextResponse.currentVideoEndpoint.watchEndpoint;
const unlockedNextResponse = getUnlockedNextResponse(videoId, playlistId,
playlistIndex);
if (originalVideoSecondaryInfoRenderer &&
unlockedVideoSecondaryInfoRenderer?.description)
originalVideoSecondaryInfoRenderer.description =
unlockedVideoSecondaryInfoRenderer.description;
if (originalStructuredDescriptionContentRenderer &&
unlockedStructuredDescriptionContentRenderer?.expandableVideoDescriptionBodyRendere
r)
originalStructuredDescriptionContentRenderer.expandableVideoDescriptionBodyRenderer
=
unlockedStructuredDescriptionContentRenderer.expandableVideoDescriptionBodyRenderer
;
return nextResponse;
}
setInnertubeConfigFromYtcfg();
return playerResponse;
// Strategy 1: Retrieve the video info by using a age-gate bypass for the
innertube API
// Source: https://github.com/yt-dlp/yt-dlp/issues/574#issuecomment-
887171136
function useInnertubeEmbed() {
console.info("Simple-YouTube-Age-Restriction-Bypass: Trying Unlock
Method #1 (Innertube Embed)");
const payload = getInnertubeEmbedPayload(videoId);
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", `/youtubei/v1/player?key=$
{INNERTUBE_CONFIG.INNERTUBE_API_KEY}`, false); // Synchronous!!!
xmlhttp.send(JSON.stringify(payload));
return nativeParse(xmlhttp.responseText);
}
// Retrieve the video info by using a age-gate bypass for the innertube API
// Source: https://github.com/zerodytrash/Simple-YouTube-Age-Restriction-
Bypass/issues/16#issuecomment-889232425
console.info("Simple-YouTube-Age-Restriction-Bypass: Trying Sidebar Unlock
Method (Innertube Embed)");
const payload = getInnertubeEmbedPayload(videoId, playlistId,
playlistIndex);
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", `/youtubei/v1/next?key=$
{INNERTUBE_CONFIG.INNERTUBE_API_KEY}`, false); // Synchronous!!!
xmlhttp.send(JSON.stringify(payload));
return nativeParse(xmlhttp.responseText);
}
return data;
}
// to avoid version conflicts between client and server response, the current
YouTube version config will be determined
function setInnertubeConfigFromYtcfg() {
if (!window.ytcfg) {
console.warn("Simple-YouTube-Age-Restriction-Bypass: Unable to retrieve
global YouTube configuration (window.ytcfg). Using old values...");
return;
}
const nativeDefineProperty =
tempFrame?.contentWindow?.Object?.defineProperty;
tempFrame.remove();
if (nativeDefineProperty) {
console.info("Simple-YouTube-Age-Restriction-Bypass: Overidden
Object.defineProperty function successfully restored!");
return nativeDefineProperty;
} else {
console.warn("Simple-YouTube-Age-Restriction-Bypass: Unable to restore
the original Object.defineProperty function");
return Object.defineProperty;
}
}