1
0
mirror of https://github.com/pixeltris/TwitchAdSolutions.git synced 2024-11-22 02:12:45 +01:00

vaft improvements

Hybrid embed, proxy, fallback implementation
https://github.com/cleanlock/VideoAdBlockForTwitch/pull/63
This commit is contained in:
pixeltris 2022-08-27 15:32:21 +01:00
parent 010167aa03
commit 51ae5b1b6a
2 changed files with 317 additions and 165 deletions

View File

@ -62,16 +62,20 @@ twitch-videoad.js application/javascript
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
scope.ClientVersion = 'null';
scope.ClientSession = 'null';
scope.PlayerType1 = 'site'; //Source
scope.PlayerType2 = 'thunderdome'; //480p
scope.PlayerType3 = 'pop_tart'; //480p
scope.PlayerType4 = 'picture-by-picture'; //360p
//scope.PlayerType1 = 'site'; //Source - NOTE: This is unused as it's implicitly used by the website iself
scope.PlayerType2 = 'embed'; //Source
scope.PlayerType3 = 'proxy'; //Source
scope.PlayerType4 = 'thunderdome'; //480p
scope.CurrentChannelName = null;
scope.UsherParams = null;
scope.WasShowingAd = false;
scope.GQLDeviceID = null;
scope.HideBlockingMessage = false;
scope.IsSquadStream = false;
scope.StreamInfos = [];
scope.StreamInfosByUrl = [];
scope.MainUrlByUrl = [];
scope.EncodingCacheTimeout = 60000;
}
declareOptions(window);
var twitchMainWorker = null;
@ -91,7 +95,9 @@ twitch-videoad.js application/javascript
return;
}
var newBlobStr = `
${getNewUsher.toString()}
${getStreamUrlForResolution.toString()}
${getStreamForResolution.toString()}
${stripUnusedParams.toString()}
${processM3U8.toString()}
${hookWorkerFetch.toString()}
${declareOptions.toString()}
@ -142,6 +148,9 @@ twitch-videoad.js application/javascript
} else if (e.data.key == 'ForceChangeQuality') {
//This is used to fix the bug where the video would freeze.
try {
if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) {
return;
}
var autoQuality = doTwitchPlayerTask(false, false, false, true, false);
var currentQuality = doTwitchPlayerTask(false, true, false, false, false);
if (IsPlayerAutoQuality == null) {
@ -253,6 +262,7 @@ twitch-videoad.js application/javascript
return req.responseText.split("'")[1];
}
function hookWorkerFetch() {
console.log('Twitch adblocker is enabled');
var realFetch = fetch;
fetch = async function(url, options) {
if (typeof url === 'string') {
@ -289,26 +299,31 @@ twitch-videoad.js application/javascript
if (isPBYPRequest) {
url = '';
}
//Make new Usher request if needed to create fallback if UBlock bypass method fails.
var useNewUsher = false;
if (url.includes('subscriber%22%3Afalse') && url.includes('hide_ads%22%3Afalse') && url.includes('show_ads%22%3Atrue')) {
useNewUsher = true;
}
if (url.includes('subscriber%22%3Atrue') && url.includes('hide_ads%22%3Afalse') && url.includes('show_ads%22%3Atrue')) {
useNewUsher = true;
}
if (useNewUsher == true) {
return new Promise(function(resolve, reject) {
var processAfter = async function(response) {
encodingsM3u8 = await getNewUsher(realFetch, response, channelName);
if (encodingsM3u8.length > 1) {
resolve(new Response(encodingsM3u8));
} else {
postMessage({
key: 'HideAdBlockBanner'
});
resolve(encodingsM3u8);
encodingsM3u8 = await response.text();
var streamInfo = StreamInfos[channelName];
if (streamInfo == null) {
StreamInfos[channelName] = streamInfo = {};
}
streamInfo.ChannelName = channelName;
streamInfo.Urls = [];// xxx.m3u8 -> "284x160" (resolution)
streamInfo.EncodingsM3U8Cache = [];
var lines = encodingsM3u8.replace('\r', '').split('\n');
for (var i = 0; i < lines.length; i++) {
if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) {
streamInfo.Urls[lines[i]] = -1;
if (i > 0 && lines[i - 1].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(lines[i - 1])['RESOLUTION'];
if (res) {
streamInfo.Urls[lines[i]] = res;
}
}
StreamInfosByUrl[lines[i]] = streamInfo;
MainUrlByUrl[lines[i]] = url;
}
}
resolve(new Response(encodingsM3u8));
};
var send = function() {
return realFetch(url, options).then(function(response) {
@ -321,67 +336,39 @@ twitch-videoad.js application/javascript
});
}
}
}
return realFetch.apply(this, arguments);
};
}
//Added as fallback for when UBlock method fails.
async function getNewUsher(realFetch, originalResponse, channelName) {
var accessTokenResponse = await getAccessToken(channelName, PlayerType1);
var encodingsM3u8 = '';
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + channelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
encodingsM3u8 = await encodingsM3u8Response.text();
return encodingsM3u8;
} else {
return originalResponse;
function getStreamUrlForResolution(targetResolution, encodingsM3u8) {
var encodingsLines = encodingsM3u8.replace('\r', '').split('\n');
var firstUrl = null;
for (var i = 0; i < encodingsLines.length; i++) {
if (!encodingsLines[i].startsWith('#') && encodingsLines[i].includes('.m3u8')) {
if (i > 0 && encodingsLines[i - 1].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(encodingsLines[i - 1])['RESOLUTION'];
if (res && (!targetResolution || res == targetResolution)) {
return encodingsLines[i];
}
} catch (err) {}
return originalResponse;
} else {
return originalResponse;
if (firstUrl == null) {
firstUrl = encodingsLines[i];
}
}
async function processM3U8(url, textStr, realFetch, playerType) {
//Checks the m3u8 for ads and if it finds one, instead returns an ad-free stream.
//Ad blocking for squad streams is disabled due to the way multiple weaver urls are used. No workaround so far.
if (IsSquadStream == true) {
return textStr;
}
if (!textStr) {
return textStr;
}
//Some live streams use mp4.
if (!textStr.includes(".ts") && !textStr.includes(".mp4")) {
return textStr;
return firstUrl;
}
var haveAdTags = textStr.includes(AdSignifier);
if (haveAdTags) {
//Reduces ad frequency.
try {
tryNotifyTwitch(textStr);
} catch (err) {}
var accessTokenResponse = await getAccessToken(CurrentChannelName, playerType);
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + CurrentChannelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
var encodingsM3u8 = await encodingsM3u8Response.text();
streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/mg)[0];
async function getStreamForResolution(streamInfo, targetResolution, encodingsM3u8, fallbackStreamStr, playerType, realFetch) {
if (streamInfo.EncodingsM3U8Cache[playerType].Resolution != targetResolution ||
streamInfo.EncodingsM3U8Cache[playerType].RequestTime < Date.now() - EncodingCacheTimeout) {
console.log(`Blocking ads (type:${playerType}, resolution:${targetResolution})`);
}
streamInfo.EncodingsM3U8Cache[playerType].RequestTime = Date.now();
streamInfo.EncodingsM3U8Cache[playerType].Value = encodingsM3u8;
streamInfo.EncodingsM3U8Cache[playerType].Resolution = targetResolution;
var streamM3u8Url = getStreamUrlForResolution(targetResolution, encodingsM3u8);
var streamM3u8Response = await realFetch(streamM3u8Url);
if (streamM3u8Response.status == 200) {
var m3u8Text = await streamM3u8Response.text();
console.log("Blocking ads...");
WasShowingAd = true;
if (HideBlockingMessage == false) {
postMessage({
@ -395,10 +382,99 @@ twitch-videoad.js application/javascript
postMessage({
key: 'ForceChangeQuality'
});
if (!m3u8Text || m3u8Text.includes(AdSignifier)) {
streamInfo.EncodingsM3U8Cache[playerType].Value = null;
}
return m3u8Text;
} else {
streamInfo.EncodingsM3U8Cache[playerType].Value = null;
return fallbackStreamStr;
}
}
function stripUnusedParams(str, params) {
if (!params) {
params = [ 'token', 'sig' ];
}
var tempUrl = new URL('https://localhost/' + str);
for (var i = 0; i < params.length; i++) {
tempUrl.searchParams.delete(params[i]);
}
return tempUrl.pathname.substring(1) + tempUrl.search;
}
async function processM3U8(url, textStr, realFetch, playerType) {
//Checks the m3u8 for ads and if it finds one, instead returns an ad-free stream.
var streamInfo = StreamInfosByUrl[url];
//Ad blocking for squad streams is disabled due to the way multiple weaver urls are used. No workaround so far.
if (IsSquadStream == true) {
return textStr;
}
if (!textStr) {
return textStr;
}
//Some live streams use mp4.
if (!textStr.includes(".ts") && !textStr.includes(".mp4")) {
return textStr;
}
var haveAdTags = textStr.includes(AdSignifier);
if (haveAdTags) {
var isMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"');
//Reduces ad frequency. TODO: Reduce the number of requests. This is really spamming Twitch with requests.
if (!isMidroll) {
try {
tryNotifyTwitch(textStr);
} catch (err) {}
}
var currentResolution = null;
if (streamInfo && streamInfo.Urls) {
for (const [resUrl, resName] of Object.entries(streamInfo.Urls)) {
if (resUrl == url) {
currentResolution = resName;
//console.log(resName);
break;
}
}
}
// Keep the m3u8 around for a little while (once per ad) before requesting a new one
var encodingsM3U8Cache = streamInfo.EncodingsM3U8Cache[playerType];
if (encodingsM3U8Cache) {
if (encodingsM3U8Cache.Value && encodingsM3U8Cache.RequestTime >= Date.now() - EncodingCacheTimeout) {
try {
var result = getStreamForResolution(streamInfo, currentResolution, encodingsM3U8Cache.Value, null, playerType, realFetch);
if (result) {
return result;
}
} catch (err) {
encodingsM3U8Cache.Value = null;
}
}
} else {
streamInfo.EncodingsM3U8Cache[playerType] = {
RequestTime: Date.now(),
Value: null,
Resolution: null
};
}
if (playerType === 'proxy') {
try {
/*var tempUrl = stripUnusedParams(MainUrlByUrl[url]);
const match = /(hls|vod)\/(.+?)$/gim.exec(tempUrl);*/
var encodingsM3u8Response = await realFetch('https://api.ttv.lol/playlist/' + CurrentChannelName + '.m3u8%3Fallow_source%3Dtrue'/* + encodeURIComponent(match[2])*/, {headers: {'X-Donate-To': 'https://ttv.lol/donate'}});
if (encodingsM3u8Response.status === 200) {
return getStreamForResolution(streamInfo, currentResolution, await encodingsM3u8Response.text(), textStr, playerType, realFetch);
}
} catch (err) {}
return textStr;
}
var accessTokenResponse = await getAccessToken(CurrentChannelName, playerType);
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + CurrentChannelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
return getStreamForResolution(streamInfo, currentResolution, await encodingsM3u8Response.text(), textStr, playerType, realFetch);
} else {
return textStr;
}

View File

@ -1,7 +1,7 @@
// ==UserScript==
// @name TwitchAdSolutions (vaft)
// @namespace https://github.com/pixeltris/TwitchAdSolutions
// @version 5.4.0
// @version 5.4.0-f1
// @description Multiple solutions for blocking Twitch ads (vaft)
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/vaft/vaft.user.js
@ -73,16 +73,20 @@
scope.ClientID = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
scope.ClientVersion = 'null';
scope.ClientSession = 'null';
scope.PlayerType1 = 'site'; //Source
scope.PlayerType2 = 'thunderdome'; //480p
scope.PlayerType3 = 'pop_tart'; //480p
scope.PlayerType4 = 'picture-by-picture'; //360p
//scope.PlayerType1 = 'site'; //Source - NOTE: This is unused as it's implicitly used by the website iself
scope.PlayerType2 = 'embed'; //Source
scope.PlayerType3 = 'proxy'; //Source
scope.PlayerType4 = 'thunderdome'; //480p
scope.CurrentChannelName = null;
scope.UsherParams = null;
scope.WasShowingAd = false;
scope.GQLDeviceID = null;
scope.HideBlockingMessage = false;
scope.IsSquadStream = false;
scope.StreamInfos = [];
scope.StreamInfosByUrl = [];
scope.MainUrlByUrl = [];
scope.EncodingCacheTimeout = 60000;
}
declareOptions(window);
var twitchMainWorker = null;
@ -102,7 +106,9 @@
return;
}
var newBlobStr = `
${getNewUsher.toString()}
${getStreamUrlForResolution.toString()}
${getStreamForResolution.toString()}
${stripUnusedParams.toString()}
${processM3U8.toString()}
${hookWorkerFetch.toString()}
${declareOptions.toString()}
@ -153,6 +159,9 @@
} else if (e.data.key == 'ForceChangeQuality') {
//This is used to fix the bug where the video would freeze.
try {
if (navigator.userAgent.toLowerCase().indexOf('firefox') == -1) {
return;
}
var autoQuality = doTwitchPlayerTask(false, false, false, true, false);
var currentQuality = doTwitchPlayerTask(false, true, false, false, false);
if (IsPlayerAutoQuality == null) {
@ -264,6 +273,7 @@
return req.responseText.split("'")[1];
}
function hookWorkerFetch() {
console.log('Twitch adblocker is enabled');
var realFetch = fetch;
fetch = async function(url, options) {
if (typeof url === 'string') {
@ -300,26 +310,31 @@
if (isPBYPRequest) {
url = '';
}
//Make new Usher request if needed to create fallback if UBlock bypass method fails.
var useNewUsher = false;
if (url.includes('subscriber%22%3Afalse') && url.includes('hide_ads%22%3Afalse') && url.includes('show_ads%22%3Atrue')) {
useNewUsher = true;
}
if (url.includes('subscriber%22%3Atrue') && url.includes('hide_ads%22%3Afalse') && url.includes('show_ads%22%3Atrue')) {
useNewUsher = true;
}
if (useNewUsher == true) {
return new Promise(function(resolve, reject) {
var processAfter = async function(response) {
encodingsM3u8 = await getNewUsher(realFetch, response, channelName);
if (encodingsM3u8.length > 1) {
resolve(new Response(encodingsM3u8));
} else {
postMessage({
key: 'HideAdBlockBanner'
});
resolve(encodingsM3u8);
encodingsM3u8 = await response.text();
var streamInfo = StreamInfos[channelName];
if (streamInfo == null) {
StreamInfos[channelName] = streamInfo = {};
}
streamInfo.ChannelName = channelName;
streamInfo.Urls = [];// xxx.m3u8 -> "284x160" (resolution)
streamInfo.EncodingsM3U8Cache = [];
var lines = encodingsM3u8.replace('\r', '').split('\n');
for (var i = 0; i < lines.length; i++) {
if (!lines[i].startsWith('#') && lines[i].includes('.m3u8')) {
streamInfo.Urls[lines[i]] = -1;
if (i > 0 && lines[i - 1].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(lines[i - 1])['RESOLUTION'];
if (res) {
streamInfo.Urls[lines[i]] = res;
}
}
StreamInfosByUrl[lines[i]] = streamInfo;
MainUrlByUrl[lines[i]] = url;
}
}
resolve(new Response(encodingsM3u8));
};
var send = function() {
return realFetch(url, options).then(function(response) {
@ -332,67 +347,39 @@
});
}
}
}
return realFetch.apply(this, arguments);
};
}
//Added as fallback for when UBlock method fails.
async function getNewUsher(realFetch, originalResponse, channelName) {
var accessTokenResponse = await getAccessToken(channelName, PlayerType1);
var encodingsM3u8 = '';
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + channelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
encodingsM3u8 = await encodingsM3u8Response.text();
return encodingsM3u8;
} else {
return originalResponse;
function getStreamUrlForResolution(targetResolution, encodingsM3u8) {
var encodingsLines = encodingsM3u8.replace('\r', '').split('\n');
var firstUrl = null;
for (var i = 0; i < encodingsLines.length; i++) {
if (!encodingsLines[i].startsWith('#') && encodingsLines[i].includes('.m3u8')) {
if (i > 0 && encodingsLines[i - 1].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(encodingsLines[i - 1])['RESOLUTION'];
if (res && (!targetResolution || res == targetResolution)) {
return encodingsLines[i];
}
} catch (err) {}
return originalResponse;
} else {
return originalResponse;
if (firstUrl == null) {
firstUrl = encodingsLines[i];
}
}
async function processM3U8(url, textStr, realFetch, playerType) {
//Checks the m3u8 for ads and if it finds one, instead returns an ad-free stream.
//Ad blocking for squad streams is disabled due to the way multiple weaver urls are used. No workaround so far.
if (IsSquadStream == true) {
return textStr;
}
if (!textStr) {
return textStr;
}
//Some live streams use mp4.
if (!textStr.includes(".ts") && !textStr.includes(".mp4")) {
return textStr;
return firstUrl;
}
var haveAdTags = textStr.includes(AdSignifier);
if (haveAdTags) {
//Reduces ad frequency.
try {
tryNotifyTwitch(textStr);
} catch (err) {}
var accessTokenResponse = await getAccessToken(CurrentChannelName, playerType);
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + CurrentChannelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
var encodingsM3u8 = await encodingsM3u8Response.text();
streamM3u8Url = encodingsM3u8.match(/^https:.*\.m3u8$/mg)[0];
async function getStreamForResolution(streamInfo, targetResolution, encodingsM3u8, fallbackStreamStr, playerType, realFetch) {
if (streamInfo.EncodingsM3U8Cache[playerType].Resolution != targetResolution ||
streamInfo.EncodingsM3U8Cache[playerType].RequestTime < Date.now() - EncodingCacheTimeout) {
console.log(`Blocking ads (type:${playerType}, resolution:${targetResolution})`);
}
streamInfo.EncodingsM3U8Cache[playerType].RequestTime = Date.now();
streamInfo.EncodingsM3U8Cache[playerType].Value = encodingsM3u8;
streamInfo.EncodingsM3U8Cache[playerType].Resolution = targetResolution;
var streamM3u8Url = getStreamUrlForResolution(targetResolution, encodingsM3u8);
var streamM3u8Response = await realFetch(streamM3u8Url);
if (streamM3u8Response.status == 200) {
var m3u8Text = await streamM3u8Response.text();
console.log("Blocking ads...");
WasShowingAd = true;
if (HideBlockingMessage == false) {
postMessage({
@ -406,10 +393,99 @@
postMessage({
key: 'ForceChangeQuality'
});
if (!m3u8Text || m3u8Text.includes(AdSignifier)) {
streamInfo.EncodingsM3U8Cache[playerType].Value = null;
}
return m3u8Text;
} else {
streamInfo.EncodingsM3U8Cache[playerType].Value = null;
return fallbackStreamStr;
}
}
function stripUnusedParams(str, params) {
if (!params) {
params = [ 'token', 'sig' ];
}
var tempUrl = new URL('https://localhost/' + str);
for (var i = 0; i < params.length; i++) {
tempUrl.searchParams.delete(params[i]);
}
return tempUrl.pathname.substring(1) + tempUrl.search;
}
async function processM3U8(url, textStr, realFetch, playerType) {
//Checks the m3u8 for ads and if it finds one, instead returns an ad-free stream.
var streamInfo = StreamInfosByUrl[url];
//Ad blocking for squad streams is disabled due to the way multiple weaver urls are used. No workaround so far.
if (IsSquadStream == true) {
return textStr;
}
if (!textStr) {
return textStr;
}
//Some live streams use mp4.
if (!textStr.includes(".ts") && !textStr.includes(".mp4")) {
return textStr;
}
var haveAdTags = textStr.includes(AdSignifier);
if (haveAdTags) {
var isMidroll = textStr.includes('"MIDROLL"') || textStr.includes('"midroll"');
//Reduces ad frequency. TODO: Reduce the number of requests. This is really spamming Twitch with requests.
if (!isMidroll) {
try {
tryNotifyTwitch(textStr);
} catch (err) {}
}
var currentResolution = null;
if (streamInfo && streamInfo.Urls) {
for (const [resUrl, resName] of Object.entries(streamInfo.Urls)) {
if (resUrl == url) {
currentResolution = resName;
//console.log(resName);
break;
}
}
}
// Keep the m3u8 around for a little while (once per ad) before requesting a new one
var encodingsM3U8Cache = streamInfo.EncodingsM3U8Cache[playerType];
if (encodingsM3U8Cache) {
if (encodingsM3U8Cache.Value && encodingsM3U8Cache.RequestTime >= Date.now() - EncodingCacheTimeout) {
try {
var result = getStreamForResolution(streamInfo, currentResolution, encodingsM3U8Cache.Value, null, playerType, realFetch);
if (result) {
return result;
}
} catch (err) {
encodingsM3U8Cache.Value = null;
}
}
} else {
streamInfo.EncodingsM3U8Cache[playerType] = {
RequestTime: Date.now(),
Value: null,
Resolution: null
};
}
if (playerType === 'proxy') {
try {
/*var tempUrl = stripUnusedParams(MainUrlByUrl[url]);
const match = /(hls|vod)\/(.+?)$/gim.exec(tempUrl);*/
var encodingsM3u8Response = await realFetch('https://api.ttv.lol/playlist/' + CurrentChannelName + '.m3u8%3Fallow_source%3Dtrue'/* + encodeURIComponent(match[2])*/, {headers: {'X-Donate-To': 'https://ttv.lol/donate'}});
if (encodingsM3u8Response.status === 200) {
return getStreamForResolution(streamInfo, currentResolution, await encodingsM3u8Response.text(), textStr, playerType, realFetch);
}
} catch (err) {}
return textStr;
}
var accessTokenResponse = await getAccessToken(CurrentChannelName, playerType);
if (accessTokenResponse.status === 200) {
var accessToken = await accessTokenResponse.json();
try {
var urlInfo = new URL('https://usher.ttvnw.net/api/channel/hls/' + CurrentChannelName + '.m3u8' + UsherParams);
urlInfo.searchParams.set('sig', accessToken.data.streamPlaybackAccessToken.signature);
urlInfo.searchParams.set('token', accessToken.data.streamPlaybackAccessToken.value);
var encodingsM3u8Response = await realFetch(urlInfo.href);
if (encodingsM3u8Response.status === 200) {
return getStreamForResolution(streamInfo, currentResolution, await encodingsM3u8Response.text(), textStr, playerType, realFetch);
} else {
return textStr;
}