Greasy Fork

stream4chan

Click the button to stream all webms in a 4chan thread

目前为 2017-01-04 提交的版本。查看 最新版本

// ==UserScript==
// @name         stream4chan
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  Click the button to stream all webms in a 4chan thread
// @author       Lauchlan105
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// @require      http://code.jquery.com/jquery-latest.min.js
// @match        http://boards.4chan.org/*/thread/*
// @grant        none
// ==/UserScript==

/////////////////////////////////////
//////////////Settings///////////////
/////////////////////////////////////
settingsArray = [

    //Start Stream4Chan Automatically
    true,

    //Debug on startup
    false,

    //Gif duration increment value
    0.25,

    //Gif duration (seconds)
    3,

    //Automatically play next video
    true,

    //Play Webms
    true,

    //Play Gifs
    true,

    //Play thread on repeat
    true,

    //Start thread in random order
    false,

    //img to use for loading gif
    'https://raw.githubusercontent.com/gabrielgio/FChan/master/4chan.png'

];
/////////////////////////////////////
//////////////Settings///////////////
/////////////////////////////////////


//Main
(function() {
    createElements();
    initElements();
    startEvents();

    if(autoStart){ start(); }
})();


function createElements(){

    //Using Settings Array Variables
    var z = 0; //Keeps count of array option correspondence to make adding options easier
    autoStart = settingsArray[z++];
    debugOn = settingsArray[z++];
    countStep = settingsArray[z++];
    var durationDefault = settingsArray[z++];
    var autoPlayDefault = settingsArray[z++] ? 'checked' : '';
    var playWebmsDefault = settingsArray[z++] ? 'checked' : '';
    var playGifsDefault = settingsArray[z++] ? 'checked' : '';
    var loopThreadDefault = settingsArray[z++] ? 'checked' : '';
    var randomDefault = settingsArray[z++] ? 'checked' : '';

    //Loading Spinner
    spinner = document.createElement("img");
    spinner.setAttribute("src",settingsArray[z++]);
    spinner.setAttribute("id","stream4chan-spinner");
    spinner.setAttribute("class","SFC-loading");

    //Arrays
    hiddenPrints = [];
    hrefs = [];
    backup = [];
    preload(hrefs);

    //Settings Header
    var modalSettings_auto = '<input id="stream4chan-auto?" class="SFC-input" type="checkbox" ' + autoPlayDefault + '> Play Automatically';
    var modalSettings_webms = '<input id="stream4chan-webms?" class="SFC-input" type="checkbox" ' + playWebmsDefault + '> Play Webms';
    var modalSettings_gifs = '<input id="stream4chan-gifs?" class="SFC-input" type="checkbox" ' + playGifsDefault + '> Play Gifs';
    var modalSettings_loopAll = '<input id="stream4chan-loopAll?" class="SFC-input" type="checkbox" ' + loopThreadDefault + '> Loop whole thread';
    var modalSettings_shuffle = '<input id="stream4chan-shuffle?" class="SFC-input" type="button" value=" shuffle ">';
    var modalSettings_random = '<input id="stream4chan-random?" class="SFC-input" type="checkbox" ' + randomDefault + '> Random';
    var modalSettings_duration = '<input id="stream4chan-duration?" class="SFC-input" type="number" min="' + countStep + '" max="60" value="' + durationDefault + '" step="' + countStep + '"> Gif Duration (Seconds)';
    var modalSettings_exit = '<div id="SFC-exit" class="SFC-li SFC-exit"></div>';
    var modalSettings = '<div id="stream4chan-settings" class="SFC-settings">' + modalSettings_auto + modalSettings_webms + modalSettings_gifs + modalSettings_loopAll + modalSettings_shuffle + modalSettings_random + modalSettings_duration + modalSettings_exit + '</div>';

    //Content Table
    var modalContent = '<div id="stream4chan-content" class="SFC-content"></div>';
    var modalContent_Left = '<th id="stream4chan-prev" class="SFC_th_left SFC_arrow"></th>';
    var modalContent_Right = '<th id="stream4chan-next" class="SFC_th_right SFC_arrow"></th>';
    var modalContent_Mid = '<th class="SFC_th_mid">' + modalSettings + modalContent + '</th>';
    var modalTable = '<table id="stream4chan-table" class="SFC_table"><tr class="SFC_table_row">' + modalContent_Left + modalContent_Mid + modalContent_Right + '</tr></table>';

    //Main Div
    var startBtn = '<input id="stream4chan-start" style="margin-left:1em;" type="button" value="Run Slideshow" >';
    var resumeBtn = '<input id="stream4chan-resume" style="margin-left:1em;" type="button" value="Resume Slideshow" >';
    var modalMain = '<div id="stream4chan-modal" class="SFC-modal">' + modalTable + '</div>';

    //CSS
    var settingsCSS = '.SFC-settings { opacity: 0.35; display: inline-block; list-style-type: none; width:100%; top: 0; height: auto; margin: 0em; padding-top: 0.5em; color:#9d9393; }';
    var hoverCSS = '.SFC-settings:hover { opacity: 1; } .SFC-settings:last-child:hover { opacity: 0; }';
    var settingsInputCSS = '.SFC-input { margin: 0em 0em 0em 1.5em; padding: 0em;  }';
    var settingsExitCSS = '.SFC-exit { float: right; height: 28px; width: 28px; background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/7/72/VisualEditor_-_Icon_-_Close_-_white.svg/2000px-VisualEditor_-_Icon_-_Close_-_white.svg.png"); background-size: contain; }';
    var AllSettingsCSS = settingsCSS + hoverCSS + settingsInputCSS + settingsExitCSS;

    //table
    var tableCSS = '.SFC_table { max-height: 100vh; min-height: 100vh; max-width: 100vw; min-width: 100vw; } ';
    var tableRowCSS = '.SFC_table_row { vertical-align: top; }';
    var arrowCSS = '.SFC_arrow { width: 15px; padding: 15px; height: 100%; background-image: url("http://www.dsetechnology.co.uk/images/disclose-arrow.png"); background-repeat: no-repeat; background-position: center; background-color: rgba(255, 255, 255, 0); background-size: contain; }';
    var leftCSS = '.SFC_th_left { opacity: 0.14; transform: rotate(180deg); }' + '.SFC_th_left:hover { opacity: 1; background-color:rgba(255, 255, 255, 0.6); }';
    var rightCSS = '.SFC_th_right { opacity: 0.14;  }' + '.SFC_th_right:hover { opacity: 1;  background-color:rgba(255, 255, 255, 0.6); }';
    var midCSS = '.SFC_th_mid { height: 100vh;  }';
    var allTableCSS = tableCSS + tableRowCSS + arrowCSS + leftCSS + rightCSS + midCSS;

    var mediaCSS = '.SFC-media { width: 100%; }';
    var contentCSS = '.SFC-content { cursor: default; display: block; }';
    var modalCSS = ' .SFC-modal { display: none; height: 100vh; width: 100vw; position: fixed; z-index: 1; left: 0; top: 0; background-color: rgba(0,0,0,0.88); -webkit-box-shadow: inset 0px 0px 71px 41px rgba(0,0,0,0.75); -moz-box-shadow: inset 0px 0px 71px 41px rgba(0,0,0,0.75); box-shadow: inset 0px 0px 71px 41px rgba(0,0,0,0.75);}';
    var loadingCSS = '.SFC-loading { margin-top: 100%idth: 200px; height: 200px; animation-name: load; animation-duration: 3s; animation-iteration-count: infinite;animation-timing-function: ease-in-out;}' +
        '@keyframes load { 0%{ transform: rotate(0deg); } 80%{ transform: rotate(360deg); } 100%{ transform: rotate(360deg); } }';
    var allModalCSS = loadingCSS + mediaCSS + contentCSS + modalCSS;
    var allCSS = '<style>' + allModalCSS + allTableCSS + AllSettingsCSS + '</style>';


    //Add start and resume buttons
    var nav = document.getElementsByClassName('navLinks desktop');
    for(var i = 0; i < nav.length; i++){
        debug('adding button to nav ' + i);

        var span = document.createElement('span');

        span.innerHTML = startBtn + resumeBtn;
        span.className = 'stream4chan-start';
        span.style.display = nav[i].style.display;

        nav[i].parentNode.insertBefore(span, nav[i]);
        nav[i].parentNode.insertBefore(document.getElementById('op'), nav[i]);
    }

    //add the modal to start of thread
    var target = document.getElementsByClassName('thread');
    for(i = 0; i < target.length; i++){
        target[i].innerHTML = (modalMain + allCSS) + target[i].innerHTML;
    }
}

