burningseries-autoplay

auto play. sit back and relax.

目前為 2021-01-08 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         burningseries-autoplay
// @namespace    https://github.com/zaheer-exe/burningseries-autoplay
// @version      3
// @description  auto play. sit back and relax.
// @author       zaheer-exe
// @match    https://bs.to/*
// @match    https://*.vivo.sx/*
// @grant    GM_setValue
// @grant    GM_getValue
// @grant    GM_deleteValue
// @grant    GM_openInTab
// @grant    window.close
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js
// @license    GPL
// ==/UserScript==

class VivoHandler {
    constructor() {
        this.episodeHandler = new EpisodeHandler();
        this.currentEpisode = this.episodeHandler.getCurrent();
        this.nextEpisode = this.episodeHandler.getNext();
        this.prevEpisode = this.episodeHandler.getPrev();
        this.skipTime = this.episodeHandler.getCurrentSkip();

        if (window.location.href.includes("vivo.sx")) {
            this.initEvents();
        }
    }

    initEvents() {
        if (window.location.href.includes("https://vivo.sx")) {
            this.play();
        } else {
            let waitForElem = setInterval(() => {
                let videoElem = document.querySelector("video");
                if (videoElem) {
                    clearTimeout(waitForElem);
                    GM_setValue("playing", true);
                    this.resize();
                    this.onEnd();
                    this.resume();
                    this.showControls();
                    this.trackWatchedState();
                }
            }, 50);
        }
    }

    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;
            }
        }
        GM_setValue("playing", true);
        window.location.href = url;
    }

    showControls() {
        //document.body.style.position = "relative";
        let nextButton = document.createElement("button");
        let prevButton = document.createElement("button");
        nextButton.style.visibility = "hidden";
        prevButton.style.visibility = "hidden";;
        nextButton.innerHTML = "Nächste Episode";
        prevButton.innerHTML = "Vorherige Episode";
        nextButton.style.position = "absolute";
        prevButton.style.position = "absolute";
        nextButton.addEventListener("click", () => {
            this.episodeHandler.clean();
            this.episodeHandler.setCurrent(this.nextEpisode);
            window.location.href = this.nextEpisode + "#autoplay";
        });
        prevButton.addEventListener("click", () => {
            this.episodeHandler.clean();
            this.episodeHandler.setCurrent(this.prevEpiside);
            window.location.href = this.prevEpisode + "#autoplay";
        });
        document.body.appendChild(nextButton);
        document.body.appendChild(prevButton);
        prevButton.style.left = "0";
        nextButton.style.left = "calc(100% - " + (nextButton.offsetWidth + 1) + "px)";
        nextButton.style.top = "50%";
        prevButton.style.top = "50%";
        let timer = null;
        document.body.addEventListener("mousemove", () => {
            if (timer) {
                clearTimeout(timer);
            }
            nextButton.style.visibility = "visible";
            prevButton.style.visibility = "visible";
            timer = setTimeout(() => {
                nextButton.style.visibility = "hidden";
                prevButton.style.visibility = "hidden";
            }, 1000);
        })
    }

    resize() {
        let video = document.querySelector("video");
        video.style.width = "100%";
        video.style.height = "100%";
        document.body.style.margin = "0px";

    }

    onEnd() {
        let videoElem = document.querySelector("video");
        videoElem.onended = () => {
            let current = videoElem.currentTime;
            let duration = videoElem.duration;
            if (current && duration) {
                this.episodeHandler.watch(this.currentEpisode, current, duration);
            }
            let nextEpisode = this.episodeHandler.getNext();
            this.episodeHandler.clean();
            this.episodeHandler.setCurrent(nextEpisode);
            window.location.href = nextEpisode + "#autoplay";

        }
    }

    trackWatchedState() {
        let videoElem = document.querySelector("video");
        if (videoElem && this.currentEpisode) {
            videoElem.addEventListener('progress', (event) => {
                let current = videoElem.currentTime;
                let duration = videoElem.duration;
                if (current && duration) {
                    this.episodeHandler.watch(this.currentEpisode, current, duration);
                }
            });
        }
    }

    skip() {
        let videoElem = document.querySelector("video");
        videoElem.currentTime = this.skipTime;
    }

    resume() {
        let videoElem = document.querySelector("video");
        let data = this.episodeHandler.getWatched(this.currentEpisode);
        if ((data.current !== data.duration) && videoElem && data) {
            videoElem.currentTime = data.current;
        } else {
            this.skip();
        }
    }

}

