// ==UserScript== // @name burningseries-autoplay // @namespace https://github.com/zaheer-exe/burningseries-autoplay // @version 3.2 // @description Autoplay für Burningseries // @author zaheer-exe // @match https://bs.to/* // @match https://*.vivo.sx/* // @match https://burningseries.co/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_openInTab // @grant window.close // @license Apache License // @downloadURL none // ==/UserScript== const debugging = false; function log(msg) { if(debugging) { console.log(msg); } } function waitForElem(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { resolve(document.querySelector(selector)); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } class SiteHandler { constructor() { log('SiteHandler: constructor()'); this.dataHandler = new DataHandler(); this.url = new URL(document.location.href); this.settings = this.dataHandler.getSettings(); this.registerEvents(); } registerEvents() { document.addEventListener('visibilitychange', () => { if(!document.hidden) { let url = new URL(document.location.href); this.dataHandler.setCurrentWebsite(url.host); return true } return false; }); } } class VivoHandler extends SiteHandler { constructor() { super(); this.data = this.dataHandler.getEpisodeData(this.settings.lastBsUrl); log(this.data); if(this.settings.vivoEnabled && this.isVivo()) { this.play(); } if(this.settings.vivoEnabled && this.isVivoVideo()){ this.resize(); this.trackWatchedState(); if(this.settings.autonextEnabled) { this.onEndPlayNext(); } } if(this.settings.vivoButtonsEnabled && this.isVivoVideo()){ this.loadButtons(); } if(this.settings.autoresumeEnabled) { this.resume(); } } isVivo() { log('VivoHandler: isVivo()'); const vivoDomains = ['vivo.sx']; const currentUrl = new URL(document.location.href); log(currentUrl); return vivoDomains.includes(currentUrl.host); } isVivoVideo() { log('VivoHandler: isVivoVideo()'); if(document.querySelector('video') && window.location.href.includes('vivo') && window.location.href.includes('--')) { return true; } return false; } loadButtons() { if(this.data.prev) { let prevButton = document.createElement('button'); prevButton.style.position = 'absolute'; prevButton.style.left = '0'; prevButton.innerText = 'Vorherige Folge'; prevButton.style.top = '50%'; prevButton.style.visibility = 'hidden'; prevButton.addEventListener('click', ()=>{ window.location.href = this.data.prev; }); prevButton.classList.add('autoplay-button'); document.body.append(prevButton); } if(this.data.next) { let nextButton = document.createElement('button'); nextButton.innerText = 'Nächste Folge'; nextButton.style.position = 'absolute'; nextButton.style.top = '50%'; nextButton.style.visibility = 'hidden'; document.body.append(nextButton); nextButton.style.left = 'calc(100% - ' + nextButton.offsetWidth + 'px)'; nextButton.addEventListener('click', ()=>{ window.location.href = this.data.next; }); nextButton.classList.add('autoplay-button'); } let timer = null; document.body.addEventListener('mousemove', () => { if(timer) { clearTimeout(timer); } document.querySelectorAll('.autoplay-button').forEach(button => { button.style.visibility = 'visible'; }); timer = setTimeout(() => { document.querySelectorAll('.autoplay-button').forEach(button => { button.style.visibility = 'hidden'; }); }, 1000); }); } trackWatchedState() { log('VivoHandler: trackWatchedState()'); let videoElem = document.querySelector('video'); if (videoElem) { videoElem.addEventListener('progress', (event) => { let current = videoElem.currentTime; let duration = videoElem.duration; if (current && duration) { this.data.currentTime = current; this.data.maxTime = duration; this.dataHandler.setEpisodeData(this.settings.lastBsUrl, this.data); } }); } } onEndPlayNext() { log('VivoHandler: onEndPlayNext()'); let videoElem = document.querySelector("video"); videoElem.onended = () => { let current = videoElem.currentTime; let duration = videoElem.duration; if (current && duration) { this.data.currentTime = current; this.data.maxTime = duration; this.dataHandler.setEpisodeData(this.settings.lastBsUrl, this.data); } let nextEpisode = this.data.next; window.location.href = nextEpisode; } } resize() { let video = document.querySelector("video"); video.style.width = "100%"; video.style.height = "100%"; document.body.style.margin = "0px"; } play() { log('VivoHandler: play()'); // code by https://greasyfork.org/de/scripts/28779-zu-vivo-video-navigieren // Thank you! var source = document.getElementsByTagName('body')[0].innerHTML; if (source != null) { source = source.replace(/(?:.|\n)+Core\.InitializeStream\s*\(\s*\{[^)}]*source\s*:\s*'(.*?)'(?:.|\n)+/, "$1"); var toNormalize = decodeURIComponent(source); var url = "" for (var i = 0; i < toNormalize.length; i++) { var c = toNormalize.charAt(i); if (c != ' ') { var t = (function (c) { return c.charCodeAt == null ? c : c.charCodeAt(0); })(c) + '/'.charCodeAt(0); if (126 < t) { t -= 94; } url += String.fromCharCode(t); } } if (!url.toLowerCase().startsWith("http")) { alert("Vivo-Script Defect!"); return; } } window.location.href = url; } resume() { let videoElem = document.querySelector('video'); if ((this.data.currentTime !== this.data.maxTime) && videoElem) { videoElem.currentTime = this.data.currentTime; } } } class BsHandler extends SiteHandler { constructor() { super(); if(this.isBs()) { this.dataHandler.setCurrentWebsite('bs'); this.settings = this.dataHandler.getSettings(); this.loadMenu(); if(this.dataHandler.getSettings().bsEnabled) { this.main(); } } } isBs() { log('BsHandler: isBs()'); const bsDomains = ['bs.to', 'burningseries.co']; const currentUrl = new URL(document.location.href); log(currentUrl); return bsDomains.includes(currentUrl.host); } loadMenu() { log('BsHandler: loadMenu()'); let css = document.createElement('style'); let lastText = this.settings.lastVivoUrl ? `

