NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Youtube floating player // @description Pins the video player in its original position while you scroll the page. // @version 3.2 // @author REVerdi // @namespace https://openuserjs.org/users/REVerdi // @copyright 2014+, REVerdi (https://openuserjs.org/users/REVerdi) // @license (CC) Attribution Non-Commercial Share Alike; http://creativecommons.org/licenses/by-nc-sa/3.0/ // Por causa do SPF (Structured Page Fragments), não posso usar // @include http*://www.youtube.com/watch?* // porque se o 1° link no YouTube não for do tipo acima, esse script nunca será executado. // @include http*://www.youtube.com/* // @downloadURL https://openuserjs.org/install/REVerdi/Youtube_floating_player.user.js // @grant none // ==/UserScript== /* TESTADO APENAS NO FIREFOX ONLY TESTED ON FIREFOX */ /* O YouTube "quase" exatamente como eu queria! Eu não sou programador, então não joguem tomates podres em mim :) YouTube "almost" exactly as I wanted! I'm not a programmer, so don't throw rotten tomatoes at me :) */ // Based on the ideia of drhouse (http://userscripts.org/scripts/show/186872) // and contains source code written by tforbus: // http://www.tristinforbus.com/ // https://github.com/tforbus/youtube-fixed-video-bookmarklet // http://www.whattheforbus.com/youtube-bookmarklet [removed] // https://chrome.google.com/webstore/detail/video-pinner/egfhbaheiflmihggjcfmnmchkijkcdpl [removed] (function(){ "use strict"; var _window; if (typeof unsafeWindow !== undefined){ _window = unsafeWindow; } else { _window = window; } /* * constants */ const BODY_ID = 'body'; const PLAYER_ID = 'player'; //why not 'movie_player'? const THEATER_ID = 'theater-background'; const PLAYLIST_ID = 'watch-appbar-playlist'; const CONTENT_ID = 'watch7-content'; const SIDEBAR_ID = 'watch7-sidebar'; const PLACEHOLDER_ID = 'placeholder-player'; //to detect if the user is or is not on a video page const BUTTON_CLASS = 'ytp-size-button ytp-button'; //player view toggle button class /* * flow control variables */ var eventListenersAdded = 0; var bodyMutationObserverAdded = 0; /* * user is playing a... */ const SINGLE_VIDEO = 1; const PLAYLIST = 2; /* * player view mode */ var playerViewMode; const NOT_DETECTED = 0; const DEFAULT_VIEW = 1; const THEATER_MODE = 2; var playerViewToggleButton; //tem que ser pública para que se possa rodar o removeEventListener //http://www.w3schools.com/colors/colors_names.asp //if (document.getElementById( PLAYER_ID)) document.getElementById( PLAYER_ID).style.border = "thick solid cyan" ; //if (document.getElementById( THEATER_ID)) document.getElementById( THEATER_ID).style.border = "thick solid red" ; //if (document.getElementById( PLAYLIST_ID)) document.getElementById( PLAYLIST_ID).style.border = "thick solid pink" ; //if (document.getElementById( SIDEBAR_ID)) document.getElementById( SIDEBAR_ID).style.border = "thick solid yellow" ; //if (document.getElementById( PLACEHOLDER_ID)) document.getElementById( PLACEHOLDER_ID).style.border = "thick solid green" ; //if (document.getElementById( 'movie_player')) document.getElementById( 'movie_player').style.border = "thick solid blue" ; //if (document.getElementById('player-playlist')) document.getElementById('player-playlist').style.border = "thick solid fuchsia"; function userIsOnAVideoPage() { //user is where? var playerPlaceHolder = document.getElementById(PLACEHOLDER_ID); if( playerPlaceHolder ) return 1; //user IS on a video page else return 0; //user is NOT on a video page } function userIsPlayingA() { if( /list/.test(document.location) === false ) return SINGLE_VIDEO; else return PLAYLIST; } function getPlayerViewToggleButton() { var player = document.getElementById(PLAYER_ID); var buttons = player.getElementsByTagName('BUTTON'); for( var b = 0; b < buttons.length; b++ ) { if( buttons[b].className == BUTTON_CLASS) { var buttonTitle = buttons[b].getAttribute('title'); if( buttonTitle != 'null' ) return buttons[b]; } } } function resizePlayer() { var playerRect; var theaterRect; var sidebarRect; var playlist; var player = document.getElementById( PLAYER_ID); var theater = document.getElementById(THEATER_ID); var sidebar = document.getElementById(SIDEBAR_ID); var content = document.getElementById(CONTENT_ID); var contentRect = content.getBoundingClientRect(); var playerPlaceHolder = document.getElementById(PLACEHOLDER_ID); playerPlaceHolder.firstElementChild.style.backgroundColor = 'transparent'; player.style.top = '60px'; //determinado por tentativa e erro :S player.style.position = 'fixed'; theater.style.position = 'fixed'; sidebar.style.position = 'inherit'; //static|absolute|fixed|relative|initial|inherit switch( playerViewMode ) { case DEFAULT_VIEW: // var content = document.getElementById(CONTENT_ID); // var contentRect = content.getBoundingClientRect(); //bottom, height, left, right, top, width, x, y player.style.left = contentRect.left + 'px'; switch( userIsPlayingA() ) { case SINGLE_VIDEO: player.style.zIndex = 998; sidebar.style.zIndex = 999; break; case PLAYLIST: player.style.zIndex = 999; sidebar.style.zIndex = 998; playlist = document.getElementById(PLAYLIST_ID); //para desfazer o que foi feito para playlist em modo teatro playlist.style.top = ''; playlist.style.position = ''; playlist.style.width = ''; playlist.style.left = ''; playerRect = player.getBoundingClientRect(); //to limit the sidebarRect = sidebar.getBoundingClientRect(); //width of player.style.width = sidebarRect.right - playerRect.left + 'px'; //the playlist break; } break; case THEATER_MODE: player.style.zIndex = 999; sidebar.style.zIndex = 998; playerRect = player.getBoundingClientRect(); theaterRect = theater.getBoundingClientRect(); player.style.left = (theaterRect.width / 2) - (playerRect.width / 2) + 'px'; switch( userIsPlayingA() ) { case SINGLE_VIDEO: //nothing to do break; case PLAYLIST: sidebarRect = sidebar.getBoundingClientRect(); playlist = document.getElementById(PLAYLIST_ID); playlist.style.top = '170px'; //determinado por tentativa e erro :S playlist.style.position = 'fixed'; playlist.style.width = sidebarRect.right - contentRect.right + 'px'; playlist.style.left = contentRect.right + 'px'; //or //playlist.style.width = sidebarRect.width + 'px'; //playlist.style.left = sidebarRect.left + 'px'; break; } break; } } function pageResize() { resizePlayer(); } function playerViewToggleButtonClick() { switch( playerViewMode ) { case DEFAULT_VIEW: playerViewMode = THEATER_MODE; break; case THEATER_MODE: playerViewMode = DEFAULT_VIEW; break; } resizePlayer(); } function getPlayerViewMode() { var playerViewToggleButtonTitle = playerViewToggleButton.getAttribute('title'); if( playerViewToggleButtonTitle != 'null' ) { playerViewToggleButtonTitle = playerViewToggleButtonTitle.toLowerCase(); switch( playerViewToggleButtonTitle ) { //detecta o modo de visualização pelo título do botão (eu sei, depende do idioma :S) case 'theater mode': //'Theater mode' case 'modo teatro': //'Modo Teatro' playerViewMode = DEFAULT_VIEW; break; case 'default view': //'Default view' case 'visualização padrão': //'Visualização padrão' playerViewMode = THEATER_MODE; break; } } //else playerViewMode = NOT_DETECTED; //isso ocorre, mas daí é mantido o último valor válido detectado } /* function initElements() { //merged into resizePlayer() var player = document.getElementById( PLAYER_ID); var theater = document.getElementById(THEATER_ID); var sidebar = document.getElementById(SIDEBAR_ID); var playerPlaceHolder = document.getElementById(PLACEHOLDER_ID); playerPlaceHolder.firstElementChild.style.backgroundColor = 'transparent'; player.style.top = '60px'; //determinado por tentativa e erro :S player.style.position = 'fixed'; theater.style.position = 'fixed'; sidebar.style.position = 'inherit'; //static|absolute|fixed|relative|initial|inherit } */ //https://developer.mozilla.org/pt-BR/docs/Web/API/MutationObserver //http://www.w3schools.com/jsref/met_element_addeventlistener.asp var bodyMutationObserver = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { if( userIsOnAVideoPage() ) { if( eventListenersAdded === 0 ) { //só adiciona uma vez playerViewToggleButton = getPlayerViewToggleButton(); playerViewToggleButton.addEventListener('click', playerViewToggleButtonClick, false); _window.addEventListener('resize', pageResize, false); eventListenersAdded = 1; getPlayerViewMode(); //initElements(); //resizePlayer(); //aqui não funciona 100%, portanto... } resizePlayer(); //...tem que ficar aqui e ser chamada várias vezes :S } else { //user is NOT on a video page if( eventListenersAdded ) { //só remove uma vez var player = document.getElementById(PLAYER_ID); player.style.top = ''; player.style.position = ''; player.style.zIndex = ''; player.style.left = ''; player.style.width = ''; playerViewToggleButton.removeEventListener('click', playerViewToggleButtonClick, false); _window.removeEventListener('resize', pageResize, false); eventListenersAdded = 0; } } }); }); /* function remBodyMutationObserver(); if( bodyMutationObserverAdded == 1 ) { //( bodyMutationObserverAdded == 1 ) ou apenas ( bodyMutationObserverAdded ) bodyMutationObserver.disconnect(); bodyMutationObserverAdded = 0; } } */ function addBodyMutationObserver() { if( bodyMutationObserverAdded === 0 ) { //( bodyMutationObserverAdded === 0 ) ou apenas ( !bodyMutationObserverAdded ) var config = { attributes: true, characterData: true, childList: true }; var target = document.getElementById(BODY_ID); //tem que ser 'body', porque 'page' só funciona quando a 1ª página NÃO for uma de vídeo if( target !== null ) { //( target !== null ) ou apenas ( target ) bodyMutationObserver.observe(target, config); bodyMutationObserverAdded = 1; } } } addBodyMutationObserver(); //initScript == entryPoint })();