class BsHandler {
    constructor() {
        this.episodeHandler = new EpisodeHandler();
        this.buttonElem = null;
        if (window.location.href.includes("bs.to")) {
            this.initEvents();
        }
    }

    initEvents() {
        // handle bs.to/*
        if (this.isLoggedIn()) {}

        // handle episode overview table
        if (window.location.href.includes("bs.to/serie") && this.isEpisodeOverview()) {
            this.episodeHandler.clean();
            this.initElementsEpisodeOverview();
        }

        // handle episode view
        if (!this.isEpisodeOverview() && this.isEpisodeSelected()) {
            if (this.isVivoAvailable() && this.isAutoplayForEpisode()) {
                this.closeOnPlay();
                this.setPrevNext();
                this.showAutoplayOverlay();
                this.clickPlay();
            } else {
                this.episodeHandler.clean();
            }
        }
    }

    isAutoplayForEpisode() {
        return (window.location.href.includes("#autoplay")) ? true : false;
    }

    setPrevNext() {
        let episodes = document.querySelector("#episodes > ul");
        let selectedEpisode = episodes.querySelector(".active");
        let nextEpisode = episodes.querySelector("li.active + li");
        let prevEpisode = selectedEpisode.previousElementSibling;
        let prevUrl = (prevEpisode) ? prevEpisode.querySelector("a").href : "";
        let nextUrl = (nextEpisode) ? nextEpisode.querySelector("a").href : "";
        this.episodeHandler.setPrev(prevUrl);
        this.episodeHandler.setNext(nextUrl);

    }

    showAutoplayOverlay() {
        let overlayElem = document.createElement("h1");
        document.querySelector("#root").style.visibility = "hidden";
        document.body.style.overflow = "hidden";
        document.body.style.height = "100vh";
        document.querySelector("footer").style.visibility = "hidden";
        overlayElem.innerHTML = "Auto Playing ..."
        overlayElem.style.position = "absolute";
        document.body.style.display = "flex";
        document.body.style.alignItems = "center";
        document.body.style.justifyContent = "center";
        overlayElem.style.zIndex = "999";
        document.body.appendChild(overlayElem);
    }

    initElementsEpisodeOverview() {
        let tableElem = document.querySelectorAll("#root > section > table > tbody > tr");
        let episodeRowElemToHandle = [];
        tableElem.forEach(episodeRowElem => {
            if (episodeRowElem.querySelector(".vivo")) {
                episodeRowElemToHandle.push(episodeRowElem);
            }
        });
        this.addSkipControl();
        this.addContinueButtons(episodeRowElemToHandle);
        this.addProgessBars(episodeRowElemToHandle);
    }

    addSkipControl() {
        let seasonUrl = this.getActiveSeasonUrl();
        let onChange = (event) => {
            let time = parseInt(event.target.value) || 0;
            this.episodeHandler.setSkipForSeason(seasonUrl, time);
        };

        let divElem = document.createElement("div");
        let labelElem = document.createElement("label");
        let inputElem = document.createElement("input");
        inputElem.type = "number";
        divElem.appendChild(labelElem);
        labelElem.innerHTML = "Intro überspringen (in Sekunden):"
        divElem.appendChild(inputElem);
        let locationElem = document.querySelector("#root > section > div.selectors");

        locationElem.appendChild(divElem);
        inputElem.value = this.episodeHandler.getSkipForSeason(seasonUrl) || "";
        inputElem.addEventListener("change", onChange);
    }

    getActiveSeasonUrl() {
        return document.querySelector("#seasons > ul > .active > a").href;
    }

    addProgessBars(elements) {
        elements.forEach((episodeRowElem) => {
            let url = episodeRowElem.querySelector("a").href;
            let data = this.episodeHandler.getWatched(url);
            let percentage = data.current * 100 / data.duration;

            if (percentage) {
                let episodeProgressbarElem = document.createElement("meter");
                episodeProgressbarElem.value = percentage;
                episodeProgressbarElem.max = 100;
                episodeProgressbarElem.style.width = "100%";
                episodeRowElem.appendChild(episodeProgressbarElem);
            }
        });
    }