function initElements(){
    modal = document.getElementById('stream4chan-modal');
    if(!modal){ debug('Modal not found!'); }

    table = document.getElementById('stream4chan-table');
    if(!table){ debug('Table not found!'); }

    settings = document.getElementById('stream4chan-settings');
    if(!settings){ debug('Settings not found!'); }

    content = document.getElementById('stream4chan-content');
    if(!content){ debug('Content not found!'); }

    //Interactable Elements
    prevButton = document.getElementById('stream4chan-prev');
    if(!prevButton){ debug('Previous Button not found!'); }

    nextButton = document.getElementById('stream4chan-next');
    if(!nextButton){ debug('Next Button not found!'); }

    startButton = document.getElementById('stream4chan-start');
    if(!startButton){ debug('Start Button could not be found!');}

    resumeButton = document.getElementById('stream4chan-resume');
    if(!resumeButton){ debug('Resume Button could not be found!');}

    autoplay = document.getElementById('stream4chan-auto?');
    if(!autoplay){ debug('Autoplay checkbox not found!');}

    playWebms = document.getElementById('stream4chan-webms?');
    if(!playWebms){ debug('Player Webms input not found!');}

    playGifs = document.getElementById('stream4chan-gifs?');
    if(!playGifs){ debug('Player Gifs input not found!');}

    loop = document.getElementById('stream4chan-loopAll?');
    if(!loop){ debug('"loopAll" could not be found!'); }

    random = document.getElementById('stream4chan-random?');
    if(!random){ debug('"random" could not be found!'); }

    shuffle = document.getElementById('stream4chan-shuffle?');
    if(!shuffle){ debug('"shuffle" could not be found!'); }

    duration = document.getElementById('stream4chan-duration?');
    if(!duration){ debug('Gif duration input not found!');}

    exit = document.getElementById('SFC-exit');
    if(!exit){ debug('Exit not found!');}

    currentVideo = 'start';
    currentTime = 0;
    currentTimeout = setTimeout(0);
    modalOn = false;
    shuffled = false;
}