Weiterschauen: ` + this.settings.lastName + `

` : ''; css.innerHTML = ` .bs-autoplay-menu { color: white; position: absolute; top: 0; z-index: 999; background: rgba(0,0,0,0.6); margin: 10px; padding: 5px; } .bs-autoplay-menu .cb { display: inline-block; } .bs-autoplay-menu a { color: red; } ` let html = document.createElement('div'); html.innerHTML = `

Autoplay

`+lastText+`
autoplay bs:
autoplay vivo:
automatisch nächste Folge abspielen:
fortsetzen wo du aufgehört hast:
Buttons im Video anzeigen:
` html.querySelector('.toggle-button-bs').checked = this.settings.bsEnabled; html.querySelector('.toggle-button-bs').addEventListener('click', () => { this.settings.bsEnabled = !this.settings.bsEnabled; this.dataHandler.setSettings(this.settings); location.reload(); }); html.querySelector('.toggle-button-vivo').checked = this.settings.vivoEnabled; html.querySelector('.toggle-button-vivo').addEventListener('click', () => { this.settings.vivoEnabled = !this.settings.vivoEnabled; this.dataHandler.setSettings(this.settings); location.reload(); }); html.querySelector('.toggle-button-autonext').checked = this.settings.autonextEnabled; html.querySelector('.toggle-button-autonext').addEventListener('click', () => { this.settings.autonextEnabled = !this.settings.autonextEnabled; this.dataHandler.setSettings(this.settings); location.reload(); }); html.querySelector('.toggle-button-autoresume').checked = this.settings.autoresumeEnabled; html.querySelector('.toggle-button-autoresume').addEventListener('click', () => { this.settings.autoresumeEnabled = !this.settings.autoresumeEnabled; this.dataHandler.setSettings(this.settings); location.reload(); }); html.querySelector('.toggle-button-vivobuttons').checked = this.settings.vivoButtonsEnabled; html.querySelector('.toggle-button-vivobuttons').addEventListener('click', () => { this.settings.vivoButtonsEnabled = !this.settings.vivoButtonsEnabled; this.dataHandler.setSettings(this.settings); location.reload(); }); html.querySelector('.bs-autoplay-menu').append() document.body.append(css); document.body.append(html); } loadAutoplayButtons() { let episodeRows = document.querySelectorAll('.episodes tr'); episodeRows.forEach((episode) => { let target = episode.querySelector('[title=\'vivo\']'); if (!target) { return; } target = target.parentElement; let buttonElem = document.createElement('button'); buttonElem.innerHTML = 'Auto Play'; buttonElem.addEventListener('click', () => { let url = episode.querySelector('a').href; window.open(url + "#autoplay"); }) target.prepend(buttonElem); }) } setPrevAndNextEpisode() { let next = document.querySelector('#episodes .active').nextElementSibling; let prev = document.querySelector('#episodes .active').previousElementSibling; let data = this.dataHandler.getEpisodeData(this.url.pathname) || {}; if(next) { next = next.querySelector('a').href; } if(prev) { prev = prev.querySelector('a').href; } console.log(data); data.prev = prev || false; data.next = next || false; this.dataHandler.setEpisodeData(this.url.pathname, data); } play() { // setTimeout needed because loading time of js libs setTimeout(() => { let playerElem = document.querySelector('section.serie .hoster-player'); if(playerElem) { let clickEvent = new Event('click'); clickEvent.which = 1; clickEvent.pageX = 1; clickEvent.pageY = 1; playerElem.dispatchEvent(clickEvent); waitForElem('.hoster-player a').then((elem) => { let data = this.dataHandler.getEpisodeData(this.url.pathname) || {}; let url = elem.href; data.vivourl = url; this.settings.lastVivoUrl = url; this.settings.lastBsUrl = this.url.pathname; this.settings.lastName = document.querySelector('section.serie h2').innerText; this.dataHandler.setSettings(this.settings); this.dataHandler.setEpisodeData(this.url.pathname, data); window.close(); }) } }, 1000); } addProgessBars() { let elements = document.querySelectorAll('.episodes tr'); elements.forEach((episodeRowElem) => { let url = new URL(episodeRowElem.querySelector('a').href); let path = url.pathname; let data = this.dataHandler.getEpisodeData(path); let percentage = data.currentTime * 100 / data.maxTime; if (percentage) { let episodeProgressbarElem = document.createElement("meter"); episodeProgressbarElem.value = percentage; episodeProgressbarElem.max = 100; episodeProgressbarElem.style.width = "100%"; episodeRowElem.appendChild(episodeProgressbarElem); } }); } main() { this.loadAutoplayButtons(); this.addProgessBars(); this.setPrevAndNextEpisode(); this.play(); } } class DataHandler { constructor() { log('DataHandler: constructor()'); } getCurrentWebsite() { log('DataHandler: getCurrentWebsite()'); let currentWebsite = GM_getValue('currentWebsite'); try { currentWebsite = JSON.parse(currentWebsite); } catch(e) { log('Datahandler: getCurrentWebsite()' + e); return false; } log(currentWebsite); return currentWebsite; } setCurrentWebsite(site) { log('DataHandler: setCurrentWebsite()'); try { let currentWebsite = JSON.stringify(site); GM_setValue('currentWebsite', currentWebsite); } catch(e) { log('Datahandler: setCurrentWebsite()' + e); return false; } return true; } setSettings(data) { try { let d = JSON.stringify(data); GM_setValue('settings', d); } catch(e) { log('Datahandler: setSettings()' + e); return false; } return true; } getSettings() { log('DataHandler: getSettings()'); let data = GM_getValue('settings') || '{}'; try { data = JSON.parse(data); } catch(e) { log('Datahandler: getSettings()' + e); return false; } log(data); return data; } setEpisodeData(url, data) { try { let d = JSON.stringify(data); GM_setValue(url, d); } catch(e) { log('Datahandler: setEpisodeData()' + e); return false; } return true; } getEpisodeData(url) { log('DataHandler: getEpisodeData()'); let data = GM_getValue(url) || {}; try { data = JSON.parse(data); } catch(e) { log('Datahandler: getEpisodeData('+ url +')' + e); return false; } log(data); return data; } } new BsHandler(); new VivoHandler();