Greasy Fork

Greasy Fork is available in English.

stream4chan

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

当前为 2017-01-04 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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);
    };
}