function startEvents(){

    //Window/Document Events
    magicMouse();
    window.onresize = function(){ setDimensions(contentExists()); };
    window.onclick = function(event){if (event.target.id == 'stream4chan-content'){ stop(); }};

    //Key Down Events
    window.onkeydown = function(event){
        event.target.blur();
        if(!toggleDebug(event)){
            //up arrow
            if(event.keyCode == 38 && modalOn){
                duration.stepUp();
            }

            //Down arrow
            if(event.keyCode == 40 && modalOn){
                duration.stepDown();
            }

            if (event.keyCode == 13 && event.shiftKey){
                if(!modalOn){
                    start(currentVideo, currentTime);
                }
            }else if(event.keyCode == 13){
                if(!modalOn){
                    start();
                }
            }
        }
    };

    //Key Up Events
    window.onkeyup = function(event){
        event.target.blur();
        if(modalOn){
            //left arrow
            if(event.keyCode == 37){
                previousVideo();
            }

            //right arrow
            if(event.keyCode == 39){
                nextVideo();
            }

            //Escape key
            if(event.keyCode == 27){
                stop();
            }

            //W key
            if(event.keyCode == 87){
                playWebms.checked = !playWebms.checked;
            }

            //G key
            if(event.keyCode == 71){
                playGifs.checked = !playGifs.checked;
            }

            //A key
            if(event.keyCode == 65){
                autoplay.checked = !autoplay.checked;
                applyAutoplay();
            }

            //L key
            if(event.keyCode == 76){
                loopAll.checked = !loopAll.checked;
            }

            //R key
            if(event.keyCode == 82){
                random.checked = !random.checked;
                if(random.checked){
                    shuffleArr();
                }else{
                    unshuffleArr();
                }
            }

            //S key
            if(event.keyCode == 83){
                if(shuffle.value === ' shuffle '){
                    shuffleArr();
                }else{
                    unshuffleArr();
                }
            }

            //Space key
            if(event.keyCode == 32){
                if(contentExists('webm')){
                    if(hrefs[currentVideo].paused){
                        hrefs[currentVideo].play();
                    }else{
                        hrefs[currentVideo].pause();
                    }
                }
            }
        }
    };

    //Page Element Events
    exit.onclick = function(){ stop(); };
    startButton.onclick = function(){ start(); };
    resumeButton.onclick = function(){ start(currentVideo, currentTime); };
    autoplay.onclick = function(){ applyAutoplay(); };
    random.onclick = function(){
        if(random.checked){
            shuffleArr();
        }else{
            unshuffleArr();
        }
    };
    prevButton.onclick = function(){ previousVideo(); };
    nextButton.onclick = function(){ nextVideo(); };
    shuffle.onclick = function(){
        if(shuffle.value === ' unshuffle '){
            unshuffleArr();
        }else{
            shuffleArr();
        }
    };

}

