@ -1,5 +1,6 @@
var player _data = JSON . parse ( document . getElementById ( 'player_data' ) . innerHTML ) ;
'use strict' ;
var video _data = JSON . parse ( document . getElementById ( 'video_data' ) . innerHTML ) ;
var player _data = JSON . parse ( document . getElementById ( 'player_data' ) . textContent ) ;
var video _data = JSON . parse ( document . getElementById ( 'video_data' ) . textContent ) ;
var options = {
var options = {
preload : 'auto' ,
preload : 'auto' ,
@ -27,7 +28,7 @@ var options = {
overrideNative : true
overrideNative : true
}
}
}
}
}
} ;
if ( player _data . aspect _ratio ) {
if ( player _data . aspect _ratio ) {
options . aspectRatio = player _data . aspect _ratio ;
options . aspectRatio = player _data . aspect _ratio ;
@ -38,7 +39,7 @@ embed_url.searchParams.delete('v');
var short _url = location . origin + '/' + video _data . id + embed _url . search ;
var short _url = location . origin + '/' + video _data . id + embed _url . search ;
embed _url = location . origin + '/embed/' + video _data . id + embed _url . search ;
embed _url = location . origin + '/embed/' + video _data . id + embed _url . search ;
var save _player _pos _key = "save_player_pos" ;
var save _player _pos _key = 'save_player_pos' ;
videojs . Vhs . xhr . beforeRequest = function ( options ) {
videojs . Vhs . xhr . beforeRequest = function ( options ) {
if ( options . uri . indexOf ( 'videoplayback' ) === - 1 && options . uri . indexOf ( 'local=true' ) === - 1 ) {
if ( options . uri . indexOf ( 'videoplayback' ) === - 1 && options . uri . indexOf ( 'local=true' ) === - 1 ) {
@ -111,12 +112,12 @@ var shareOptions = {
description : player _data . description ,
description : player _data . description ,
image : player _data . thumbnail ,
image : player _data . thumbnail ,
get embedCode ( ) {
get embedCode ( ) {
return "<iframe id='ivplayer' width='640' height='360' src='" +
return '<iframe id="ivplayer" width="640" height="360" src="' +
addCurrentTimeToURL ( embed _url ) + "' style='border:none;'></iframe>" ;
addCurrentTimeToURL ( embed _url ) + '" style="border:none;"></iframe>' ;
}
}
} ;
} ;
const storage = ( ( ) => {
const storage = ( function ( ) {
try { if ( localStorage . length !== - 1 ) return localStorage ; }
try { if ( localStorage . length !== - 1 ) return localStorage ; }
catch ( e ) { console . info ( 'No storage available: ' + e ) ; }
catch ( e ) { console . info ( 'No storage available: ' + e ) ; }
@ -137,57 +138,57 @@ if (location.pathname.startsWith('/embed/')) {
// Detection code taken from https://stackoverflow.com/a/20293441
// Detection code taken from https://stackoverflow.com/a/20293441
function isMobile ( ) {
function isMobile ( ) {
try { document . createEvent ( "TouchEvent" ) ; return true ; }
try { document . createEvent ( 'TouchEvent' ) ; return true ; }
catch ( e ) { return false ; }
catch ( e ) { return false ; }
}
}
if ( isMobile ( ) ) {
if ( isMobile ( ) ) {
player . mobileUi ( ) ;
player . mobileUi ( ) ;
buttons = [ "playToggle" , "volumePanel" , "captionsButton" ] ;
var buttons = [ 'playToggle' , 'volumePanel' , 'captionsButton' ] ;
if ( video _data . params . quality !== 'dash' ) buttons . push ( "qualitySelector" )
if ( video _data . params . quality !== 'dash' ) buttons . push ( 'qualitySelector' ) ;
// Create new control bar object for operation buttons
// Create new control bar object for operation buttons
const ControlBar = videojs . getComponent ( "controlBar" ) ;
const ControlBar = videojs . getComponent ( 'controlBar' ) ;
let operations _bar = new ControlBar ( player , {
let operations _bar = new ControlBar ( player , {
children : [ ] ,
children : [ ] ,
playbackRates : [ 0.25 , 0.5 , 0.75 , 1.0 , 1.25 , 1.5 , 1.75 , 2.0 ]
playbackRates : [ 0.25 , 0.5 , 0.75 , 1.0 , 1.25 , 1.5 , 1.75 , 2.0 ]
} ) ;
} ) ;
buttons . slice ( 1 ) . forEach ( child => operations _bar . addChild ( child ) )
buttons . slice ( 1 ) . forEach ( function ( child ) { operations _bar . addChild ( child ) ;} );
// Remove operation buttons from primary control bar
// Remove operation buttons from primary control bar
primary _control _bar = player . getChild ( "controlBar" ) ;
var primary _control _bar = player . getChild ( 'controlBar' ) ;
buttons . forEach ( child => primary _control _bar . removeChild ( child ) ) ;
buttons . forEach ( function ( child ) { primary _control _bar . removeChild ( child ) ; } ) ;
operations _bar _element = operations _bar . el ( ) ;
var operations _bar _element = operations _bar . el ( ) ;
operations _bar _element . className += " mobile-operations-bar"
operations _bar _element . className += ' mobile-operations-bar' ;
player . addChild ( operations _bar )
player . addChild ( operations _bar ) ;
// Playback menu doesn't work when it's initialized outside of the primary control bar
// Playback menu doesn't work when it's initialized outside of the primary control bar
playback _element = document . getElementsByClassName ( "vjs-playback-rate" ) [ 0 ]
var playback _element = document . getElementsByClassName ( 'vjs-playback-rate' ) [ 0 ] ;
operations _bar _element . append ( playback _element )
operations _bar _element . append ( playback _element ) ;
// The share and http source selector element can't be fetched till the players ready.
// The share and http source selector element can't be fetched till the players ready.
player . one ( "playing" , ( ) => {
player . one ( 'playing' , function ( ) {
share _element = document . getElementsByClassName ( "vjs-share-control" ) [ 0 ]
var share _element = document . getElementsByClassName ( 'vjs-share-control' ) [ 0 ] ;
operations _bar _element . append ( share _element )
operations _bar _element . append ( share _element ) ;
if ( video _data . params . quality === 'dash' ) {
if ( video _data . params . quality === 'dash' ) {
http _source _selector = document . getElementsByClassName ( "vjs-http-source-selector vjs-menu-button" ) [ 0 ]
var http _source _selector = document . getElementsByClassName ( 'vjs-http-source-selector vjs-menu-button' ) [ 0 ] ;
operations _bar _element . append ( http _source _selector )
operations _bar _element . append ( http _source _selector ) ;
}
}
} )
} ) ;
}
}
// Enable VR video support
// Enable VR video support
if ( ! video _data . params . listen && video _data . vr && video _data . params . vr _mode ) {
if ( ! video _data . params . listen && video _data . vr && video _data . params . vr _mode ) {
player . crossOrigin ( "anonymous" )
player . crossOrigin ( 'anonymous' ) ;
switch ( video _data . projection _type ) {
switch ( video _data . projection _type ) {
case "EQUIRECTANGULAR" :
case 'EQUIRECTANGULAR' :
player . vr ( { projection : "equirectangular" } ) ;
player . vr ( { projection : 'equirectangular' } ) ;
default : // Should only be "MESH" but we'll use this as a fallback.
default : // Should only be 'MESH' but we'll use this as a fallback.
player . vr ( { projection : "EAC" } ) ;
player . vr ( { projection : 'EAC' } ) ;
}
}
}
}
@ -222,27 +223,27 @@ player.playbackRate(video_data.params.speed);
* @ returns cookieValue
* @ returns cookieValue
* /
* /
function getCookieValue ( name ) {
function getCookieValue ( name ) {
var value = document . cookie . split ( ";" ) . filter ( item => item . includes ( name + "=" ) ) ;
var value = document . cookie . split ( ';' ) . filter ( function ( item ) { return item . includes ( name + '=' ) ; } ) ;
return ( value != null && value . length >= 1 )
return ( value . length >= 1 )
? value [ 0 ] . substring ( ( name + "=" ) . length , value [ 0 ] . length )
? value [ 0 ] . substring ( ( name + '=' ) . length , value [ 0 ] . length )
: null ;
: null ;
}
}
/ * *
/ * *
* Method for updating the "PREFS" cookie ( or creating it if missing )
* Method for updating the 'PREFS' cookie ( or creating it if missing )
*
*
* @ param { number } newVolume New volume defined ( null if unchanged )
* @ param { number } newVolume New volume defined ( null if unchanged )
* @ param { number } newSpeed New speed defined ( null if unchanged )
* @ param { number } newSpeed New speed defined ( null if unchanged )
* /
* /
function updateCookie ( newVolume , newSpeed ) {
function updateCookie ( newVolume , newSpeed ) {
var volumeValue = newVolume != null ? newVolume : video _data . params . volume ;
var volumeValue = newVolume != = null ? newVolume : video _data . params . volume ;
var speedValue = newSpeed != null ? newSpeed : video _data . params . speed ;
var speedValue = newSpeed != = null ? newSpeed : video _data . params . speed ;
var cookieValue = getCookieValue ( 'PREFS' ) ;
var cookieValue = getCookieValue ( 'PREFS' ) ;
var cookieData ;
var cookieData ;
if ( cookieValue != null ) {
if ( cookieValue != = null ) {
var cookieJson = JSON . parse ( decodeURIComponent ( cookieValue ) ) ;
var cookieJson = JSON . parse ( decodeURIComponent ( cookieValue ) ) ;
cookieJson . volume = volumeValue ;
cookieJson . volume = volumeValue ;
cookieJson . speed = speedValue ;
cookieJson . speed = speedValue ;
@ -259,7 +260,7 @@ function updateCookie(newVolume, newSpeed) {
var domainUsed = window . location . hostname ;
var domainUsed = window . location . hostname ;
// Fix for a bug in FF where the leading dot in the FQDN is not ignored
// Fix for a bug in FF where the leading dot in the FQDN is not ignored
if ( domainUsed . charAt ( 0 ) != '.' && ! ipRegex . test ( domainUsed ) && domainUsed ! = 'localhost' )
if ( domainUsed . charAt ( 0 ) != = '.' && ! ipRegex . test ( domainUsed ) && domainUsed ! = = 'localhost' )
domainUsed = '.' + window . location . hostname ;
domainUsed = '.' + window . location . hostname ;
document . cookie = 'PREFS=' + cookieData + '; SameSite=Strict; path=/; domain=' +
document . cookie = 'PREFS=' + cookieData + '; SameSite=Strict; path=/; domain=' +
@ -279,7 +280,7 @@ player.on('volumechange', function () {
player . on ( 'waiting' , function ( ) {
player . on ( 'waiting' , function ( ) {
if ( player . playbackRate ( ) > 1 && player . liveTracker . isLive ( ) && player . liveTracker . atLiveEdge ( ) ) {
if ( player . playbackRate ( ) > 1 && player . liveTracker . isLive ( ) && player . liveTracker . atLiveEdge ( ) ) {
console . log ( 'Player has caught up to source, resetting playbackRate.' )
console . info ( 'Player has caught up to source, resetting playbackRate.' ) ;
player . playbackRate ( 1 ) ;
player . playbackRate ( 1 ) ;
}
}
} ) ;
} ) ;
@ -290,13 +291,13 @@ if (video_data.premiere_timestamp && Math.round(new Date() / 1000) < video_data.
if ( video _data . params . save _player _pos ) {
if ( video _data . params . save _player _pos ) {
const url = new URL ( location ) ;
const url = new URL ( location ) ;
const hasTimeParam = url . searchParams . has ( "t" ) ;
const hasTimeParam = url . searchParams . has ( 't' ) ;
const remeberedTime = get _video _time ( ) ;
const remeberedTime = get _video _time ( ) ;
let lastUpdated = 0 ;
let lastUpdated = 0 ;
if ( ! hasTimeParam ) set _seconds _after _start ( remeberedTime ) ;
if ( ! hasTimeParam ) set _seconds _after _start ( remeberedTime ) ;
const updateTime = ( ) => {
const updateTime = function ( ) {
const raw = player . currentTime ( ) ;
const raw = player . currentTime ( ) ;
const time = Math . floor ( raw ) ;
const time = Math . floor ( raw ) ;
@ -306,7 +307,7 @@ if (video_data.params.save_player_pos) {
}
}
} ;
} ;
player . on ( "timeupdate" , updateTime ) ;
player . on ( 'timeupdate' , updateTime ) ;
}
}
else remove _all _video _times ( ) ;
else remove _all _video _times ( ) ;
@ -316,13 +317,13 @@ if (video_data.params.autoplay) {
player . ready ( function ( ) {
player . ready ( function ( ) {
new Promise ( function ( resolve , reject ) {
new Promise ( function ( resolve , reject ) {
setTimeout ( ( ) => resolve ( 1 ) , 1 ) ;
setTimeout ( function ( ) { resolve ( 1 ) ; } , 1 ) ;
} ) . then ( function ( result ) {
} ) . then ( function ( result ) {
var promise = player . play ( ) ;
var promise = player . play ( ) ;
if ( promise !== undefined ) {
if ( promise !== undefined ) {
promise . then ( _ => {
promise . then ( function ( ) {
} ) . catch ( error => {
} ) . catch ( function ( error ) {
bpb . show ( ) ;
bpb . show ( ) ;
} ) ;
} ) ;
}
}
@ -333,16 +334,16 @@ if (video_data.params.autoplay) {
if ( ! video _data . params . listen && video _data . params . quality === 'dash' ) {
if ( ! video _data . params . listen && video _data . params . quality === 'dash' ) {
player . httpSourceSelector ( ) ;
player . httpSourceSelector ( ) ;
if ( video _data . params . quality _dash != "auto" ) {
if ( video _data . params . quality _dash != = 'auto' ) {
player . ready ( ( ) => {
player . ready ( function ( ) {
player . on ( "loadedmetadata" , ( ) => {
player . on ( 'loadedmetadata' , function ( ) {
const qualityLevels = Array . from ( player . qualityLevels ( ) ) . sort ( ( a , b ) => a . height - b . height ) ;
const qualityLevels = Array . from ( player . qualityLevels ( ) ) . sort ( function ( a , b ) {return a . height - b . height ; } ) ;
let targetQualityLevel ;
let targetQualityLevel ;
switch ( video _data . params . quality _dash ) {
switch ( video _data . params . quality _dash ) {
case "best" :
case 'best' :
targetQualityLevel = qualityLevels . length - 1 ;
targetQualityLevel = qualityLevels . length - 1 ;
break ;
break ;
case "worst" :
case 'worst' :
targetQualityLevel = 0 ;
targetQualityLevel = 0 ;
break ;
break ;
default :
default :
@ -356,7 +357,7 @@ if (!video_data.params.listen && video_data.params.quality === 'dash') {
}
}
}
}
for ( let i = 0 ; i < qualityLevels . length ; i ++ ) {
for ( let i = 0 ; i < qualityLevels . length ; i ++ ) {
qualityLevels [ i ] . enabled = ( i == targetQualityLevel ) ;
qualityLevels [ i ] . enabled = ( i == = targetQualityLevel ) ;
}
}
} ) ;
} ) ;
} ) ;
} ) ;
@ -390,10 +391,12 @@ if (!video_data.params.listen && video_data.params.annotations) {
}
}
}
}
}
}
}
} ;
window . addEventListener ( '__ar_annotation_click' , e => {
window . addEventListener ( '__ar_annotation_click' , function ( e ) {
const { url , target , seconds } = e . detail ;
const url = e . detail . url ,
target = e . detail . target ,
seconds = e . detail . seconds ;
var path = new URL ( url ) ;
var path = new URL ( url ) ;
if ( path . href . startsWith ( 'https://www.youtube.com/watch?' ) && seconds ) {
if ( path . href . startsWith ( 'https://www.youtube.com/watch?' ) && seconds ) {
@ -463,7 +466,7 @@ function get_video_time() {
return timestamp || 0 ;
return timestamp || 0 ;
}
}
catch {
catch (e ) {
return 0 ;
return 0 ;
}
}
}
}
@ -474,7 +477,7 @@ function set_all_video_times(times) {
try {
try {
storage . setItem ( save _player _pos _key , JSON . stringify ( times ) ) ;
storage . setItem ( save _player _pos _key , JSON . stringify ( times ) ) ;
} catch ( e ) {
} catch ( e ) {
console . debug ( 'set_all_video_times: ' + e ) ;
console . warn ( 'set_all_video_times: ' + e ) ;
}
}
} else {
} else {
storage . removeItem ( save _player _pos _key ) ;
storage . removeItem ( save _player _pos _key ) ;
@ -489,7 +492,7 @@ function get_all_video_times() {
try {
try {
return JSON . parse ( raw ) ;
return JSON . parse ( raw ) ;
} catch ( e ) {
} catch ( e ) {
console . debug ( 'get_all_video_times: ' + e ) ;
console . warn ( 'get_all_video_times: ' + e ) ;
}
}
}
}
}
}
@ -583,7 +586,7 @@ function increase_playback_rate(steps) {
player . playbackRate ( options . playbackRates [ newIndex ] ) ;
player . playbackRate ( options . playbackRates [ newIndex ] ) ;
}
}
window . addEventListener ( 'keydown' , e => {
window . addEventListener ( 'keydown' , function ( e ) {
if ( e . target . tagName . toLowerCase ( ) === 'input' ) {
if ( e . target . tagName . toLowerCase ( ) === 'input' ) {
// Ignore input when focus is on certain elements, e.g. form fields.
// Ignore input when focus is on certain elements, e.g. form fields.
return ;
return ;
@ -702,7 +705,7 @@ window.addEventListener('keydown', e => {
var volumeHover = false ;
var volumeHover = false ;
var volumeSelector = pEl . querySelector ( '.vjs-volume-menu-button' ) || pEl . querySelector ( '.vjs-volume-panel' ) ;
var volumeSelector = pEl . querySelector ( '.vjs-volume-menu-button' ) || pEl . querySelector ( '.vjs-volume-panel' ) ;
if ( volumeSelector != null ) {
if ( volumeSelector != = null ) {
volumeSelector . onmouseover = function ( ) { volumeHover = true ; } ;
volumeSelector . onmouseover = function ( ) { volumeHover = true ; } ;
volumeSelector . onmouseout = function ( ) { volumeHover = false ; } ;
volumeSelector . onmouseout = function ( ) { volumeHover = false ; } ;
}
}
@ -722,9 +725,9 @@ window.addEventListener('keydown', e => {
var delta = Math . max ( - 1 , Math . min ( 1 , ( event . wheelDelta || - event . detail ) ) ) ;
var delta = Math . max ( - 1 , Math . min ( 1 , ( event . wheelDelta || - event . detail ) ) ) ;
event . preventDefault ( ) ;
event . preventDefault ( ) ;
if ( delta == 1 ) {
if ( delta == = 1 ) {
increase _volume ( volumeStep ) ;
increase _volume ( volumeStep ) ;
} else if ( delta == - 1 ) {
} else if ( delta == = - 1 ) {
increase _volume ( - volumeStep ) ;
increase _volume ( - volumeStep ) ;
}
}
}
}
@ -733,7 +736,7 @@ window.addEventListener('keydown', e => {
} ;
} ;
player . on ( 'mousewheel' , mouseScroll ) ;
player . on ( 'mousewheel' , mouseScroll ) ;
player . on ( "DOMMouseScroll" , mouseScroll ) ;
player . on ( 'DOMMouseScroll' , mouseScroll ) ;
} ( ) ) ;
} ( ) ) ;
// Since videojs-share can sometimes be blocked, we defer it until last
// Since videojs-share can sometimes be blocked, we defer it until last
@ -743,13 +746,13 @@ if (player.share) {
// show the preferred caption by default
// show the preferred caption by default
if ( player _data . preferred _caption _found ) {
if ( player _data . preferred _caption _found ) {
player . ready ( ( ) => {
player . ready ( function ( ) {
player . textTracks ( ) [ 1 ] . mode = 'showing' ;
player . textTracks ( ) [ 1 ] . mode = 'showing' ;
} ) ;
} ) ;
}
}
// Safari audio double duration fix
// Safari audio double duration fix
if ( navigator . vendor == "Apple Computer, Inc." && video _data . params . listen ) {
if ( navigator . vendor == = 'Apple Computer, Inc.' && video _data . params . listen ) {
player . on ( 'loadedmetadata' , function ( ) {
player . on ( 'loadedmetadata' , function ( ) {
player . on ( 'timeupdate' , function ( ) {
player . on ( 'timeupdate' , function ( ) {
if ( player . remainingTime ( ) < player . duration ( ) / 2 && player . remainingTime ( ) >= 2 ) {
if ( player . remainingTime ( ) < player . duration ( ) / 2 && player . remainingTime ( ) >= 2 ) {
@ -760,18 +763,18 @@ if (navigator.vendor == "Apple Computer, Inc." && video_data.params.listen) {
}
}
// Watch on Invidious link
// Watch on Invidious link
if ( window . location . pathname . startsWith ( "/embed/" ) ) {
if ( window . location . pathname . startsWith ( '/embed/' ) ) {
const Button = videojs . getComponent ( 'Button' ) ;
const Button = videojs . getComponent ( 'Button' ) ;
let watch _on _invidious _button = new Button ( player ) ;
let watch _on _invidious _button = new Button ( player ) ;
// Create hyperlink for current instance
// Create hyperlink for current instance
redirect _element = document . createElement ( "a" ) ;
var redirect _element = document . createElement ( 'a' ) ;
redirect _element . setAttribute ( "href" , ` // ${ window . location . host } /watch?v= ${ window . location . pathname . replace ( "/embed/" , "" ) } ` )
redirect _element . setAttribute ( 'href' , location . pathname . replace ( '/embed/' , '/watch?v=' ) ) ;
redirect _element . appendChild ( document . createTextNode ( "Invidious" ) )
redirect _element . appendChild ( document . createTextNode ( 'Invidious' ) ) ;
watch _on _invidious _button . el ( ) . appendChild ( redirect _element )
watch _on _invidious _button . el ( ) . appendChild ( redirect _element ) ;
watch _on _invidious _button . addClass ( "watch-on-invidious" )
watch _on _invidious _button . addClass ( 'watch-on-invidious' ) ;
cb = player . getChild ( 'ControlBar' )
var cb = player . getChild ( 'ControlBar' ) ;
cb . addChild ( watch _on _invidious _button )
cb . addChild ( watch _on _invidious _button ) ;
} ;
}