Greasy Fork

stream4chan

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

目前为 2017-03-29 提交的版本。查看 最新版本

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