function displayModal(state){

    //if state toggles modal if a state is not specified
    if(state === true){
        debug('Show Modal');
        modalOn = state;
        modal.style.display = 'block';

        //removes scoll bar
        document.body.style.overflow = 'hidden';
    }else if(state === false){
        debug('Hide Modal');
        modalOn = state;
        modal.style.display = 'none';

        //removes scoll bar
        document.body.style.overflow = 'scroll';
    }else{
        if(!modalOn){
            debug('Show Modal');
            modal.style.display = 'block';

            //removes scoll bar
            document.body.style.overflow = 'hidden';
        }else{
            debug('Hide Modal');
            modal.style.display = 'none';

            //removes scoll bar
            document.body.style.overflow = 'scroll';
        }
        modalOn = !modalOn;
    }
}

function start(crntVid, crntTime){
    var newStart = (!crntVid && (crntVid !== 0));
    currentVideo = !newStart ? crntVid-1 : 'start';
    currentTime = crntTime ? crntTime : 0;

    //resume if starting from the beginning
    if(newStart){ unshuffleArr(); }

    displayModal(true);
    content.innerHTML = '';
    content.appendChild(spinner);

    //If document is loaded
    if (document.readyState === "complete") {
        nextVideo();
    }else{
        debug('page still loading');
        window.onload = function(){
            debug('page loaded');
            if(modalOn){
                nextVideo();
            }
        };
    }
}

function stop(){
    if(contentExists()){
        currentTime = contentExists('webm') ? contentExists('webm').currentTime : 0;
        pauseContent();
    }
    content.innerHTML = '';
    displayModal(false);
}

function nextVideo(){
    debug('Function: nextVideo');

    pauseContent();
    if(currentVideo === 'start'){ currentVideo = -1; }

    //While the href can't be played
    do{
        currentVideo++;
        if(loop.checked){
            currentVideo = currentVideo % hrefs.length;
        }

        var temp = noContentToDisplay();
        if(temp){
            stop();
            displayModal(true);
            content.innerHTML = temp;
            return;
        }
    }while(!canPlay(hrefs[currentVideo]));

    //Play specified video/img element
    playContent(hrefs[currentVideo]);
}

