您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Uses FireBase Helper Function to Call Youtube Data API 3 to get Comments with TimeStamps
// ==UserScript== // @name Youtube Timestamp Buttons from Comments // @namespace http://greasyforks.org // @version 0.6 // @description Uses FireBase Helper Function to Call Youtube Data API 3 to get Comments with TimeStamps // @author 636597 // @include *://*youtube.com/* // @run-at document-start // @grant none // ==/UserScript== var button_menu_element = false; var load_button_element = false; var next_button_element = false; var previous_button_element = false; var time_stamp_data_paragraph_parent_element = false; var time_stamp_data_paragraph_element = false; var time_stamp_button_elements = []; var current_video_id = false; var current_video_duration = false; var current_playlist_circular_array = false; var x1_player = undefined; var comment_map = {}; // https://stackoverflow.com/a/18359711 function add_custom_css() { var custom_css = ` .tooltip-container:hover .tooltip { display: inline; } .tooltip { display: none; /* NEW */ background: #C8C8C8; margin-left: 28px; padding: 10px; position: absolute; z-index: 1000; width:200px; height:100px; } .tooltip-container { display: inline; } `; var styleSheet = document.createElement("style") styleSheet.type = "text/css" styleSheet.innerText = custom_css; document.head.appendChild(styleSheet) } var window_history_oberver = false; function load_window_history_observer() { CustomLog( "Initializing Window History Poller" ); window_history_oberver = setInterval( function() { if ( !current_video_id ) { return; } var url_string = null; var now_playing_id = null; try { url_string = x1_player.getVideoUrl(); now_playing_id = url_string.split( "v=" )[ 1 ].split( "&" )[ 0 ]; } catch( error ) { return; } if ( now_playing_id !== current_video_id ) { CustomLog( "Detected New Video ID" ); CustomLog( "Resetting Time Stamps" ); current_video_id = now_playing_id; setTimeout( function() { load_comments_from_firebase_helper( { skip: "yes" , override_id: now_playing_id } ); } , 3000 ); } } , 1000 ); } function CustomLog( message ) { console.log( "YoutubeTimestampButtons.js === " + message ); } function CircularArrayIterator( list , starting_index ) { if ( !list ) { return false; } if ( list.length < 1 ) { return false; } const llen = list.length; return { current_index: starting_index || 0 , list: list , list_length: llen , push: function( item , index ) { if ( !item ) { return; } if ( index ) { this.list.splice( index , 0 , item ); } else { this.list.push( item ); } this.list_length += 1; } , pop: function( index ) { if ( index ) { this.list.splice( index , 1 ); } else { this.list.pop(); } this.list_length -= 1; } , current: function() { return this.list[ this.current_index ]; } , next: function() { CustomLog( "next" ); this.current_index += 1; if ( this.current_index > ( this.list_length - 1 ) ) { this.current_index = 0; } return this.list[ this.current_index ]; } , next_index: function() { CustomLog( "next index" ); this.current_index += 1; if ( this.current_index > ( this.list_length - 1 ) ) { this.current_index = 0; } return this.current_index; } , previous: function() { CustomLog( "previous" ); this.current_index -= 1; if ( this.current_index < 0 ) { this.current_index = ( this.list_length - 1 ); } return this.list[ this.current_index ]; } , previous_index: function() { CustomLog( "previous index" ); this.current_index -= 1; if ( this.current_index < 0 ) { this.current_index = ( this.list_length - 1 ); } return this.current_index; } }; } function removeDuplicates(originalArray, prop) { var newArray = []; var lookupObject = {}; for( var i in originalArray ) { lookupObject[originalArray[i][prop]] = originalArray[i]; } for(i in lookupObject) { newArray.push(lookupObject[i]); } return newArray; } // function playlist_next() { // CustomLog( "NEXT()" ); // if ( !x1_player ) { return; } // var current_time = x1_player.getCurrentTime(); // if ( !current_time ) { return; } // current_time = parseInt( current_time ); // CustomLog( "CURRENT TIME === " + current_time.toString() ); // CustomLog( "CURRENT === [ " + ( current_playlist_circular_array.current_index + 1 ).toString() + " ] of " + current_playlist_circular_array.list_length.toString() + " === " + current_playlist_circular_array.list[ current_playlist_circular_array.current_index ].url_seconds.toString() ); // console.log( current_playlist_circular_array.list[ current_playlist_circular_array.current_index ] ); // var current_url_seconds = current_playlist_circular_array.list[ current_playlist_circular_array.current_index ].url_seconds; // var current_item = current_playlist_circular_array.list[ current_playlist_circular_array.current_index ]; // while ( current_url_seconds <= current_time ) { // CustomLog( "current_url_seconds <= current_time" ); // CustomLog( current_url_seconds.toString() + " <= " + current_time.toString() ); // CustomLog( "current_index === " + current_playlist_circular_array.current_index.toString() ); // CustomLog( "Current Item === " ); // console.log( current_item ); // CustomLog( "NEXT()" ); // current_playlist_circular_array.next_index(); // current_item = current_playlist_circular_array.list[ current_playlist_circular_array.current_index ]; // current_url_seconds = current_item.url_seconds; // CustomLog( current_url_seconds.toString() + " <= " + current_time.toString() ); // CustomLog( "current_index === " + current_playlist_circular_array.current_index.toString() ); // CustomLog( "Current Item === " ); // console.log( current_item ); // if ( current_playlist_circular_array.current_index === 0 ) { break; } // } // //next = current_playlist_circular_array.next(); // CustomLog( "NEXT()-FINAL === [ " + ( current_playlist_circular_array.current_index + 1 ).toString() + " ] of " + current_playlist_circular_array.list_length.toString() ); // console.log( current_item ); // x1_player.loadVideoById( current_video_id , current_item.url_seconds ); // } // function playlist_previous() { // CustomLog( "PREVIOUS()" ); // if ( !x1_player ) { return; } // var current_time = x1_player.getCurrentTime(); // if ( !current_time ) { return; } // current_time = parseInt( current_time ); // CustomLog( "CURRENT TIME === " + current_time.toString() ); // CustomLog( "CURRENT === [ " + ( current_playlist_circular_array.current_index + 1 ).toString() + " ] of " + current_playlist_circular_array.list_length.toString() ); // while ( current_time > current_playlist_circular_array.list[ current_playlist_circular_array.current_index ].url_seconds ) { // CustomLog( "current_time > current_index" ); // current_playlist_circular_array.previous_index(); // CustomLog( "CURRENT === [ " + ( current_playlist_circular_array.current_index + 1 ).toString() + " ] of " + current_playlist_circular_array.list_length.toString() ); // if ( current_playlist_circular_array.current_index === current_playlist_circular_array.list_length ) { break; } // } // //next = current_playlist_circular_array.next(); // CustomLog( "CURRENT === [ " + ( current_playlist_circular_array.current_index + 1 ).toString() + " ] of " + current_playlist_circular_array.list_length.toString() ); // x1_player.loadVideoById( current_video_id , current_playlist_circular_array.list[ current_playlist_circular_array.current_index ].url_seconds ); // } function playlist_seek( seconds ) { CustomLog( "SEEKING TO === " + seconds.toString() ); x1_player.loadVideoById( current_video_id , seconds ); } function add_paragraph_with_time_stamp_data() { time_stamp_data_paragraph_parent_element = document.querySelector( "ytd-comments#comments" ); if ( time_stamp_data_paragraph_parent_element ) { time_stamp_data_paragraph_parent_element = time_stamp_data_paragraph_parent_element.parentElement; var reversed = current_playlist_circular_array.list; reversed.reverse(); for ( var i = 0; i < reversed.length; ++i ) { var id = "x1_p_ts_entry_" + i.toString(); var p_string =`<div class="tooltip-container"><button id="${ id }">${ reversed[ i ].time_string }</button><span class="tooltip">${ comment_map[ reversed[ i ].url_seconds.toString() ] }</span></div>`; //CustomLog( p_string ); var template = document.createElement( 'template' ); template.innerHTML = p_string; var fragment = template.content //time_stamp_data_paragraph_parent_element.appendChild( fragment ); time_stamp_data_paragraph_parent_element.insertBefore( fragment , time_stamp_data_paragraph_parent_element.childNodes[ 3 ] ); var b_elem = document.body.querySelector( "#" + id ); b_elem.setAttribute( "url_seconds" , current_playlist_circular_array.list[ i ].url_seconds ); //b_elem.setAttribute( "playlist_index" , reversed[ i ].index ); b_elem.addEventListener( "click" , function( event ) { //current_playlist_circular_array.current_index = parseInt( this.getAttribute( "playlist_index" ) ); playlist_seek( parseInt( this.getAttribute( "url_seconds" ) ) ); }); time_stamp_button_elements.push( b_elem ); } } load_button_element.style.visibility = "visible"; if ( !window_history_oberver ) { load_window_history_observer(); } } function add_previous_next_buttons() { if ( button_menu_element ) { button_menu_element.insertAdjacentHTML( 'beforeend' , '<button id="x1_playlist_previous">Previous</button>' ); previous_button_element = document.body.querySelector( "#x1_playlist_previous" ); previous_button_element.addEventListener( "click" , playlist_previous ); button_menu_element.insertAdjacentHTML( 'beforeend' , '<button id="x1_playlist_next">Next</button>' ); next_button_element = document.body.querySelector( "#x1_playlist_next" ); next_button_element.addEventListener( "click" , playlist_next ); } } function load_keyboard_watchers() { add_previous_next_buttons(); add_paragraph_with_time_stamp_data(); // TODO: Need To figure out Javscript Circular List, COGGERS FailFish /* document.body.addEventListener( "keydown" , function( event ) { if ( event.key === "n" ) { playlist_next(); } else if ( event.key === "b" ) { playlist_previous(); } }); */ } function get_video_stats() { var url_string = x1_player.getVideoUrl(); current_video_id = url_string.split( "v=" )[ 1 ].split( "&" )[ 0 ]; current_video_duration = x1_player.getDuration(); /* current_playlist_id = url_string.split( "list=" ); if ( current_playlist_id ) { if ( current_playlist_id.length > 1 ) { current_playlist_id = current_playlist_id[ 1 ].split( "&" )[ 0 ]; current_playlist_index = x1_player.getPlaylistIndex(); CustomLog( current_playlist_id ); CustomLog( current_playlist_index ); } } */ CustomLog( current_video_id ); } function parse_firebase_helper( comments ) { CustomLog( "Parsing Recieved Comment Data" ); var final = []; for ( var i = 0; i < comments.length; ++i ) { if ( comments[ i ].time_stamp_parts ) { if ( comments[ i ].time_stamp_parts.length > 0 ) { var text = comments[ i ].text; for ( var j = 0; j < comments[ i ].time_stamp_parts.length; ++j ) { if ( comments[ i ].time_stamp_parts[ j ].url_seconds ) { var url_seconds_string = comments[ i ].time_stamp_parts[ j ].url_seconds.toString(); if ( !comment_map[ url_seconds_string ] ) { comment_map[ url_seconds_string ] = text; } } } final.push( ...comments[ i ].time_stamp_parts ); } } } console.log( comment_map ); var uniqueArray = removeDuplicates( final , "url_seconds" ); uniqueArray = uniqueArray.sort( ( a , b ) => { b.url_seconds - a.url_seconds }); uniqueArray = uniqueArray.filter( x => x.url_seconds !== null ); uniqueArray = uniqueArray.filter( x => x.url_seconds !== "null" ); uniqueArray = uniqueArray.filter( x => x.url_seconds < current_video_duration ); current_playlist_circular_array = false; current_playlist_circular_array = CircularArrayIterator( uniqueArray ); add_custom_css(); add_paragraph_with_time_stamp_data(); console.log( uniqueArray ); } var comment_count = "50"; var fburlb = atob( 'aHR0cHM6Ly91cy1jZW50cmFsMS1oZWxwZXItZTNkODYuY2xvdWRmdW5jdGlvbnMubmV0L3RpbWVzdGFtcHM/aWQ9' ); function load_comments_from_firebase_helper( options ) { reset_simple(); var rebuild = true; if ( options ) { if ( options.skip ) { if ( options.skip === "yes" ) { current_video_id = options.override_id; } } } x1_player = document.getElementById( "movie_player" ); if ( !x1_player ) { return; } get_video_stats(); if ( !current_video_id ) { return; } load_button_element.style.visibility = "hidden"; CustomLog( "Fetching Comments from FireBase Helper" ); // fetch( 'https://us-central1-helper-e3d86.cloudfunctions.net/timestamps?id=' + current_video_id , { // headers: new Headers({ // 'Access-Control-Allow-Origin': '*' , // 'Access-Control-Allow-Headers':'application/json', // 'Access-Control-Allow-Headers': 'Content-Type, Authorization' // }) // }) fetch( fburlb + current_video_id + "&count=" + comment_count ) .then( response => response.json() ) .then( data => { console.log( data ); parse_firebase_helper( data.top_time_stamp_comments ); }) .catch(error => console.error(error)) } function add_load_button() { button_menu_element = document.body.querySelector( "ytd-menu-renderer" ); if ( button_menu_element ) { button_menu_element.insertAdjacentHTML( 'beforeend' , '<button id="x1_load_ts">Load Timestamps</button>' ); load_button_element = document.body.querySelector( "#x1_load_ts" ); load_button_element.addEventListener( "click" , load_comments_from_firebase_helper ); } } function reset_simple() { try { next_button_element.parentNode.removeChild( next_button_element ); } catch( e ){} next_button_element = false; try { previous_button_element.parentNode.removeChild( previous_button_element ); } catch( e ){} previous_button_element = false; for ( var i = 0; i < time_stamp_button_elements.length; ++i ) { try { time_stamp_button_elements[ i ].parentNode.removeChild( time_stamp_button_elements[ i ] ); } catch( e ){} } //time_stamp_data_paragraph_parent_element = false; //time_stamp_data_paragraph_element = false; time_stamp_button_elements = []; current_video_id = false; current_video_duration = false; // current_playlist_id = false; // current_playlist_index = 0; // current_index = 0; // current_playlist = []; current_playlist_circular_array = undefined; x1_player = undefined; comment_map = false; comment_map = {}; } function reset_all() { button_menu_element = false; try { load_button_element.parentNode.removeChild( load_button_element ); } catch( e ){} load_button_element = false; try { next_button_element.parentNode.removeChild( next_button_element ); } catch( e ){} next_button_element = false; try { previous_button_element.parentNode.removeChild( previous_button_element ); } catch( e ){} previous_button_element = false; try { time_stamp_data_paragraph_parent_element.parentNode.removeChild( time_stamp_data_paragraph_parent_element ); } catch( e ){} time_stamp_data_paragraph_parent_element = false; time_stamp_data_paragraph_element = false; time_stamp_button_elements = []; current_video_id = false; current_video_duration = false; //current_playlist_id = false; //current_playlist_index = 0; //current_index = 0; //current_playlist = []; current_playlist_circular_array = undefined; x1_player = undefined; comment_map = false; comment_map = {}; } function init() { reset_all(); CustomLog( "LOADING" ); setTimeout(function(){ add_load_button(); //CustomLog( "LOADED" ); } , 3000 ); } (function() { window.addEventListener ( "load", init ); })();