video-swap-new - initial fix for 2k/4k streams on chrome based browsers (error 4000 fix)

This commit is contained in:
pixeltris
2025-10-23 21:04:18 +01:00
parent b85834ff55
commit 61c634b379
2 changed files with 33 additions and 7 deletions
+16 -3
View File
@@ -1,7 +1,7 @@
twitch-videoad.js text/javascript twitch-videoad.js text/javascript
(function() { (function() {
if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; } if ( /(^|\.)twitch\.tv$/.test(document.location.hostname) === false ) { return; }
var ourTwitchAdSolutionsVersion = 12;// Used to prevent conflicts with outdated versions of the scripts var ourTwitchAdSolutionsVersion = 13;// Used to prevent conflicts with outdated versions of the scripts
if (typeof unsafeWindow === 'undefined') { if (typeof unsafeWindow === 'undefined') {
unsafeWindow = window; unsafeWindow = window;
} }
@@ -280,12 +280,14 @@ twitch-videoad.js text/javascript
// TODO: Do a better matching up of the resolutions rather than picking the highest low res for all // TODO: Do a better matching up of the resolutions rather than picking the highest low res for all
var lowResLines = encodingsM3u8.replace('\r', '').split('\n'); var lowResLines = encodingsM3u8.replace('\r', '').split('\n');
var lowResBestUrl = null; var lowResBestUrl = null;
var lowResSettings = [];
for (var j = 0; j < lowResLines.length; j++) { for (var j = 0; j < lowResLines.length; j++) {
if (lowResLines[j].startsWith('#EXT-X-STREAM-INF')) { if (lowResLines[j].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(lowResLines[j])['RESOLUTION']; var res = parseAttributes(lowResLines[j])['RESOLUTION'];
if (res && lowResLines[j + 1].endsWith('.m3u8')) { if (res && lowResLines[j + 1].endsWith('.m3u8')) {
// Assumes resolutions are correctly ordered // Assumes resolutions are correctly ordered
lowResBestUrl = lowResLines[j + 1]; lowResBestUrl = lowResLines[j + 1];
lowResSettings = parseAttributes(lowResLines[j].substring(lowResLines[j].indexOf(':') + 1));
break; break;
} }
} }
@@ -295,6 +297,17 @@ twitch-videoad.js text/javascript
var normalLines = normalEncodingsM3u8.replace('\r', '').split('\n'); var normalLines = normalEncodingsM3u8.replace('\r', '').split('\n');
for (var j = 0; j < normalLines.length - 1; j++) { for (var j = 0; j < normalLines.length - 1; j++) {
if (normalLines[j].startsWith('#EXT-X-STREAM-INF')) { if (normalLines[j].startsWith('#EXT-X-STREAM-INF')) {
var resSettings = parseAttributes(normalLines[j].substring(normalLines[j].indexOf(':') + 1));
const codecsKey = 'CODECS';
if (typeof resSettings[codecsKey] === 'string' && typeof lowResSettings[codecsKey] === 'string' &&
resSettings[codecsKey].length >= 3 && lowResSettings[codecsKey].length >= 3 &&
resSettings[codecsKey].substring(0, 3) === 'hev' &&
resSettings[codecsKey].substring(0, 3) !== lowResSettings[codecsKey].substring(0, 3)
) {
console.log('swap ' + resSettings[codecsKey] + ' to ' + lowResSettings[codecsKey]);
normalLines[j] = normalLines[j].replace(/CODECS="[^"]+"/, `CODECS="${lowResSettings[codecsKey]}"`);
console.log(normalLines[j]);
}
var res = parseAttributes(normalLines[j])['RESOLUTION']; var res = parseAttributes(normalLines[j])['RESOLUTION'];
if (res) { if (res) {
lowResBestUrl += ' ';// The stream doesn't load unless each url line is unique lowResBestUrl += ' ';// The stream doesn't load unless each url line is unique
@@ -334,7 +347,7 @@ twitch-videoad.js text/javascript
return textStr; return textStr;
} }
var haveAdTags = textStr.includes(AD_SIGNIFIER); var haveAdTags = textStr.includes(AD_SIGNIFIER);
if (SimulatedAdsDepth && (!streamInfo.BackupEncodings || !streamInfo.BackupEncodings.includes(url) || SimulatedAdsDepth - 1 > streamInfo.BackupEncodingsPlayerTypeIndex)) { if (SimulatedAdsDepth > 0 && (!streamInfo.BackupEncodings || !streamInfo.BackupEncodings.includes(url) || SimulatedAdsDepth - 1 > streamInfo.BackupEncodingsPlayerTypeIndex)) {
haveAdTags = true; haveAdTags = true;
} }
if (streamInfo.BackupEncodings) { if (streamInfo.BackupEncodings) {
@@ -343,7 +356,7 @@ twitch-videoad.js text/javascript
if (streamM3u8Response.status == 200) { if (streamM3u8Response.status == 200) {
var streamM3u8 = await streamM3u8Response.text(); var streamM3u8 = await streamM3u8Response.text();
if (streamM3u8 != null) { if (streamM3u8 != null) {
if (!streamM3u8.includes(AD_SIGNIFIER) && !SimulatedAdsDepth) { if (!streamM3u8.includes(AD_SIGNIFIER) && SimulatedAdsDepth == 0) {
console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); console.log('No more ads on main stream. Triggering player reload to go back to main stream...');
streamInfo.IsMovingOffBackupEncodings = true; streamInfo.IsMovingOffBackupEncodings = true;
streamInfo.BackupEncodings = null; streamInfo.BackupEncodings = null;
+17 -4
View File
@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name TwitchAdSolutions (video-swap-new) // @name TwitchAdSolutions (video-swap-new)
// @namespace https://github.com/pixeltris/TwitchAdSolutions // @namespace https://github.com/pixeltris/TwitchAdSolutions
// @version 1.44 // @version 1.45
// @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js // @updateURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
// @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js // @downloadURL https://github.com/pixeltris/TwitchAdSolutions/raw/master/video-swap-new/video-swap-new.user.js
// @description Multiple solutions for blocking Twitch ads (video-swap-new) // @description Multiple solutions for blocking Twitch ads (video-swap-new)
@@ -14,7 +14,7 @@
// ==/UserScript== // ==/UserScript==
(function() { (function() {
'use strict'; 'use strict';
var ourTwitchAdSolutionsVersion = 12;// Used to prevent conflicts with outdated versions of the scripts var ourTwitchAdSolutionsVersion = 13;// Used to prevent conflicts with outdated versions of the scripts
if (typeof unsafeWindow === 'undefined') { if (typeof unsafeWindow === 'undefined') {
unsafeWindow = window; unsafeWindow = window;
} }
@@ -293,12 +293,14 @@
// TODO: Do a better matching up of the resolutions rather than picking the highest low res for all // TODO: Do a better matching up of the resolutions rather than picking the highest low res for all
var lowResLines = encodingsM3u8.replace('\r', '').split('\n'); var lowResLines = encodingsM3u8.replace('\r', '').split('\n');
var lowResBestUrl = null; var lowResBestUrl = null;
var lowResSettings = [];
for (var j = 0; j < lowResLines.length; j++) { for (var j = 0; j < lowResLines.length; j++) {
if (lowResLines[j].startsWith('#EXT-X-STREAM-INF')) { if (lowResLines[j].startsWith('#EXT-X-STREAM-INF')) {
var res = parseAttributes(lowResLines[j])['RESOLUTION']; var res = parseAttributes(lowResLines[j])['RESOLUTION'];
if (res && lowResLines[j + 1].endsWith('.m3u8')) { if (res && lowResLines[j + 1].endsWith('.m3u8')) {
// Assumes resolutions are correctly ordered // Assumes resolutions are correctly ordered
lowResBestUrl = lowResLines[j + 1]; lowResBestUrl = lowResLines[j + 1];
lowResSettings = parseAttributes(lowResLines[j].substring(lowResLines[j].indexOf(':') + 1));
break; break;
} }
} }
@@ -308,6 +310,17 @@
var normalLines = normalEncodingsM3u8.replace('\r', '').split('\n'); var normalLines = normalEncodingsM3u8.replace('\r', '').split('\n');
for (var j = 0; j < normalLines.length - 1; j++) { for (var j = 0; j < normalLines.length - 1; j++) {
if (normalLines[j].startsWith('#EXT-X-STREAM-INF')) { if (normalLines[j].startsWith('#EXT-X-STREAM-INF')) {
var resSettings = parseAttributes(normalLines[j].substring(normalLines[j].indexOf(':') + 1));
const codecsKey = 'CODECS';
if (typeof resSettings[codecsKey] === 'string' && typeof lowResSettings[codecsKey] === 'string' &&
resSettings[codecsKey].length >= 3 && lowResSettings[codecsKey].length >= 3 &&
resSettings[codecsKey].substring(0, 3) === 'hev' &&
resSettings[codecsKey].substring(0, 3) !== lowResSettings[codecsKey].substring(0, 3)
) {
console.log('swap ' + resSettings[codecsKey] + ' to ' + lowResSettings[codecsKey]);
normalLines[j] = normalLines[j].replace(/CODECS="[^"]+"/, `CODECS="${lowResSettings[codecsKey]}"`);
console.log(normalLines[j]);
}
var res = parseAttributes(normalLines[j])['RESOLUTION']; var res = parseAttributes(normalLines[j])['RESOLUTION'];
if (res) { if (res) {
lowResBestUrl += ' ';// The stream doesn't load unless each url line is unique lowResBestUrl += ' ';// The stream doesn't load unless each url line is unique
@@ -347,7 +360,7 @@
return textStr; return textStr;
} }
var haveAdTags = textStr.includes(AD_SIGNIFIER); var haveAdTags = textStr.includes(AD_SIGNIFIER);
if (SimulatedAdsDepth && (!streamInfo.BackupEncodings || !streamInfo.BackupEncodings.includes(url) || SimulatedAdsDepth - 1 > streamInfo.BackupEncodingsPlayerTypeIndex)) { if (SimulatedAdsDepth > 0 && (!streamInfo.BackupEncodings || !streamInfo.BackupEncodings.includes(url) || SimulatedAdsDepth - 1 > streamInfo.BackupEncodingsPlayerTypeIndex)) {
haveAdTags = true; haveAdTags = true;
} }
if (streamInfo.BackupEncodings) { if (streamInfo.BackupEncodings) {
@@ -356,7 +369,7 @@
if (streamM3u8Response.status == 200) { if (streamM3u8Response.status == 200) {
var streamM3u8 = await streamM3u8Response.text(); var streamM3u8 = await streamM3u8Response.text();
if (streamM3u8 != null) { if (streamM3u8 != null) {
if (!streamM3u8.includes(AD_SIGNIFIER) && !SimulatedAdsDepth) { if (!streamM3u8.includes(AD_SIGNIFIER) && SimulatedAdsDepth == 0) {
console.log('No more ads on main stream. Triggering player reload to go back to main stream...'); console.log('No more ads on main stream. Triggering player reload to go back to main stream...');
streamInfo.IsMovingOffBackupEncodings = true; streamInfo.IsMovingOffBackupEncodings = true;
streamInfo.BackupEncodings = null; streamInfo.BackupEncodings = null;