Greasy Fork

Greasy Fork is available in English.

bs.to and vivo enhancer

Wechselt automatisch zum vivo-Tab auf bs.to und auf vivo.XX kopiert es die Video-URL in den Zwischenspeicher oder leitet zur Videoquelle weiter

当前为 2021-07-23 提交的版本,查看 最新版本

// ==UserScript==
// @name           bs.to and vivo enhancer
// @author         xtrars
// @description    Wechselt automatisch zum vivo-Tab auf bs.to und auf vivo.XX kopiert es die Video-URL in den Zwischenspeicher oder leitet zur Videoquelle weiter
// @description:en Automatically switches to the vivo tab on bs.to and on vivo.XX it copies the video URL to the clipboard or redirects to the video source
// @include        https://bs.to/*
// @include        https://*.vivo.sx/*
// @include        https://*.vivo.st/*
// @include        https://vivo.sx/*
// @include        https://vivo.st/*
// @version        2.3
// @run-at         document-start
// @license        CC BY 4.0
// @namespace      http://greasyfork.icu/users/140785
// @grant          GM_setValue
// @grant          GM_getValue
// @grant          GM_setClipboard
// @grant          GM_addValueChangeListener
// @grant          GM_removeValueChangeListener
// ==/UserScript==



class SiteHandler {

    isVivoTab() {
        let sVivoStr = '/Vivo';
        return document['location']['href'].search(sVivoStr) !== -1;
    }

    hasAnotherHoster() {
        let hosterRegex = /^https:\/\/bs.to\/.*[0-9]{1,2}\/[0-9]{1,2}\-.*\/[a-z]*\/(?!Vivo).*$/g;
        return document['location']['href'].search(hosterRegex) !== -1;
    }

    isEpisode() {
        let serieRegex = /[0-9]{1,2}\/[0-9]{1,2}\-/g;
        let bsRegex = /^(https:\/\/bs.to)/g;
        return document['location']['href'].search(bsRegex) !== -1 && document['location']['href'].search(serieRegex) !== -1;
    }

    isVivo() {
        let vivoRegex = /^https:\/\/vivo.[a-z]{2,3}\//g;
        return document['location']['href'].search(vivoRegex) !== -1 && document.getElementsByTagName('video') && document.getElementsByTagName('video')[document.getElementsByTagName('video').length -1]
    }

    isReady() {
        return new Promise(result => {
            window.addEventListener('load', function() {
                result(true);
            });
        });
    }

