Greasy Fork

Greasy Fork is available in English.

stream4chan

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

当前为 2017-03-29 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         stream4chan
// @namespace    http://tampermonkey.net/
// @version      3.0
// @description  Click the button to stream all webms in a 4chan thread
// @author       Lauchlan105
// @match        http://boards.4chan.org/*/thread/*
// @grant        none
// ==/UserScript==

//////////////////
// # Settings # //
//////////////////

var settingsArray = [
    
    //Loop whole thread
    true,

    //Play automatically
    true,

    //Randomize on startup
    false,

    //Play Webms
    true,

    //Show Webm controls
    true,

    //Play webm sound
    true,

    //Play Gifs
    true,

    //Gif duration (Seconds)
    3,

    //Play Images
    true,

    //Image duration (Seconds)
    3,

    //Open Stream4chan on startup
    true
];

///////////////////
// # Variables # //
///////////////////

//Placeholder variables
var globalTimeout;
var webm;
var gif;
var png;
var jpg;
var SOT;
var EOT;
var noneSelected;
var allContent;
var usedContent;
var currentContent;

//////////////////////
// # Object Model # //
//////////////////////

//Class constructor for content elements
class Media{
    constructor(thumb, source, id){

    	// local scope variable for object access via video/thumbnail elements
        var obj = this;

        this.position = 0;

        this.id = id === undefined ? "" : id;

        this.thumb = document.createElement('img');
        this.thumb.src = thumb;
        this.thumb.setAttribute('class','sfc-slide-preview');

        this.type = mediaType(source);

        //Handles deleted files/invalid media
        if(this.type === undefined || this.type === null){

        	//Force null for simpler conditionals
        	this.type = null;

        	console.log('Media has been given invalid source');
        	console.log('	Given Arguments:');
        	console.log('		thumb: ' + thumb);
        	console.log('		source: ' + source);
        	console.log('		id: ' + id);
        	console.log('');
        	console.log('	All functions will be assigned placeholders');

        	this.play = function(){
		        			console.log('This object is not valid and');
			        		console.log(calledFunction + ' cannot be called in this object');
			        		return;
		        		};

        	this.pause = function(){
		        			console.log('This object is not valid and');
			        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
			        		return;
		        		};

	       	this.highlight = function(){
			        			console.log('This object is not valid and');
				        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
				        		return;
			        		};

			this.unhighlight = 	function(){
				        			console.log('This object is not valid and');
					        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
					        		return;
				        		};

    		this.select = 	function(){
			        			console.log('This object is not valid and');
				        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
				        		return;
			        		};

			this.deselect = function(){
			        			console.log('This object is not valid and');
				        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
				        		return;
			        		};

			this.resize = function(){
			        			console.log('This object is not valid and');
				        		console.log(arguments.callee.caller.toString() + ' cannot be called in this object');
				        		return;
			        		};
        	return false;
        }

    	if(this.type === webm){
            this.media = document.createElement('video');

            this.media.setAttribute("id", "sfc-webm");

            this.media.setAttribute("controls","");

            this.media.setAttribute("loop","");
            this.media.loop = true;

            this.media.setAttribute("autoplay","");
            this.media.autoplay = false;

            this.media.setAttribute("preload","");
            this.media.preload = "none";

        }else if(this.type === png || this.type === gif || this.type === jpg){
            this.media = document.createElement('img');
            this.media.setAttribute("id","sfc-img");
        }

    	this.media.setAttribute("class", "sfc-media");
    	this.media.src = source;


        ///////////////////
        //MEDIA FUNCTIONS//
        ///////////////////
    	this.play = function(){

        	if(obj !== SOT && obj !== EOT && obj !== noneSelected){
        		if(obj.type == webm){
	                obj.media.volume = op_playSound.checked ? obj.media.volume : 0;
	                obj.media.play();
	            }else if(obj.type == gif){
	                //Restart gif
	                obj.media.src = obj.media.src;
	            }

	            //Load neighbouring media
	            var prevMedia = obj.position === 0 ? usedContent[usedContent.length - 1] : usedContent[obj.position - 1];
	            var nextMedia = obj.position === usedContent.length - 1 ? usedContent[0] : usedContent[obj.position + 1];
	            if(prevMedia.type === webm){
	                prevMedia.media.load();
	            }else if(nextMedia.type === webm){
	                nextMedia.media.load();
	            }
        	}
        };

        this.pause = function(){
            clearTimeout(globalTimeout);
            if(obj.type == webm){
                obj.media.pause();
            }
        };

        ///////////////////////
        //THUMBNAIL FUNCTIONS//
        ///////////////////////

        var highlight = function(){

            obj.thumb.style.border = "2px solid gainsboro";

            /*

			//Scroll into view
	        var pc = document.getElementById('pc' + id.substr(id.lastIndexOf('p') + 1));
  	 		pc.scrollIntoView();

			//Set container style to mimic focused content 
  			pc.style.background = '#f0e0d6';
    		pc.style.border = '1px solid #D99F91!important';

    		*/
        };

        var unhighlight = function(){

            obj.thumb.style.border = "2px solid transparent";

			/*

			//Remove focused content styles           
 			var pc = document.getElementById('pc' + id.substr(id.lastIndexOf('p') + 1));
  			pc.style.background = '#F0C0B0!important';
    		pc.style.border = '1px solid #D9BFB7';

    		*/
        };

        ///////////////////////////
        //MISCELLANEOUS FUNCTIONS//
        ///////////////////////////

        this.select = function(){

            //Deselect active content
            if(currentContent !== null){
                currentContent.deselect();
            }

            //Set currentContent to this object
            currentContent = obj;

            //Highlight thumbnail border
            highlight();

            //Add media to stage
            obj.media.controls = op_controls.checked;
            el_stage.appendChild(obj.media);

            //Play Media
            obj.play();

            //resize media
            obj.resize();

            //Update auto playing
            updateAutoplay();

            //Moves gallery so selected object is centered

            //half of thumbnail width
            el_internalSlider.style.transform = '';
            var middleOfThumb = getPageTopLeft(obj.thumb).left + (obj.thumb.clientWidth/2);
            var middleOfWindow = window.innerWidth/2;
            var distance = middleOfThumb - middleOfWindow;
            var distanceFromMiddle = distance > 0 ? distance*-1 : distance + ((-1*distance)*2);
            el_internalSlider.style.transform = 'translateX( ' + distanceFromMiddle + 'px)';
        };


        this.deselect = function(){

            obj.pause();
            obj.media.currentTime = 0;
            unhighlight();
            el_stage.innerHTML = "";
            currentContent = null;
        };

        this.thumb.onclick = function(){
        	if(obj.thumb.style.border == "2px solid gainsboro"){
        		obj.deselect();
        	}else{
        		obj.select();
        	}
        };

        this.resize = function(){

        	var resizeTimeout = setTimeout(function(){}, 0);

        	//Recursive resize function
        	//repeats every {interval} seconds
        	//if interval is undefined or < 0.01, default to 0.01
        	function execResize(interval){

        		//if interval is below 0.01, set to minimum 0.01
        		if(interval){
        			if(interval < 0.05){
        				interval = 0.05;
        			}
        		}

        		if(obj === currentContent){
                    var setByWidth = true;

    				//Set to max width
					obj.media.style.width = window.innerWidth - (el_stagePrev.clientWidth + el_stageNext.clientWidth) + 'px';
        			obj.media.style.height = 'auto';

        			//if media height exceeds the stage height
        			if(obj.media.clientHeight > el_stage.clientHeight){
        				//Set to max height instead
                        console.log('too tall');
	        			obj.media.style.height = el_stage.clientHeight + 'px';
	        			obj.media.style.width = 'auto';
                        setByWidth = false;
	        		}

                    if(setByWidth){
                        //if full width, set height padding
                        // var difHeight = (el_stage.clientHeight - obj.media.clientHeight)/2;
                        // var topMarg = (difHeight) - ( difHeight%1 ); //Minus any decimals
                        // obj.media.style.marginTop = topMarg  + 'px';
                    }else{
                        //if full height, set width padding
                        // var difWidth = (el_stage.clientWidth - obj.media.clientWidth)/2;
                        // var leftMarg = (difWidth) - ( difWidth%1 ); //Minus any decimals
                        // obj.media.style.marginLeft = leftMarg  + 'px';
                    }

        			if(interval){
        				setTimeout(function(){
							execResize(interval);
						}, interval*1000);
        			}else{
        				return;
        			}
        		}else{
        			clearTimeout(resizeTimeout);
        		}
        		return;
        	}

        	//Continue resizing every 1 second till video ends
        	execResize();
            execResize();
            execResize();
            execResize();
            execResize();

        };

        this.media.getObj = function(){ return obj; };
        this.thumb.getObj = function(){ return obj; };


        return true;
    }
}