    addContinueButtons(elements) {
        elements.forEach((episodeRowElem) => {
            let location = episodeRowElem.querySelector("[title='vivo']").parentElement;
            let buttonElem = document.createElement("a");
            buttonElem.innerHTML = "AutoPlay";
            buttonElem.style.cursor = "pointer";
            buttonElem.addEventListener("click", () => {
                let url = episodeRowElem.querySelector("a").href;
                this.episodeHandler.clean();
                this.episodeHandler.setCurrent(url);
                window.open(url + "#autoplay");
            })
            location.prepend(buttonElem);
        });
    }

    isLoggedIn() {
        let logoutButtonElem = document.querySelector("#root > header > section > a:nth-child(4)");
        return (logoutButtonElem) ? true : false;
    }

    isEpisodeOverview() {
        let isSerie = window.location.href.includes("serie");
        return (isSerie && !this.isEpisodeSelected());
    }

    isEpisodeSelected() {
        let checkElem = document.querySelector("#root > section > ul.hoster-tabs.top");
        return (checkElem) ? true : false;

    }

    isVivoAvailable() {
        let vivoButton = document.querySelector("#root > section > ul.hoster-tabs.top > li > a > i.vivo");
        if (!vivoButton) {
            return false;
        } else {
            return true;
        }
    }

    clickPlay() {
        let seasonUrl = this.getActiveSeasonUrl();
        let skipTime = this.episodeHandler.getSkipForSeason(seasonUrl);
        this.episodeHandler.setCurrentSkip(skipTime);

        // setTimeout needed because loading time of js libs
        setTimeout(() => {
            let playerElem = document.querySelector("section.serie .hoster-player");
            let clickEvent = new Event("click");
            clickEvent.which = 1;
            clickEvent.pageX = 1;
            clickEvent.pageY = 1;
            playerElem.dispatchEvent(clickEvent);

        }, 1000)
    }

    closeOnPlay() {
        setInterval(() => {
            if (GM_getValue("playing")) {
                window.close();
            }
        }, 1000);
    }
}

class EpisodeHandler {
    watch(episodeUrl, current, duration) {
        let data = JSON.parse(GM_getValue(episodeUrl) || "{}");
        data.watched = {
            current: current,
            duration: duration
        };
        GM_setValue(episodeUrl, JSON.stringify(data));
    }

    getWatched(episodeUrl) {
        let data = GM_getValue(episodeUrl);
        if (!data) {
            return false;
        }

        data = JSON.parse(data);
        return data.watched;
    }

    // oursource
    setSkipForSeason(seasonUrl, time) {
        let data = JSON.parse(GM_getValue(seasonUrl) || "{}");
        data.skipTime = time;
        console.log(data);
        GM_setValue(seasonUrl, JSON.stringify(data));
    }

    getSkipForSeason(seasonUrl) {
        let data = GM_getValue(seasonUrl);
        if (!data) {
            return false;
        }

        data = JSON.parse(data);
        return data.skipTime;
    }
    //outsource end

    setCurrentSkip(time) {
        GM_setValue("currentSkip", time);
    }

    getCurrentSkip() {
        return GM_getValue("currentSkip") || 0;
    }

    getCurrent() {
        return GM_getValue("current");
    }

    setCurrent(episodeUrl) {
        GM_setValue("current", episodeUrl);
    }

    getPrev() {
        return GM_getValue("prev");
    }

    setPrev(episodeUrl) {
        GM_setValue("prev", episodeUrl);
    }

    getNext() {
        return GM_getValue("next");
    }

    setNext(episodeUrl) {
        GM_setValue("next", episodeUrl);
    }

    clean() {
        GM_deleteValue("current");
        GM_deleteValue("next");
        GM_deleteValue("prev");
        GM_deleteValue("playing");
        GM_deleteValue("currentSkip");

    }
}

(function() {
    'use strict';
    let vivoHandler = new VivoHandler();
    let bsHandler = new BsHandler();

})();