    // thanks to xZaheer (http://greasyfork.icu/de/scripts/400669-burningseries-autoplay/code)
    waitForElement(selector) {
        return new Promise(async 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();
                }
            });
            let waitForElementInterval = setInterval(() => {
                if(document.body) {
                    observer.observe(document.body, {
                        childList: true,
                        subtree: true,
                    });
                    clearInterval(waitForElementInterval);
                }

            }, 20);

        });
    }

    // thanks to xZaheer (http://greasyfork.icu/de/scripts/400669-burningseries-autoplay/code)
    async clickPlay() {
        await this.waitForElement('section.serie .hoster-player').catch(() => {});
        let playerElem = document.querySelector('section.serie .hoster-player');
        if(playerElem) {
            let clickEvent = new Event('click');
            clickEvent.which = 1;
            clickEvent.pageX = 1;
            clickEvent.pageY = 1;
            setTimeout(() => {
                playerElem.dispatchEvent(clickEvent);
            }, 500);
        }
    }

    playNextEpisodeIfVideoEnded(bSetEvent = true) {
        if(!bSetEvent) {
            GM_removeValueChangeListener('isLocalVideoEnded');
            GM_setValue('isLocalVideoEnded', false);
            return;
        }
        GM_addValueChangeListener('isLocalVideoEnded', () => {
            if (GM_getValue('isLocalVideoEnded')) {
                GM_setValue('isLocalVideoEnded', false);
                document['location'].replace(document.querySelector('.serie .frame ul li[class^="e"].active + li a').href);
            }
        });

    }

    buildButton() {
        const style = document.createElement('style');
        style.innerHTML = `
  :root {
  --inner-pl: 14px;
  --inner-bc-before: #2FB536;
  --inner-bc-after: #12A6F6;
  --color: white;
}

  @keyframes shake {
  10%, 90% {transform: translate3d(-.5px, 0, 0);}
  20%, 80% {transform: translate3d(1px, 0, 0);}
  30%, 50%, 70% {transform: translate3d(-2px, 0, 0);}
  40%, 60% {transform: translate3d(2px, 0, 0);}
}
.onoffswitch {
    position: relative; width: 350px;
    -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
}
.onoffswitch-checkbox {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}
.onoffswitch-label {
    width: 350px;
    display: block;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    border-radius: 20px;
}
.onoffswitch-inner {
    display: block; width: 200%; margin-left: -100%;
    transition: margin 0.3s ease-in 0s;
}
.onoffswitch-inner:before, .onoffswitch-inner:after {
    display: block; float: left; width: 50%; height: 30px; padding: 0; line-height: 30px;
    font-size: 10px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
    box-sizing: border-box;
}
.onoffswitch-switch {
    display: block;
    width: 23px; margin: 3.5px;
    background: #FFFFFF;
    position: absolute;
    top: 0;
    bottom: 0;
    right: 314px;
    border: 2px solid #999999;
    border-radius: 20px;
    transition: all 0.3s ease-in 0s;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
    margin-left: 0;
}
.onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
    right: 0px;
}

#xtrars-btn {
   position: absolute;
   bottom: 100px;
   right: 18px;
   background: #12a6f6;
   border-radius: 50%;
   width: 70px;
   height: 70px;
   line-height: 81px;
   text-align: center;
   cursor: pointer;
   animation: shake 1s ease 1s 1 normal;
}
#xtrars-menu {
   right: 0;
}
#xtrars-btn-icon {
   color: var(--color);
}
.onoffswitch-inner.autoplay:before {
    padding-left: var(--inner-pl);
    background-color: var(--inner-bc-before);
    color: var(--color);
    text-align: start;
    content: "Vivo Autoplay aktivieren";
}
.onoffswitch-inner.autoplay:after {
    padding-right: var(--inner-pl);
    background-color: var(--inner-bc-after);
    color: var(--color);
    text-align: end;
    content: "Video-URL in die Zwischenablage kopieren und Tab schließen";
}
.onoffswitch-inner.auto-next-episode:before {
    padding-left: var(--inner-pl);
    background-color: var(--inner-bc-before);
    color: var(--color);
    text-align: start;
    content: "Nächste Folge automatisch abspielen";
}
.onoffswitch-inner.auto-next-episode:after {
    padding-right: var(--inner-pl);
    background-color: var(--inner-bc-after);
    color: var(--color);
    text-align: end;
    content: "Nächste Folge manuell abspielen";
}
.onoffswitch-inner.enable-enhancer:before {
    padding-left: var(--inner-pl);
    background-color: var(--inner-bc-before);
    color: var(--color);
    text-align: start;
    content: "bs.to and vivo enhancer aktiviert";
}
.onoffswitch-inner.enable-enhancer:after {
    padding-right: var(--inner-pl);
    background-color: var(--inner-bc-after);
    color: var(--color);
    text-align: end;
    content: "bs.to and vivo enhancer deaktiviert";
}
  `;
        document.head.appendChild(style);

        const button = document.createElement("div");
        button['innerHTML'] = '<div id="xtrars-btn">' +
            '<i id="xtrars-btn-icon" class="fas fa-cogs fa-2x"></i>' +
            '</div>';
        button['style'] = 'position: relative; height: 0;'
        document.getElementsByClassName('infos')[0].appendChild(button);

        const menu = document.createElement("div");
        menu['innerHTML'] = '<div class="onoffswitch"><input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch"><label class="onoffswitch-label" for="xtrars-onoffswitch"><span class="onoffswitch-inner enable-enhancer"></span><span class="onoffswitch-switch"></span></label></div>' +
            '<div class="onoffswitch"><input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch"><label class="onoffswitch-label" for="xtrars-onoffswitch"><span class="onoffswitch-inner auto-next-episode"></span><span class="onoffswitch-switch"></span></label></div>' +
            '<div class="onoffswitch"><input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox xtrars-onoffswitch"><label class="onoffswitch-label" for="xtrars-onoffswitch"><span class="onoffswitch-inner autoplay"></span><span class="onoffswitch-switch"></span></label></div>';
        menu['style'] = 'display: none;';
        menu['id'] = 'xtrars-menu';
        document.getElementById('xtrars-btn').appendChild(menu);

        this.initEvents();
    }

    initEvents() {
        let button = document.getElementById('xtrars-btn');
        let menu = document.getElementById('xtrars-menu');
        let activateEnhancer = document.querySelectorAll('.xtrars-onoffswitch + label')[0]
        let autoplayNextEpisode = document.querySelectorAll('.xtrars-onoffswitch + label')[1]
        let autoplayVivoVideo = document.querySelectorAll('.xtrars-onoffswitch + label')[2];

        activateEnhancer.previousSibling.checked = GM_getValue('bActivateEnhancer');
        autoplayNextEpisode.previousSibling.checked = GM_getValue('bAutoplayNextEpisode');
        autoplayVivoVideo.previousSibling.checked = GM_getValue('bAutoplayVivoVideo');


        if(!GM_getValue('bActivateEnhancer')) {
            this.hideAutoplayNextEpisode(autoplayNextEpisode);
        }

        if(!GM_getValue('bActivateEnhancer') || GM_getValue('bAutoplayNextEpisode')) {
            this.manageAutoplayVivoVideoButton(activateEnhancer, autoplayNextEpisode, autoplayVivoVideo);
        }

        button.addEventListener('mouseover', () => {
            menu['style'] = 'display: block; position: absolute; bottom: 0; line-height: normal;'
            document.getElementById('xtrars-btn')['style'] = 'background: transparent; border-radius: 0; width: 350px; right: -130px; height: 108px; bottom: 50px;';
            document.getElementById('xtrars-btn-icon')['style'] = 'color: transparent;';
        });

        button.addEventListener('mouseleave', () => {
            menu['style'] = 'display: none;';
            document.getElementById('xtrars-btn')['style'] = '';
            document.getElementById('xtrars-btn-icon')['style'] = '';
        });

        activateEnhancer.addEventListener('click', () => {
            activateEnhancer.previousSibling.checked = !activateEnhancer.previousSibling.checked;
            GM_setValue('bActivateEnhancer', activateEnhancer.previousSibling.checked);
            if (!activateEnhancer.previousSibling.checked) {
                this.hideAutoplayVivoVideo(autoplayVivoVideo);
                this.hideAutoplayNextEpisode(autoplayNextEpisode);
            } else {
                autoplayVivoVideo['style'] = '';
                autoplayNextEpisode['style'] = '';


                this.manageAutoplayVivoVideoButton(activateEnhancer, autoplayNextEpisode, autoplayVivoVideo);
            }
        });

        autoplayNextEpisode.addEventListener('click', () => {
            autoplayNextEpisode.previousSibling.checked = !autoplayNextEpisode.previousSibling.checked;
            GM_setValue('bAutoplayNextEpisode', autoplayNextEpisode.previousSibling.checked);
            this.manageAutoplayVivoVideoButton(activateEnhancer, autoplayNextEpisode, autoplayVivoVideo);
        });

        autoplayVivoVideo.addEventListener('click', () => {
            if (!GM_getValue('bAutoplayNextEpisode')) {
                autoplayVivoVideo.previousSibling.checked = !autoplayVivoVideo.previousSibling.checked;
                GM_setValue('bAutoplayVivoVideo', autoplayVivoVideo.previousSibling.checked);
            }
        });
    }

    hideAutoplayNextEpisode(autoplayNextEpisode) {
        this.playNextEpisodeIfVideoEnded(false);
        autoplayNextEpisode['style'] = 'visibility:hidden;';
        GM_setValue('bAutoplayNextEpisode', false);
    }

    hideAutoplayVivoVideo(autoplayVivoVideo) {
        this.playNextEpisodeIfVideoEnded();
        autoplayVivoVideo['style'] = 'visibility:hidden;';
        GM_setValue('bAutoplayVivoVideo', true);
    }

    manageAutoplayVivoVideoButton(activateEnhancer, autoplayNextEpisode, autoplayVivoVideo) {
        if (autoplayNextEpisode.previousSibling.checked || !activateEnhancer.previousSibling.checked) {
            this.hideAutoplayVivoVideo(autoplayVivoVideo);
        } else {
            autoplayVivoVideo['style'] = '';
            autoplayVivoVideo.querySelectorAll('span')['style'] = '';
            this.playNextEpisodeIfVideoEnded(false);
        }
    }

    initGMVariables() {
        if (typeof GM_getValue('bActivateEnhancer') === "undefined") {
            GM_setValue('bActivateEnhancer', true);
        }

        if (typeof GM_getValue('bAutoplayNextEpisode') === "undefined") {
            GM_setValue('bAutoplayNextEpisode', true);
        }

        if (typeof GM_getValue('bAutoplayVivoVideo') === "undefined") {
            GM_setValue('bAutoplayVivoVideo', true);
        }
    }
}


