Greasy Fork

Greasy Fork is available in English.

bs.to autoplay

auto play. sit back and relax.

当前为 2020-06-28 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         bs.to autoplay
// @namespace    http://tampermonkey.net/
// @version      2.5
// @description  auto play. sit back and relax.
// @author       xZaheer
// @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
// ==/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 http://greasyfork.icu/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+"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();

})();