// ==UserScript== // @name burning series enhancer // @name:en burning series enhancer // @icon https://bs.to/favicon.ico // @author xtrars // @description Wechselt automatisch zum VOE- oder Streamtape-Tab auf burning series und öffnet VOE oder Streamtape. Das Tool startet das nächste Video und falls nötig die nächste Staffel, wenn eine Episode beendet wurde. // @description:en Automatically switches to the VOE or Streamtape tab on burning series and opens VOE or Streamtape. The tool starts the next video and if necessary the next season when an episode is finished. // @version 10.5.2 // @run-at document-body // @license GPL-3.0-or-later // @namespace https://greasyfork.org/users/140785 // @compatible chrome Chrome // @compatible firefox Firefox // @compatible opera Opera // @compatible edge Edge // @compatible safari Safari // @grant GM_setValue // @grant GM_getValue // @grant GM_addValueChangeListener // @grant GM_removeValueChangeListener // @grant GM_download // @grant GM_info // @grant GM_addStyle // @grant GM_getResourceText // @grant window.close // @grant window.focus // @match https://bs.to/* // @match https://burningseries.co/* // @match https://burningseries.sx/* // @match https://burningseries.vc/* // @match https://burningseries.ac/* // @match https://burningseries.cx/* // @match https://burningseries.nz/* // @match https://burningseries.se/* // @match https://streamtape.com/* // @match https://*.tapecontent.net/* // @match https://*.voe-network.net/* // @include /^(https:\/\/(v-*o-*e|[-unblock\d]){1,15}\.[a-z]{2,3}\/.*)|(https:\/\/greaseball6eventual20\.com\/.*)/ // @require https://unpkg.com/video.js@latest/dist/video.min.js // @require https://unpkg.com/hls.js@latest/dist/hls.min.js // @downloadURL none // ==/UserScript== class BaseHandler { waitForElement(sSelector, bWaitUnlimited = true) { return new Promise(async resolve => { if (document.querySelector(sSelector)) { return resolve(document.querySelector(sSelector)); } const observer = new MutationObserver(() => { if (document.querySelector(sSelector)) { resolve(document.querySelector(sSelector)); observer.disconnect(); } }); if (document['body']) { observer.observe(document['body'], { childList: true, subtree: true, }); } if (!bWaitUnlimited) { setTimeout(() => { resolve(document.querySelector(sSelector)); observer.disconnect(); }, 3000); } }); } hasUrl(aSelector) { let isAvailable = true; for (let selector of aSelector) { isAvailable = document['location']['href'].search(selector) !== -1; if (!isAvailable) { return false; } } return true; } reload(iDelay = 300) { setTimeout(() => { window['location'].reload(); }, iDelay); } querySelectorAllRegex(sSelector = '*', sAttribute = 'name', rRegex = /.*/) { for (const eElement of document.querySelectorAll(sSelector)) { if (rRegex.test(eElement[sAttribute])) { return eElement; } } return false; } } class BurningSeriesHandler extends BaseHandler { initGMVariables() { if (typeof GM_getValue('bActivateEnhancer') === "undefined") { GM_setValue('bActivateEnhancer', false); } if (typeof GM_getValue('bAutoplayNextEpisode') === "undefined") { GM_setValue('bAutoplayNextEpisode', true); } if (typeof GM_getValue('bAutoplayVideo') === "undefined") { GM_setValue('bAutoplayVideo', true); } if (typeof GM_getValue('bAutoplayNextSeason') === "undefined") { GM_setValue('bAutoplayNextSeason', true); } if (typeof GM_getValue('bAutoplayRandomEpisode') === "undefined") { GM_setValue('bAutoplayRandomEpisode', false); } if (typeof GM_getValue('bSelectHoster') === "undefined") { GM_setValue('bSelectHoster', 'voe'); } if (typeof GM_getValue('bSkipStart') === "undefined") { GM_setValue('bSkipStart', false); } if (typeof GM_getValue('bSkipEnd') === "undefined") { GM_setValue('bSkipEnd', false); } if (typeof GM_getValue('bSkipEndTime') === "undefined") { GM_setValue('bSkipEndTime', 0); } if (typeof GM_getValue('bSkipStartTime') === "undefined") { GM_setValue('bSkipStartTime', 0); } } hasAnotherHoster() { return this.hasUrl([/^https:\/\/(bs.to|burningseries.[a-z]{2,3})\/.*[0-9]{1,3}\/[0-9]{1,3}-.*\/[a-z]+\/(?!Vupload|VOE|Streamtape).*/g]); } isEpisode() { return this.hasUrl([/^https:\/\/(bs.to|burningseries.[a-z]{2,3})/g, /[0-9]{1,3}\/[0-9]{1,3}-/g]); } async clickPlay() { return new Promise(async resolve => { let playerElem = await this.waitForElement('section.serie .hoster-player').catch(() => { }); let iNumberOfClicks = 0; let clickInterval = setInterval(async () => { if (playerElem) { if (document.querySelector('section.serie .hoster-player > a') || document.querySelector('section.serie .hoster-player > iframe') || iNumberOfClicks > 120 || this.querySelectorAllRegex('iframe', 'title', /recaptcha challenge/)) { clearInterval(clickInterval); resolve(); } iNumberOfClicks++; let clickEvent = new Event('click'); clickEvent['which'] = 1; clickEvent['pageX'] = 6; clickEvent['pageY'] = 1; playerElem.dispatchEvent(clickEvent); } }, 500); }); } playNextEpisodeIfVideoEnded(bSetEvent = true) { if (!bSetEvent) { GM_removeValueChangeListener('isLocalVideoEnded'); return; } GM_addValueChangeListener('isLocalVideoEnded', () => { if (GM_getValue('isLocalVideoEnded')) { GM_setValue('isLocalVideoEnded', false); window.focus(); if (GM_getValue('bAutoplayRandomEpisode')) { let oRandomEpisode = document.querySelector('#sp_right > a'); document['location'].replace(oRandomEpisode.href); } else { let oNextEpisode = document.querySelector('.serie .frame ul li[class^="e"].active ~ li:not(.disabled) a'); if (oNextEpisode) { document['location'].replace(oNextEpisode['href']); } else if (GM_getValue('bAutoplayNextSeason')) { let oNextSeason = document.querySelector('.serie .frame ul li[class^="s"].active ~ li:not(.disabled) a'); if (oNextSeason) { GM_setValue('clickFirstSeason', true); document['location'].replace(oNextSeason['href']); } } } } }); } appendOwnStyle() { const style = document.createElement('style'); style['innerHTML'] = `