function previousVideo(){
    debug('Function: previousVideo');

    pauseContent();
    if(currentVideo === 'start'){ currentVideo = 0; }

    //While the href can't be played
    do{
        currentVideo--;
        if(loop.checked){
            if(currentVideo === -1){ currentVideo = hrefs.length -1;}
        }

        var temp = noContentToDisplay();
        if(temp){
            stop();
            displayModal(true);
            content.innerHTML = temp;
            return;
        }
    }while(!canPlay(hrefs[currentVideo]));

    //Play specified video/img element
    playContent(hrefs[currentVideo]);
}

function playContent(currentContent){
    debug('Function: playContent');

    if(random.checked){
        shuffleArr();
    }

    content.innerHTML = '';
    content.appendChild(spinner);

    //Play specified video/img element
    //If its a webm, play when loaded, otherwise play immediately
    if(getFileExt(currentContent.src) === 'webm' ){
        if(currentContent.canStart){
            showContent();

            //add events for next video
            applyAutoplay();
        }else{
            currentContent.oncanplaythrough = function(){
                x.oncanplaythrough = function(){ this.canStart = true; };
                showContent();

                //add events for next video
                applyAutoplay();
            };
        }
    }else{
        showContent();

        //add events for next video
        applyAutoplay();
    }
}

function showContent(){

    content.innerHTML = '';
    content.appendChild(hrefs[currentVideo]);

    setDimensions(contentExists());

    if(contentExists('webm')){
        contentExists('webm').currentTime = currentTime;
        currentTime = 0;
        contentExists('webm').play();
    }
}

function pauseContent(){
    debug('Function: pauseContent');
    var x = contentExists('webm');
    if(x){
        x.removeEventListener('ended', nextVideo, false);
        x.loop = true;
        x.pause();
    }
    clearTimeout(currentTimeout);
    content.appendChild(spinner);
}

function canPlay(currentContent){
    return ( (playGifs.checked && (getFileExt(currentContent.src) === 'gif')) || (playWebms.checked && (getFileExt(currentContent.src) === 'webm')) );
}

function getFileExt(input){
    temp = input.toString();
    return temp.substr(temp.lastIndexOf('.') + 1);
}

function preload(arr){
    debug('Function: preload');

    var temp = document.getElementsByClassName('fileThumb');
    var x = null;

    //Iterates over number of gif/webms in a thread
    for (i = 0; i < temp.length; i++){

        debug('    intitializing element: ' + temp[i]);

        //If (gif){
        //} else if (webm){
        //} else {}
        if(getFileExt(temp[i]) == 'gif'){
            x = document.createElement('img');
            x.setAttribute("id", "stream4chan-gif");
        }else if (getFileExt(temp[i]) == 'webm'){
            x = document.createElement('video');
            x.setAttribute("id", "stream4chan-webm");
            x.setAttribute("controls","");

            x.setAttribute("loop","");
            x.loop = true;

            x.setAttribute("autoplay","");
            x.autoplay = false;

            x.setAttribute("ended","");
            x.ended = false;

            x.setAttribute("preload", "");
            x.preload = 'auto';

            x.setAttribute("canStart", "false");
            x.canStart = false;

            x.oncanplaythrough = function(){ this.canStart = true; };
        }
        x.setAttribute("src",temp[i]);
        x.setAttribute("style", "height: 100%; width: auto;");
        arr.push(x);
        backup.push(x);
    }
}

function debug(text){
    if(debugOn){
        console.log(text);
    }else{
        hiddenPrints.push(text);
    }
}

function toggleDebug(e) {
    var evtobj = window.event? event : e;
    if (!e || evtobj.keyCode == 68 && evtobj.ctrlKey && evtobj.altKey && evtobj.shiftKey){
        debug('Function: toggleDebug');
        if(debugOn){
            console.log('##Debug Off##');
            debugOn = false;
        }else{
            console.log('##Debug On##');
            debugOn = true;
            for(var i = 0; i < hiddenPrints.length; i++){
                debug(hiddenPrints[i]);
            }
            hiddenPrints = [];
        }
        return true;
    }
    return false;
}