//////////////
// # Main # //
//////////////

(function(){
    insertElements();
    initVars();
    initPlaceholders();
    startInteractions();
    startEventListeners();
    applyDefaulSettings();

    //Show and hide gallery to force load thumbnails
    //otherwise .select() does not work until gallery is shown
    showGallery(true);
    showGallery(false);

    sfc.style.display = "none"; //Force hide SFC
    showSFC(false);             //Force styles to be ready for fade in 

    //If open on startup is selected -> open on startup
    if(settingsArray[10]){
        showSFC(true);
        usedContent[0].select();
    }
})();

/////////////////////////////////
// # Initial Setup Functions # //
/////////////////////////////////

//Insert html for buttons and modal
function insertElements(){

    //Start Button
    var btn1 = '[<a id="sfc-start" href="#">start</a>]';
    var btn2 = '[<a id="sfc-resume" href="#">resume</a>]';

    //Add span to nav
    var nav = document.getElementsByClassName('navLinks desktop');
    for(var i = 0; i < nav.length; i++){
        var span = document.createElement('span');
        span.innerHTML = btn1 + " " + btn2;

        span.className = 'sfc-nav';
        span.style.display = nav[i].style.display;

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

    var html = '<!-- SETTINGS --> <div id="sfc-settings-column"> <div id="sfc-settings-row"> <div id="sfc-settings-panel"> Settings <div id="sfc-settings-exit"></div> <!-- GENERAL SETTINGS --> <div> <p class="sfc-settings-title"> General </p> <div id="sfc-option"> <input id="stream4chan-loopAll" class="SFC-input" type="checkbox"> Loop whole thread (L) </div> <div id="sfc-option"> <input id="stream4chan-auto" class="SFC-input" type="checkbox"> Play Automatically (A) </div> <div id="sfc-option"> <input id="stream4chan-random" class="SFC-input" type="checkbox"> Random (R) </div> <div id="sfc-option"> <input id="stream4chan-shuffle" class="SFC-input" type="button" value=" Shuffle "> (S) </div> </div> <!-- WEBM SETTINGS --> <div> <p class="sfc-settings-title"> Webm </p> <div id="sfc-option"> <input id="stream4chan-webms" class="SFC-input" type="checkbox"> Play Webms (W) </div> <div id="sfc-option"> <input id="stream4chan-controls" class="SFC-input" type="checkbox"> Show Controls (C) </div> <div id="sfc-option"> <input id="stream4chan-playSound" class="SFC-input" type="checkbox"> Play sound (S) </div> </div> <!-- GIF SETTINGS --> <div> <p class="sfc-settings-title"> Gif </p> <div id="sfc-option"> <input id="stream4chan-gifs" class="SFC-input" type="checkbox"> Play Gifs (G) </div> <div id="sfc-option"> <input id="stream4chan-gif-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Gif Duration (up/down) </div> </div> <!-- IMG SETTINGS --> <div> <p class="sfc-settings-title"> Images </p> <div id="sfc-option"> <input id="stream4chan-imgs" class="SFC-input" type="checkbox"> Play Images (I) </div> <div id="sfc-option"> <input id="stream4chan-img-duration" class="SFC-input" type="number" min="1" max="60" value="3" step="1"> Image Duration (Shift + up/down) </div> </div> </div> </div> </div> <!-- Main --> <div id="sfc-main"> <div id="sfc-main-prev" class="sfc-util prev"></div> <div id="sfc-stage"> </div> <div id="sfc-utility"> <div id="sfc-main-settings" class="sfc-util settings"></div> <div id="sfc-main-gallery" class="sfc-util gallery"></div> </div> <div id="sfc-main-next" class="sfc-util next"></div> </div> <!-- Gallery Slider --> <div id="sfc-gallery"> <div id="sfc-gallery-prev" class="sfc-util prev"></div> <div id="sfc-slider"> <div id="sfc-slider-internal"> </div> </div> <div id="sfc-gallery-next" class="sfc-util next"></div> </div>';
    var css = '<!-- CSS --> <style> body, div, img, a, span, html, p{ margin: 0px; border: 0px; padding: 0px; } .sfc-nav{ height: auto; width: auto; } #sfc{ opacity: 1; -moz-transition: opacity 0.50s ease-in-out; -webkit-transition: opacity 0.50s ease-in-out; -o-transition: opacity 0.50s ease-in-out; -ms-transition: opacity 0.50s ease-in-out; transition: opacity 0.50s ease-in-out; } #sfc-main { width: 100%; height: 100%; z-index: 500; position: fixed; top: 0; display: flex; flex-flow: row; background-color: rgba(0,0,0,0.9 ); -webkit-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); -moz-box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); box-shadow: inset 0px 0px 300px 28px rgba(0,0,0,1); } #sfc-gallery{ width: 100%; height: auto; z-index: 1000; position: fixed; bottom: 0; display: flex; flex-flow: row; background-color: rgba(0,0,0,0.35); transform: translateY(100%); -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } #sfc-settings-column{ height: 100vh; z-index: 1500; top: 0; display: none; flex-flow: column; position: fixed; background-color: rgba(0,0,0,0.7); font-family: "PT Sans", sans-serif; font-size: 16pt; } #sfc-settings-row{ width: 100vw; display: flex; flex-flow: row; flex: 1 1 auto; } #sfc-settings-panel{ margin: auto; padding: 20px; flex: 0 1 auto; background-color: rgba(255,255,255,0.8); } .sfc-settings-title{ margin-top: 7%; text-decoration: underline; } #sfc-settings-exit { width: 20px; height: 20px; opacity: 0.3; float: right; background-image: url("http://www.myiconfinder.com/uploads/iconsets/4c515d45f6a8c4fe16e448a692a9370d.png"); background-size: contain; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } #sfc-settings-exit:hover{ opacity: 1; } #sfc-stage, #sfc-slider{ flex: 1 1 auto; margin: 5px; } #sfc-slider-internal{ width: 0px; } #sfc-utility{ position: fixed; bottom: 0; -webkit-transition: transform 0.4s ease-in-out 0.05s; transition: transform 0.4s ease-in-out 0.05s; } .sfc-util{ opacity: 0.1; width: 3vw; height: 3vw; background-color: rgba(255,255,255,0.6); background-clip: content-box; border-radius: 50%; background-size: 1.5vw; background-repeat: no-repeat; background-position:center; margin: auto; padding: 5px; -webkit-transition: opacity 0.2s linear 0.05s, visibility 0s; transition: opacity 0.2s linear 0.05s, visibility 0s; } .sfc-util:hover{ opacity: 1; } .gallery, .settings{ background-size: 2.2vw; } .gallery{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Photo_Video/gallery-24.png"); } .settings{ background-image: url("https://maxcdn.icons8.com/Android_L/PNG/24/Very_Basic/settings-24.png"); } .prev, .next { flex: 0 0 3vw; background-image: url("http://www.dsetechnology.co.uk/images/disclose-arrow.png"); } .prev{ transform: rotate(180deg); } .sfc-slide-preview{ height: 6vh; width: auto; border: 2px solid transparent; -webkit-transition: border 0.2s linear 0.05s, visibility 0s; transition: border 0.2s linear 0.05s, visibility 0s; } .sfc-slide-preview:hover { border: 2px solid white; } </style> ';

    var sfc = document.createElement('div');
    sfc.setAttribute('id','sfc');
    sfc.innerHTML = html + css;

    var target = document.getElementsByClassName('thread');
    for(i = 0; i < target.length; i++){
        target[i].prepend(sfc);
    }
}

//Create and initialize global variables for easy access to HTML elements
function initVars(){

    //Custom function to find elements while 
        //alerting console of errors in case of null || undefined
    function getEl(elName){
        var temp = document.getElementById(elName);
        if(temp === null || temp === undefined){
            temp = document.getElementsByClassName(elName)[0];
            if(temp === null || temp === undefined){
                console.log('### ERROR ###');
                console.log('initVars: getEl(\'' + elName +'\') returned... ');
                console.log(temp);
            }
        }
        return temp;
    }

    //Main Page
    el_startBtn = getEl('sfc-start');
    el_resumeBtn = getEl('sfc-resume');

    //Modal
    el_sfc = getEl('sfc');

    //Stage Area
    el_stage = getEl('sfc-stage');
    el_stagePrev = getEl('sfc-main-prev');
    el_stageNext = getEl('sfc-main-next');

    //Utility buttons
    el_util = getEl("sfc-utility");
    el_galleryBtn = getEl("sfc-main-gallery");
    el_settingsBtn = getEl("sfc-main-settings");

    //Gallery Area
    el_gallery = getEl("sfc-gallery");
    el_slider = getEl('sfc-slider');
    el_internalSlider = getEl('sfc-slider-internal');
    el_sliderPrev = getEl('sfc-gallery-prev');
    el_sliderNext = getEl('sfc-gallery-next');

    //Settings and option area
    el_settings = getEl("sfc-settings-column");
    el_settingsExit = getEl("sfc-settings-exit");
    op_loopAll = getEl('stream4chan-loopAll');
    op_auto = getEl('stream4chan-auto');
    op_random = getEl('stream4chan-random');
    op_shuffle = getEl('stream4chan-shuffle');

    op_webms = getEl('stream4chan-webms');
    op_controls = getEl('stream4chan-controls');
    op_playSound = getEl('stream4chan-playSound');

    op_gifs = getEl('stream4chan-gifs');
    op_gif_duration = getEl('stream4chan-gif-duration');

    op_imgs = getEl('stream4chan-imgs');
    op_img_duration = getEl('stream4chan-img-duration');
}

//Inititialize values to placeholder variables
function initPlaceholders(){
    //Type placeholders. Less quotations in code
    webm = 'webm';
    gif = 'gif';
    png = 'png';
    jpg ='jpg';

    //Start of thread
    //Object based placeholder for the beginning of the thread (used when loopAll is unchecked)
    SOT = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    SOT.media.src = ""; //https://dummyimage.com/1920x1080/000000/ffffff.png&text=Start+of+thread"; 
    SOT.thumb.src = ""; //https://dummyimage.com/480x270/000000/ffffff.png&text=Start+of+thread";
    SOT.type = "SOT";

    //End of thread
    //Object based placeholder for the end of the thread (used when loopAll is unchecked)
    EOT = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    EOT.media.src = ""; //https://dummyimage.com/1920x1080/000000/ffffff.png&text=End+of+thread
    EOT.thumb.src = ""; //https://dummyimage.com/480x270/000000/ffffff.png&text=End+of+thread
    EOT.type = "EOT";

    //Object based placeholder for when there is no applicable media found or nothing is selected
    noneSelected = new Media("https://dummyimage.com/1920x1080/000000/ffffff.png","https://dummyimage.com/1920x1080/000000/ffffff.png");
    noneSelected.media.src = "https://dummyimage.com/1920x1080/000000/ffffff.png&text=No+Media+Selected";
    noneSelected.thumb.src = "https://dummyimage.com/480x270/000000/ffffff.png&text=No+Media+Selected";

    allContent = getContent();
    usedContent = getUsedContent();
    currentContent = noneSelected;
}

//////////////////////////////////////////////
// # SFC Control  and Animation Functions # //
//////////////////////////////////////////////

//Links functions with page controllers
//eg: making gallery button show/hide gallery
function startInteractions(){

    //Apply functionality: click start to show modal and play first media item
    el_startBtn.onclick = function(){
        showSFC(true);
        if(op_auto.checked){
            usedContent[0].select();
        }
    };

    el_resumeBtn.onclick = function(){
        showSFC(true);
        currentContent.play();
        updateAutoplay();
    };

    //Apply functionality: click gallery button to show/hide gallery
    el_gallery.style.transform = "translateY(100%)";
    el_galleryBtn.onclick = showGallery;

    //Apply functionality: click settings button to show settings
        //Click exit button to exit settings
    el_settingsBtn.onclick = function(){ showSettings(true); };
    el_settingsExit.onclick = function(){ showSettings(false); };
}

//Applies default settings
//  • Default settings are on line 5
function applyDefaulSettings(){
    op_loopAll.checked = settingsArray[0];

    op_auto.checked = settingsArray[1];

    op_random.checked = settingsArray[2];

    op_webms.checked = settingsArray[3];

    op_controls.checked = settingsArray[4];

    op_playSound.checked = settingsArray[5];

    op_gifs.checked = settingsArray[6];

    op_gif_duration.value = settingsArray[7];

    op_imgs.checked = settingsArray[8];

    op_img_duration.value = settingsArray[9];
}

//Toggles showing the modal
function showSFC(bool){

    function show(){
        document.body.style.overflow = "hidden";
        el_sfc.style.display = "block";
        setTimeout(function(){
            el_sfc.style.opacity = 1;
        }, 40);
        return true;
    }

    function hide(){
        showGallery(false);
        showSettings(false);
        currentContent.pause();
        el_sfc.style.opacity = 0;
        el_sfc.addEventListener("transitionend", function() {
            if(el_sfc.style.opacity == 0){
                el_sfc.style.display = "none";
                el_sfc.removeEventListener("transitionend", function(){}, false);
                document.body.style.overflow = "scroll";
            }
        }, false);
        return true;
    }

    if(bool === true){
        show();
    }else if (bool === false){
        hide();
    }else if (isShown(el_sfc)){
        show();
    }else{
        hide();
    }

    return false;
}

//Toggles showing the gallery
function showGallery(bool){
    

    function show(){

        //Sets internal gallery slider to appropriate width
        //'if' statements causes this to only fire once
        if(el_internalSlider.style.width == ""){
            updateGallery();
        }

        el_gallery.style.transform = "translateY(0px)";
        el_util.style.transform = "translateY(-" + el_gallery.clientHeight + "px)";

        return true;
    }

    function hide(){
        el_gallery.style.transform = "translateY(100%)";
        el_util.style.transform = "translateY(0)";
        return true;
    }

    if(bool === true){
        show();
    }else if(bool === false){
        hide();
    }else if(el_gallery.style.transform == "translateY(100%)"){
        show();
    }else{
        hide();
    }

    return false;
}

//Toggles showing the settings
function showSettings(bool){

    function show(){
        el_settings.style.display = "flex";
        return true;
    }

    function hide(){
        el_settings.style.display = "none";
        return true;
    }

    if(bool === true){
        show();
    }else if(bool === false){
        hide();
    }else if(el_settings.style.display == "none" || el_settings.style.display === ""){
        show();
    }else{
        hide();
    }

    return false;
}

//Parse through el_sfc, el_settings or el_gallery
//Return boolean indicating it's state
function isShown(el){
    if(el === el_sfc){
        return !(el_sfc.style.display == "none");
    }

    if(el === el_settings){
        return !(el_settings.style.display == "none" || el_settings.style.display === "");
    }

    if(el === el_gallery){
        return !(el_gallery.style.transform == "translateY(100%)");
    }
}

/////////////////////////////////////////
// # Media and Media Array Functions # //
/////////////////////////////////////////

//Updates usedContent array, populates gallery and readjusts width
function updateGallery(){
    //Update contents of usedContent array
    usedContent = getUsedContent();

    //Change currentContent to closest valid content
    if(currentContent !== noneSelected && currentContent !== null){
        if(!canPlay(currentContent)){

            var newContent = null;

            //If usedContent actually has something in it
            if(usedContent.length > 0){
                var a = 0;
                var b = 0;

                //Find currentContent in allContent array
                if(currentContent !== noneSelected){
                    for(var i = 0; i < allContent.length; i++){
                        if(allContent[i] === currentContent){
                            a = i;
                            b = i;
                        }
                    }
                }
                

                //Begin searching in both directions for playable media
                //starting from currentContent
                do{
                    a++;
                    b--;

                    //If a is above range set to start
                    if(a >= allContent.length){
                        a = 0;
                    }

                    //If b is below range set to end
                    if(b < 0){
                        b = allContent.length - 1;
                    }

                    if(canPlay(allContent[a])){ //if can play a --> play a
                        newContent = allContent[a]; 
                    }else if(canPlay(allContent[b])){ // if can play b --> play b
                        newContent = allContent[b];
                    }else if(a == b){ // if circled around to beginning --> noneSelected (no content found)
                        newContent = noneSelected;
                    }
                }while(newContent === null);
                newContent = newContent;
            }else{
                newContent = noneSelected;
            }
            newContent.select();
        }
    }

    //Clear contents and width of internalSlider
    el_internalSlider.innerHTML = "";
    el_internalSlider.style.width = "-1px";

    //Add all thumbnails to internalSlider
    for(var i = 0; i < usedContent.length; i++){
        el_internalSlider.appendChild(usedContent[i].thumb);
        el_internalSlider.style.width = (el_internalSlider.offsetWidth + usedContent[i].thumb.offsetWidth) + "px";
    }

    //Trigger height calculations without changing gallery state
    showGallery(isShown(el_gallery));
    
}

//Play next valid media item
function next(){

    if(op_loopAll.checked){

        //If at last position play first item
        if(currentContent.position === usedContent.length-1){
            usedContent[0].select();
        }else{
        	if(usedContent[currentContent.position + 1] !== undefined){
        		usedContent[currentContent.position + 1].select();	
        	}
        }

    }else{

        //If its not the last item --> play next, else do nothing
        if(currentContent.position !== usedContent.length-1){
            usedContent[currentContent.position + 1].select();
        }
    }
}

//Play previous valid media item
function previous(){
    if(op_loopAll.checked){

        //If at first position play last item
        //else play previous
        if(currentContent.position === 0){
            usedContent[usedContent.length - 1].select();
        }else{
            if(usedContent[currentContent.position - 1] !== undefined){
        		usedContent[currentContent.position - 1].select();	
        	}
        }

    }else{

        //If its not the last item --> play next, else do nothing
        if(currentContent.position !== 0){
            usedContent[currentContent.position - 1].select();
        }
    }
}

//Returns media type when given source
function mediaType(input){
	if(input === undefined){
		console.log('Error: mediaType input argument was undefined');
	}else if(input === null){
		console.log('Error: mediaType input argument was null');
	}else{
		var temp = input.toString();

	    temp = temp.substr(temp.lastIndexOf('.') + 1);

	    if(temp == webm) return webm;
	    if(temp == gif)   return gif;
	    if(temp == png)  return png;
	    if(temp == jpg)  return jpg;
	}

	//Last Resort    
    return null;
}

//Returns if current user settings permits the playing of parsed object
function canPlay(mediaObj){
    var objType = mediaObj.type;
    return (objType == webm && op_webms.checked) || (objType == gif && op_gifs.checked) || ( (objType == png || objType == jpg) && op_imgs.checked ) || (objType == "SOT" && !op_loopAll.checked) || (objType == "EOT" && !op_loopAll.checked);
}

//Applies autoplay based on user settings
function updateAutoplay(){

    //Clear timeout to avoid timeout overlaps and
    //unwanted function calls
    clearTimeout(globalTimeout);


    if(currentContent.type == webm){

        //Loop media (incase auto is not turned on)
        currentContent.media.loop = true;

        //If it is turned on, set to false and await end of video
        if(op_auto.checked){
            currentContent.media.loop = false;
            currentContent.media.onended = next;
        }
    }else if(currentContent.type == gif){

        //If auto is checked apply according timeout
        if(op_auto.checked){
            globalTimeout = setTimeout(next, op_gif_duration.value*1000);
        }
    }else if(currentContent.type == png || currentContent.type == jpg){

        //If auto is checked apply according timeout
        if(op_auto.checked){
            globalTimeout = setTimeout(next, op_img_duration.value*1000);
        }
    }
}

//Returns ALL elemnts. Including SOT, EOT and noneSelected
function getContent(){

    var temp = [];

    var elements = document.getElementsByClassName('fileThumb');

    //Pushes 'start of thread' placeholder
    temp.push(SOT);

    //Loops over all media elements in thread
    //and pushes them to temp array
    for(var i = 0; i < elements.length; i++){

        var vidSrc = elements[i].href;
        var imgSrc = elements[i].getElementsByTagName('img')[0].src;
        var id = elements[i].parentNode.parentNode.id;

        var x = new Media(imgSrc, vidSrc, id);
        temp.push(x);
    }

    //Pushes 'end of thread' placeholder
    temp.push(EOT);

    return temp;
}

//Returns all media permitted to play by user settings
function getUsedContent(){
    var temp = [];
    var count = 0;

    for(var i = 0; i < allContent.length; i++){
        if(canPlay(allContent[i])){
            temp.push(allContent[i]);
            temp[count].position = count;
            count++;
        }
    }
    return temp;
}

///////////////////////
// # Miscellaneous # //
///////////////////////

function startEventListeners(){

    window.onresize = function(){
        updateGallery();
        currentContent.resize();
    }

    op_loopAll.onchange = updateGallery;
    
    op_controls.onchange = function(){
        if(currentContent.type == webm){
        	currentContent.media.controls = op_controls.checked;
        }
    };

    op_playSound.onchange = function(){
        if(currentContent.type == webm){
            currentContent.media.volume = op_playSound.checked ? 1 : 0;
        }
    };

    op_webms.onchange = updateGallery;
    op_gifs.onchange = updateGallery;
    op_imgs.onchange = updateGallery;
    op_auto.onchange = updateAutoplay;

    el_stagePrev.onclick = previous;
    el_stageNext.onclick = next;

    document.onkeydown = function(event){
        switch(event.keyCode){

            //Esc Key
            case 27:
                if(isShown(el_settings)){
                    showSettings(false);
                }else if(isShown(el_sfc)){
                    showSFC(false);
                }
                break;

            //Left arrow Key
            case 37:
                previous();
                break;

            //Right arrow Key
            case 39:
                next();
                break;

            //Up arrow Key
            case 38:
            	if(event.shiftKey){
            		op_img_duration.value++;
            	}else{
            		op_gif_duration.value++;
            	}
                break;

            //Down arrow Key
            case 40:
                if(event.shiftKey){
            		op_img_duration.value--;
            	}else{
            		op_gif_duration.value--;
            	}
                break;

            //L Key
            case 76:
                op_loopAll.checked = !op_loopAll.checked;
                op_loopAll.onchange();
                break;

             //A Key
            case 65:
                op_auto.checked = !op_auto.checked;
                op_auto.onchange();
                break;

            //R Key
            case 82:
                op_random.checked = !op_random.checked;
                op_random.onchange();
                break;

            //Q Key
            case 81:
                //op_shuffle.onclick();
                break;

            //S Key
            case 83:
                op_playSound.checked = !op_playSound.checked;
                op_playSound.onchange();
                break;

            //W Key
            case 87:
                op_webms.checked = !op_webms.checked;
                op_webms.onchange();
                break;

            //C Key
            case 67:
                op_controls.checked = !op_controls.checked;
                op_controls.onchange();
                break;

            //G Key
            case 71:
                op_gifs.checked = !op_gifs.checked;
                op_gifs.onchange();
                break;

            //I Key
            case 73:
                op_imgs.checked = !op_imgs.checked;
                op_imgs.onchange();
                break;

            //Print what was typed into console
            default:
            	var temp = "";
            	
            	if(event.shiftKey){
            		temp += "Shift + ";
            	}

            	if(event.altKey){
            		temp += "Alt + ";
            	}

            	if(event.ctrlKey){
            		temp += "Ctrl + ";
            	}

            	temp += event.keyCode;

                console.log(temp);
        }
    }
}

function getPageTopLeft(el) {
    var rect = el.getBoundingClientRect();
    var docEl = document.documentElement;
    return {
        left: rect.left + (window.pageXOffset || docEl.scrollLeft || 0),
        top: rect.top + (window.pageYOffset || docEl.scrollTop || 0)
    };
}