(async function() {
    'use strict';

    let siteHandler = new SiteHandler();
    siteHandler.initGMVariables();

    if (siteHandler.isEpisode()) {
        if (GM_getValue('bActivateEnhancer') && !siteHandler.hasAnotherHoster() && !siteHandler.isVivoTab()) {
            document['location'].replace(document['location']['href'] + '/Vivo');
        }

        await siteHandler.waitForElement('#sp_left').catch(() => {});
        siteHandler.buildButton();

        if (GM_getValue('bActivateEnhancer') && !siteHandler.hasAnotherHoster() && siteHandler.isVivoTab()) {
            if (GM_getValue('bAutoplayNextEpisode')) {
                siteHandler.playNextEpisodeIfVideoEnded();
            }

            if(GM_getValue('bActivateEnhancer') && GM_getValue('bAutoplayVivoVideo')){
                siteHandler.clickPlay();
            }

        }
    }


    if (GM_getValue('bActivateEnhancer') && await siteHandler.isReady().catch(() => {}) && siteHandler.isVivo()) {
        // thanks to Wissidi dom (http://greasyfork.icu/de/scripts/28779-zu-vivo-video-navigieren/code)
        let sSrc = document.getElementsByTagName('video')[document.getElementsByTagName('video').length -1]['currentSrc'];

        if (GM_getValue('bAutoplayVivoVideo')) {
            window['location'].replace(sSrc);
        } else {
            await navigator.clipboard.writeText(sSrc).catch(() => {});
            // if the first method doesn't work
            GM_setClipboard(sSrc);
            window.close();
        }
    }

    if (GM_getValue('bActivateEnhancer')) {
        let video;
        if (video = await siteHandler.waitForElement('html > head + body > video').catch(() => {})) {
            GM_setValue('isLocalVideoEnded', false);
            video.requestFullscreen().catch(() => {
                video.style.width = "100%";
                video.style.height = "100%";
                document.body.style.margin = "0px";
            });
            video.onended = () => {
                GM_setValue('isLocalVideoEnded', true);
                window.close();
            }
        }
    }
})();