function setDimensions(e){
    debug('Function: setDimensions');
    content.style.height = window.innerHeight - (settings.offsetHeight*2) + 'px';
    if(e){
        e.style.height = '100%';
        e.style.width =  'auto';
        if(e.offsetWidth > (window.innerWidth - (prevButton.offsetWidth + nextButton.offsetWidth))){
            debug('    Content was wider');
            e.style.height = 'auto';
            e.style.width =  '100%';
        }

        e.style.marginTop = ((content.offsetHeight - e.offsetHeight)/2) + 'px';
        e.style.marginBottom = ((content.offsetHeight - e.offsetHeight)/2) + 'px';
    }
}

function contentExists(type){
    debug('Function: contentExists');
    if(type){
        return document.getElementById('stream4chan-' + type);
    }else{
        var div = document.getElementById('stream4chan-webm');
        if(!div){ div = document.getElementById('stream4chan-gif'); }
        return div;
    }
}

function thereAre(type){
    debug('Function: thereAre');
    if(type){
        for(i = 0; i < hrefs.length; i++){
            if(getFileExt(hrefs[i].src) === type){
                return true;
            }
        }
    }
    debug('    Error: argument not passed to function');
    return false;
}

function noContentToDisplay(){
    debug('Function: noContentToDisplay');
    var text = false;

    //End and display modal if nothing can play
    if(!playGifs.checked && !playWebms.checked){
        text = 'Nothing selected to play';
    }

    //End and display modal if nothing can play
    if(!thereAre('gif') && (playGifs.checked && !playWebms.checked)){
        text = 'No gifs!';
    }

    //End and display modal if nothing can play
    if(!thereAre('webm') && (!playGifs.checked && playWebms.checked)){
        text = 'No Webms!';
    }

    //End and display modal if nothing can play
    if(!thereAre('gif') && !thereAre('webm')){
        text = 'No Gifs or Webs';
    }

    //End and display modal if out of range
    if( 0 > currentVideo || currentVideo > hrefs.length-1){
        text = 'End of Thread';
        if(currentVideo < 0){ text = 'Start of thread'; }
    }
    if(text){ debug('    Returning: '+ text); }
    return text;
}

function applyAutoplay(){
    debug('Function: applyAutoplay');

    var x = contentExists();
    debug('    ' + getFileExt(x.src) + ' event listener is ' + autoplay.checked);
    clearTimeout();

    if(getFileExt(x.src) === 'webm'){
        x.loop = !autoplay.checked;
        x.removeEventListener('ended', nextVideo, false);
        if(autoplay.checked){
            x.addEventListener('ended', nextVideo, false);
        }
    }

    if(getFileExt(x.src) === 'gif' && autoplay.checked){
        currentTimeout = setTimeout(nextVideo, duration.value*1000);
    }
}

function shuffleArr() {
    debug('Function: shuffleArr');
    var j, x, i;
    for (i = hrefs.length; i; i--) {
        j = Math.floor(Math.random() * i);
        x = hrefs[i - 1];
        hrefs[i - 1] = hrefs[j];
        hrefs[j] = x;
    }
    shuffled = true;
    shuffle.value = ' unshuffle ';
}

function unshuffleArr() {
    debug('Function: unshuffleArr');
    hrefs = backup.slice();
    if(contentExists()){
        for(var i = 0; i < hrefs.length; i++){
            if(hrefs[i].src === contentExists().src){
                currentVideo = i;
                break;
            }
        }
    }
    shuffled = false;
    shuffle.value = ' shuffle ';
}

function magicMouse() {
    var mouseTimer = null, cursorVisible = true;

    document.onmousemove = function() {
        if (mouseTimer) {
            window.clearTimeout(mouseTimer);
        }

        if (!cursorVisible) {
            debug('adding cursor');
            content.style.cursor = 'auto';
            cursorVisible = true;
        }

        mouseTimer = window.setTimeout(function(){
            debug('removing cursor');
            mouseTimer = null;
            content.style.cursor = 'none';
            cursorVisible = false;
        }, 1500);
    };
}