NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Loop YouTube Video // @description Adds a Loop button to YouTube that lets you auto-repeat videos. // @namespace youtube-loop-video-c // @match *://*.youtube.com/watch?v=* // @version 2.1 // ==/UserScript== // Make sure we're actually on a video page! if (!document.getElementById('watch8-secondary-actions')) return; // Add the button to toggle whether we're looping. var button = document.createElement('span'); button.innerHTML = '<button \ id="watch-loop" \ class="yt-uix-button yt-uix-button-text yt-uix-tooltip" \ type="button" \ title="Loop this video" \ data-orientation="vertical" \ data-position="bottomright" \ data-button-toggle="true" \ data-tooltip-text="Loop this video" \ role="button"> \ <span class="yt-uix-button-content">Loop </span> \ </button>'; document.getElementById('watch8-secondary-actions').appendChild(button); // Styles for the button. Most of it is taken from YouTube's style for // .yt-uix-button-panel:hover #watch-like-dislike-buttons .yt-uix-button-text.yt-uix-button-toggled GM_addStyle('\ .yt-uix-button-toggled#watch-loop { \ color: #932720; \ } \ .yt-uix-button-panel:hover .yt-uix-button-toggled#watch-loop { \ border-color: #c6c6c6; \ background-color: #e9e9e9; \ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .20); \ -ms-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .20); \ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .20); \ box-shadow: inset 0 1px 1px rgba(0, 0, 0, .20); \ filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#fff8f8f8, EndColorStr=#ffeeeeee); \ background-image: -moz-linear-gradient(top, #f8f8f8 0, #eee 100%); \ background-image: -ms-linear-gradient(top, #f8f8f8 0, #eee 100%); \ background-image: -o-linear-gradient(top, #f8f8f8 0, #eee 100%); \ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #f8f8f8), color-stop(100%, #eee)); \ background-image: -webkit-linear-gradient(top, #f8f8f8 0, #eee 100%); \ background-image: linear-gradient(to bottom, #f8f8f8 0, #eee 100%); \ }'); // Injects code into the global scope. function inject(fn) { var script = document.createElement('script'); script.innerHTML = '(' + fn.toString() + ')();'; document.body.appendChild(script); } // This function listens for the video ending and restarts it if we're looping. Inject // it into the page. Note that we can't access any variables outside the function here. inject(function () { // Controls whether we're looping. var looping = false; // Listen for the button click. document.getElementById('watch-loop').onclick = function () { looping = !looping; this.setAttribute('data-tooltip-text', looping ? 'Turn off looping' : 'Loop this video'); return false; }; // Returns the player API interface or false if it's not ready. function getPlayer() { return window.yt.player && window.yt.player.getPlayerByElement && window.yt.player.getPlayerByElement(document.getElementById('player-api')); } // Listen for the end of the video. function attach() { var player = getPlayer(); player.addEventListener('onStateChange', function (state) { if (state == '0' && looping) player.playVideo(); }); } // Wait until the YouTube API's ready. function wait() { setTimeout(getPlayer() ? attach : wait, 100); } wait(); });