bs.to and vivo enhancer

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

As of 2021-07-22. See the latest version.

// ==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.2
// @run-at         document-start
// @license        CC BY 4.0
// @namespace https://greasyforks.org/users/140785
// @grant    GM_setValue
// @grant    GM_getValue
// ==/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 (https://greasyforks.org/de/scripts/400669-burningseries-autoplay/code)
    waitForElement(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,
            });
        });
    }

    // thanks to xZaheer (https://greasyforks.org/de/scripts/400669-burningseries-autoplay/code)
    async clickPlay() {
        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);
            //let elem = await this.waitForElement('.hoster-player a').catch(() => {});
            //window.open(elem.href);
        }
    }

    buildButton() {
        const style = document.createElement('style');
        style.innerHTML = `
  @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-inner:before {
content: "Video-URL in die Zwischenablage kopieren und Tab schließen";
    padding-left: 14px;
    background-color: #2FB536;
    color: #FFFFFF;
    text-align: start;
}
.onoffswitch-inner:after {
    content: "Vivo Autoplay aktivieren";
    padding-right: 14px;
    background-color: #12A6F6; color: #FFFFF1;
    text-align: end;
}
.onoffswitch-switch {
    display: block; width: 23px; margin: 3.5px;
    background: #FFFFF2;
    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: 175px;
}
  `;
        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" style="color:white;"></i>' +
            '</div>';
        button['style'] = 'position: relative; height: 0;'
        document.getElementById('sp_left').appendChild(button);

        const menu = document.createElement("div");
        menu['innerHTML'] = '<div class="onoffswitch"><input type="checkbox" name="onoffswitch" class="onoffswitch-checkbox" id="xtrars-onoffswitch" tabindex="0"><label class="onoffswitch-label" for="xtrars-onoffswitch"><span class="onoffswitch-inner"></span><span class="onoffswitch-switch"></span></label></div>';
        menu['style'] = 'display: none;';
        menu['id'] = 'xtrars-menu';
        document.getElementById('xtrars-btn').appendChild(menu);
        document.getElementById('xtrars-onoffswitch').checked = GM_getValue('bCloseTabAfterCopyToClipboard');

        button.addEventListener('mouseover', () => {
            menu['style'] = 'display: block; position: absolute; bottom: 10px; height: 50px; width: 50px; line-height: normal;'
            document.getElementById('xtrars-btn')['style'] = 'background: transparent;';
        });

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

        menu.addEventListener('change', () => {
            GM_setValue('bCloseTabAfterCopyToClipboard', document.getElementById('xtrars-onoffswitch').checked)
        });
    }
}


(async function() {
    'use strict';

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

        if (GM_getValue('bCloseTabAfterCopyToClipboard')) {
            navigator.clipboard.writeText(sSrc);
            window.close();
        } else {
            window['location'].replace(sSrc);
        }
    }

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

        if (!siteHandler.hasAnotherHoster() && siteHandler.isVivoTab() && await siteHandler.waitForElement('#sp_left').catch(() => {})) {
            siteHandler.buildButton();
            siteHandler.clickPlay();
            // TODO Einstellungsmöglichkeiten erweitern (Vollbild, automatisch Tab wählen, etc)
        }
    }

    let video;
    if (video = await siteHandler.waitForElement('html > head + body > video').catch(() => {})) {
        video.requestFullscreen().catch(() => {
            video.style.width = "100%";
            video.style.height = "100%";
            document.body.style.margin = "0px";
        });
    }
    // TODO tab am Ende schließen
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。