2019-07-09 20:50:19 +02:00
//was sponsor data found when doing SponsorsLookup
var sponsorDataFound = false ;
2019-08-08 21:33:05 +02:00
var previousVideoID = null ;
2019-07-16 00:56:16 +02:00
//the actual sponsorTimes if loaded and UUIDs associated with them
2019-07-28 23:22:05 +02:00
var sponsorTimes = null ;
var UUIDs = null ;
//what video id are these sponsors for
var sponsorVideoID = null ;
2019-08-13 02:22:00 +02:00
//these are sponsors that have been downvoted
var hiddenSponsorTimes = [ ] ;
2019-08-03 04:37:12 +02:00
//the time this video is starting at when first played, if not zero
var youtubeVideoStartTime = null ;
2019-07-09 21:05:16 +02:00
//the video
var v ;
2019-08-13 19:02:35 +02:00
var listenerAdded ;
2019-08-14 01:18:53 +02:00
//the video id of the last preview bar update
var lastPreviewBarUpdate ;
//whether the duration listener listening for the duration changes of the video has been setup yet
var durationListenerSetUp = false ;
2019-08-04 03:35:41 +02:00
//the channel this video is about
var channelURL ;
//is this channel whitelised from getting sponsors skipped
var channelWhitelisted = false ;
2019-08-13 01:34:44 +02:00
// create preview bar
2019-08-13 20:05:32 +02:00
var previewBar ;
2019-08-13 01:34:44 +02:00
2019-08-20 23:59:34 +02:00
// Direct Links
videoIDChange ( getYouTubeVideoID ( document . URL ) ) ;
2019-07-09 21:05:16 +02:00
//the last time looked at (used to see if this time is in the interval)
2019-07-26 02:00:07 +02:00
var lastTime = - 1 ;
2019-01-18 20:49:43 +01:00
2019-08-12 05:18:50 +02:00
//the amount of times the sponsor lookup has retried
//this only happens if there is an error
var sponsorLookupRetries = 0 ;
2019-07-10 03:44:41 +02:00
//the last time in the video a sponsor was skipped
//used for the go back button
var lastSponsorTimeSkipped = null ;
2019-07-16 00:56:16 +02:00
//used for ratings
var lastSponsorTimeSkippedUUID = null ;
2019-07-10 03:44:41 +02:00
2019-07-12 22:48:07 +02:00
//if showing the start sponsor button or the end sponsor button on the player
var showingStartSponsor = true ;
2019-07-13 01:04:24 +02:00
//should the video controls buttons be added
var hideVideoPlayerControls = false ;
2019-07-30 03:40:13 +02:00
var hideInfoButtonPlayerControls = false ;
var hideDeleteButtonPlayerControls = false ;
2019-07-13 01:04:24 +02:00
2019-08-02 02:01:33 +02:00
//the sponsor times being prepared to be submitted
var sponsorTimesSubmitting = [ ] ;
2019-07-29 21:42:14 +02:00
//becomes true when isInfoFound is called
//this is used to close the popup on YouTube when the other popup opens
var popupInitialised = false ;
2019-07-24 03:06:36 +02:00
//should view counts be tracked
var trackViewCount = false ;
chrome . storage . sync . get ( [ "trackViewCount" ] , function ( result ) {
2019-08-20 01:21:19 +02:00
let trackViewCountStorage = result . trackViewCount ;
if ( trackViewCountStorage != undefined ) {
trackViewCount = trackViewCountStorage ;
} else {
trackViewCount = true ;
}
2019-07-24 03:06:36 +02:00
} ) ;
2019-07-10 04:10:25 +02:00
//if the notice should not be shown
//happens when the user click's the "Don't show notice again" button
var dontShowNotice = false ;
2019-07-22 22:42:57 +02:00
chrome . storage . sync . get ( [ "dontShowNoticeAgain" ] , function ( result ) {
2019-08-20 01:21:19 +02:00
let dontShowNoticeAgain = result . dontShowNoticeAgain ;
if ( dontShowNoticeAgain != undefined ) {
dontShowNotice = dontShowNoticeAgain ;
}
2019-07-10 04:10:25 +02:00
} ) ;
2019-07-30 19:27:20 +02:00
//get messages from the background script and the popup
chrome . runtime . onMessage . addListener ( messageListener ) ;
2019-08-08 20:26:26 +02:00
2019-07-30 19:27:20 +02:00
function messageListener ( request , sender , sendResponse ) {
2019-08-20 01:21:19 +02:00
//messages from popup script
2019-08-08 21:15:23 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "update" ) {
2019-08-21 19:17:30 +02:00
videoIDChange ( getYouTubeVideoID ( document . URL ) ) ;
2019-08-20 01:21:19 +02:00
}
2019-08-08 21:15:23 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "sponsorStart" ) {
sponsorMessageStarted ( sendResponse ) ;
}
2019-07-09 06:05:27 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "sponsorDataChanged" ) {
updateSponsorTimesSubmitting ( ) ;
}
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "isInfoFound" ) {
//send the sponsor times along with if it's found
sendResponse ( {
found : sponsorDataFound ,
sponsorTimes : sponsorTimes ,
hiddenSponsorTimes : hiddenSponsorTimes ,
UUIDs : UUIDs
} ) ;
if ( popupInitialised && document . getElementById ( "sponsorBlockPopupContainer" ) != null ) {
//the popup should be closed now that another is opening
closeInfoMenu ( ) ;
}
popupInitialised = true ;
}
2019-07-09 21:55:33 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "getVideoID" ) {
sendResponse ( {
2019-08-20 21:27:30 +02:00
videoID : sponsorVideoID
2019-08-20 01:21:19 +02:00
} )
}
2019-07-10 04:10:25 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "skipToTime" ) {
v . currentTime = request . time ;
}
2019-08-12 18:21:20 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "getCurrentTime" ) {
sendResponse ( {
currentTime : v . currentTime
} ) ;
}
2019-08-12 21:27:35 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "getChannelURL" ) {
sendResponse ( {
channelURL : channelURL
} )
}
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "isChannelWhitelisted" ) {
sendResponse ( {
value : channelWhitelisted
} )
}
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "whitelistChange" ) {
channelWhitelisted = request . value ;
2019-08-20 21:27:30 +02:00
sponsorsLookup ( sponsorVideoID ) ;
2019-08-20 01:21:19 +02:00
}
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "showNoticeAgain" ) {
dontShowNotice = false ;
}
2019-07-12 23:45:20 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "changeStartSponsorButton" ) {
changeStartSponsorButton ( request . showStartSponsor , request . uploadButtonVisible ) ;
}
2019-07-13 01:04:24 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "changeVideoPlayerControlsVisibility" ) {
hideVideoPlayerControls = request . value ;
2019-07-13 01:04:24 +02:00
2019-08-20 01:21:19 +02:00
updateVisibilityOfPlayerControlsButton ( ) ;
} else if ( request . message == "changeInfoButtonPlayerControlsVisibility" ) {
hideInfoButtonPlayerControls = request . value ;
2019-07-30 03:40:13 +02:00
2019-08-20 01:21:19 +02:00
updateVisibilityOfPlayerControlsButton ( ) ;
} else if ( request . message == "changeDeleteButtonPlayerControlsVisibility" ) {
hideDeleteButtonPlayerControls = request . value ;
2019-07-30 03:40:13 +02:00
2019-08-20 01:21:19 +02:00
updateVisibilityOfPlayerControlsButton ( ) ;
}
2019-07-24 03:06:36 +02:00
2019-08-20 01:21:19 +02:00
if ( request . message == "trackViewCount" ) {
trackViewCount = request . value ;
}
2019-07-30 19:27:20 +02:00
}
2018-06-23 17:09:05 +02:00
2019-07-26 22:20:07 +02:00
//check for hotkey pressed
document . onkeydown = function ( e ) {
2019-08-20 01:21:19 +02:00
e = e || window . event ;
var key = e . which || e . keyCode ;
let video = document . getElementById ( "movie_player" ) ;
//is the video in focus, otherwise they could be typing a comment
if ( document . activeElement === video ) {
if ( key == 186 ) {
//semicolon
startSponsorClicked ( ) ;
} else if ( key == 222 ) {
//single quote
submitSponsorTimes ( ) ;
}
2019-07-26 22:20:07 +02:00
}
}
2019-08-14 01:18:53 +02:00
function resetValues ( ) {
2019-08-20 01:21:19 +02:00
//reset last sponsor times
lastTime = - 1 ;
2019-08-14 01:18:53 +02:00
2019-08-20 01:21:19 +02:00
//reset sponsor times
sponsorTimes = null ;
UUIDs = null ;
sponsorLookupRetries = 0 ;
2019-08-14 01:18:53 +02:00
2019-08-20 01:21:19 +02:00
//empty the preview bar
2019-08-21 00:37:40 +02:00
previewBar = null ;
2019-08-14 01:18:53 +02:00
2019-08-20 01:21:19 +02:00
//reset sponsor data found check
sponsorDataFound = false ;
2019-08-14 01:18:53 +02:00
}
2019-07-13 00:28:41 +02:00
function videoIDChange ( id ) {
2019-08-21 00:26:35 +02:00
// ID has not changed return
if ( sponsorVideoID === id ) return
2019-08-21 19:17:30 +02:00
// Global ID
2019-08-21 20:10:49 +02:00
sponsorVideoID = id ;
2019-08-21 00:26:35 +02:00
resetValues ( ) ;
// ID is not valid
if ( id === false ) return ;
2019-08-21 20:10:49 +02:00
2019-08-20 01:21:19 +02:00
if ( previewBar == null ) {
//create it
let progressBar = document . getElementsByClassName ( "ytp-progress-bar-container" ) [ 0 ] || document . getElementsByClassName ( "no-model cue-range-markers" ) [ 0 ] ;
previewBar = new PreviewBar ( progressBar ) ;
2019-07-13 01:04:24 +02:00
}
2019-08-20 01:21:19 +02:00
//warn them if they had unsubmitted times
if ( previousVideoID != null ) {
//get the sponsor times from storage
let sponsorTimeKey = 'sponsorTimes' + previousVideoID ;
chrome . storage . sync . get ( [ sponsorTimeKey ] , function ( result ) {
let sponsorTimes = result [ sponsorTimeKey ] ;
if ( sponsorTimes != undefined && sponsorTimes . length > 0 ) {
//warn them that they have unsubmitted sponsor times
chrome . runtime . sendMessage ( {
message : "alertPrevious" ,
previousVideoID : previousVideoID
} )
}
//set the previous video id to the currentID
previousVideoID = id ;
} ) ;
} else {
//set the previous id now, don't wait for chrome.storage.get
previousVideoID = id ;
2019-07-30 03:40:13 +02:00
}
2019-08-20 01:21:19 +02:00
//close popup
closeInfoMenu ( ) ;
2019-08-20 21:27:30 +02:00
2019-08-21 20:10:49 +02:00
addButtons ( ) ;
2019-08-20 21:27:30 +02:00
2019-08-20 01:21:19 +02:00
//see if there is a video start time
2019-08-20 21:27:30 +02:00
youtubeVideoStartTime = sponsorVideoID ;
2019-08-20 01:21:19 +02:00
sponsorsLookup ( id ) ;
//make sure everything is properly added
updateVisibilityOfPlayerControlsButton ( true ) ;
//reset sponsor times submitting
sponsorTimesSubmitting = [ ] ;
//see if the onvideo control image needs to be changed
2019-08-21 19:17:30 +02:00
wait ( getControls ) . then ( result => {
chrome . runtime . sendMessage ( {
message : "getSponsorTimes" ,
videoID : id
} , function ( response ) {
if ( response != undefined ) {
let sponsorTimes = response . sponsorTimes ;
if ( sponsorTimes != null && sponsorTimes . length > 0 && sponsorTimes [ sponsorTimes . length - 1 ] . length >= 2 ) {
changeStartSponsorButton ( true , true ) ;
} else if ( sponsorTimes != null && sponsorTimes . length > 0 && sponsorTimes [ sponsorTimes . length - 1 ] . length < 2 ) {
2019-08-20 01:21:19 +02:00
changeStartSponsorButton ( false , true ) ;
2019-08-21 19:17:30 +02:00
} else {
changeStartSponsorButton ( true , false ) ;
}
//see if this data should be saved in the sponsorTimesSubmitting variable
if ( sponsorTimes != undefined && sponsorTimes . length > 0 ) {
sponsorTimesSubmitting = sponsorTimes ;
}
}
} ) ;
} ) ;
2019-08-20 01:21:19 +02:00
2019-07-30 03:40:13 +02:00
2019-08-20 01:21:19 +02:00
//see if video controls buttons should be added
chrome . storage . sync . get ( [ "hideVideoPlayerControls" ] , function ( result ) {
if ( result . hideVideoPlayerControls != undefined ) {
hideVideoPlayerControls = result . hideVideoPlayerControls ;
}
updateVisibilityOfPlayerControlsButton ( ) ;
} ) ;
chrome . storage . sync . get ( [ "hideInfoButtonPlayerControls" ] , function ( result ) {
if ( result . hideInfoButtonPlayerControls != undefined ) {
hideInfoButtonPlayerControls = result . hideInfoButtonPlayerControls ;
}
2019-07-30 03:40:13 +02:00
2019-08-20 01:21:19 +02:00
updateVisibilityOfPlayerControlsButton ( ) ;
} ) ;
chrome . storage . sync . get ( [ "hideDeleteButtonPlayerControls" ] , function ( result ) {
if ( result . hideDeleteButtonPlayerControls != undefined ) {
hideDeleteButtonPlayerControls = result . hideDeleteButtonPlayerControls ;
}
updateVisibilityOfPlayerControlsButton ( false ) ;
} ) ;
2019-07-30 03:40:13 +02:00
2019-07-13 00:28:41 +02:00
}
2019-07-09 20:50:19 +02:00
function sponsorsLookup ( id ) {
2019-08-20 01:21:19 +02:00
v = document . querySelector ( 'video' ) // Youtube video player
//there is no video here
if ( v == null ) {
setTimeout ( ( ) => sponsorsLookup ( id ) , 100 ) ;
return ;
}
2019-08-12 05:18:50 +02:00
2019-08-20 01:21:19 +02:00
if ( ! durationListenerSetUp ) {
durationListenerSetUp = true ;
2019-08-12 05:18:50 +02:00
2019-08-20 01:21:19 +02:00
//wait until it is loaded
v . addEventListener ( 'durationchange' , updatePreviewBar ) ;
2019-07-26 02:00:07 +02:00
}
2019-08-20 01:21:19 +02:00
//check database for sponsor times
sendRequestToServer ( 'GET' , "/api/getVideoSponsorTimes?videoID=" + id , function ( xmlhttp ) {
if ( xmlhttp . readyState == 4 && xmlhttp . status == 200 ) {
sponsorDataFound = true ;
sponsorTimes = JSON . parse ( xmlhttp . responseText ) . sponsorTimes ;
UUIDs = JSON . parse ( xmlhttp . responseText ) . UUIDs ;
//update the preview bar
//leave the type blank for now until categories are added
if ( lastPreviewBarUpdate == id || ( lastPreviewBarUpdate == null && ! isNaN ( v . duration ) ) ) {
//set it now
//otherwise the listener can handle it
updatePreviewBar ( ) ;
}
getChannelID ( ) ;
sponsorLookupRetries = 0 ;
} else if ( xmlhttp . readyState == 4 && xmlhttp . status == 404 ) {
sponsorDataFound = false ;
//check if this video was uploaded recently
//use the invidious api to get the time published
sendRequestToCustomServer ( 'GET' , "https://invidio.us/api/v1/videos/" + id , function ( xmlhttp , error ) {
if ( xmlhttp . readyState == 4 && xmlhttp . status == 200 ) {
let unixTimePublished = JSON . parse ( xmlhttp . responseText ) . published ;
//if less than 3 days old
if ( ( Date . now ( ) / 1000 ) - unixTimePublished < 259200 ) {
setTimeout ( ( ) => sponsorsLookup ( id ) , 10000 ) ;
}
}
} ) ;
sponsorLookupRetries = 0 ;
} else if ( xmlhttp . readyState == 4 && sponsorLookupRetries < 90 ) {
//some error occurred, try again in a second
setTimeout ( ( ) => sponsorsLookup ( id ) , 1000 ) ;
sponsorLookupRetries ++ ;
}
} ) ;
2019-07-26 02:00:07 +02:00
2019-08-20 01:21:19 +02:00
//add the event to run on the videos "ontimeupdate"
v . ontimeupdate = function ( ) {
sponsorCheck ( ) ;
} ;
2019-08-02 02:01:33 +02:00
}
2019-07-24 01:33:12 +02:00
2019-08-13 19:02:35 +02:00
function updatePreviewBar ( ) {
2019-08-20 01:21:19 +02:00
previewBar . set ( sponsorTimes , [ ] , v . duration ) ;
2019-08-13 19:02:35 +02:00
2019-08-20 01:21:19 +02:00
//update last video id
2019-08-20 21:27:30 +02:00
lastPreviewBarUpdate = sponsorVideoID ;
2019-08-13 19:02:35 +02:00
}
2019-08-04 03:35:41 +02:00
function getChannelID ( ) {
2019-08-20 01:21:19 +02:00
//get channel id
let channelContainers = document . querySelectorAll ( "#owner-name" ) ;
let channelURLContainer = null ;
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
for ( let i = 0 ; i < channelContainers . length ; i ++ ) {
if ( channelContainers [ i ] . firstElementChild != null ) {
channelURLContainer = channelContainers [ i ] . firstElementChild ;
}
2019-08-04 03:35:41 +02:00
}
2019-08-20 01:21:19 +02:00
if ( channelContainers . length == 0 ) {
//old YouTube theme
channelContainers = document . getElementsByClassName ( "yt-user-info" ) ;
if ( channelContainers . length != 0 ) {
channelURLContainer = channelContainers [ 0 ] . firstElementChild ;
}
2019-08-04 04:12:20 +02:00
}
2019-08-20 01:21:19 +02:00
if ( channelURLContainer == null ) {
//try later
setTimeout ( getChannelID , 100 ) ;
return ;
}
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
channelURL = channelURLContainer . getAttribute ( "href" ) ;
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
//see if this is a whitelisted channel
chrome . storage . sync . get ( [ "whitelistedChannels" ] , function ( result ) {
let whitelistedChannels = result . whitelistedChannels ;
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
if ( whitelistedChannels != undefined && whitelistedChannels . includes ( channelURL ) ) {
//reset sponsor times to nothing
sponsorTimes = [ ] ;
UUIDs = [ ] ;
2019-08-04 03:35:41 +02:00
2019-08-20 01:21:19 +02:00
channelWhitelisted = true ;
}
} ) ;
2019-08-04 03:35:41 +02:00
}
2019-08-02 02:01:33 +02:00
//video skipping
function sponsorCheck ( ) {
2019-08-20 01:21:19 +02:00
let skipHappened = false ;
if ( sponsorTimes != null ) {
//see if any sponsor start time was just passed
for ( let i = 0 ; i < sponsorTimes . length ; i ++ ) {
//if something was skipped
if ( checkSponsorTime ( sponsorTimes , i , true ) ) {
skipHappened = true ;
break ;
}
}
2019-08-02 02:01:33 +02:00
}
2019-08-20 01:21:19 +02:00
if ( ! skipHappened ) {
//check for the "preview" sponsors (currently edited by this user)
for ( let i = 0 ; i < sponsorTimesSubmitting . length ; i ++ ) {
//must be a finished sponsor and be valid
if ( sponsorTimesSubmitting [ i ] . length > 1 && sponsorTimesSubmitting [ i ] [ 1 ] > sponsorTimesSubmitting [ i ] [ 0 ] ) {
checkSponsorTime ( sponsorTimesSubmitting , i , false ) ;
}
}
2019-07-16 00:56:16 +02:00
}
2019-07-26 02:00:07 +02:00
2019-08-20 01:21:19 +02:00
//don't keep track until they are loaded in
if ( sponsorTimes != null || sponsorTimesSubmitting . length > 0 ) {
lastTime = v . currentTime ;
}
2018-06-23 17:09:05 +02:00
}
2019-01-18 20:49:43 +01:00
2019-08-02 02:01:33 +02:00
function checkSponsorTime ( sponsorTimes , index , openNotice ) {
2019-08-20 01:21:19 +02:00
//this means part of the video was just skipped
if ( Math . abs ( v . currentTime - lastTime ) > 1 && lastTime != - 1 ) {
//make lastTime as if the video was playing normally
lastTime = v . currentTime - 0.0001 ;
}
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
if ( checkIfTimeToSkip ( v . currentTime , sponsorTimes [ index ] [ 0 ] ) && ! hiddenSponsorTimes . includes ( index ) ) {
//skip it
skipToTime ( v , index , sponsorTimes , openNotice ) ;
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
//something was skipped
return true ;
}
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
return false ;
2019-08-02 02:01:33 +02:00
}
function checkIfTimeToSkip ( currentVideoTime , startTime ) {
2019-08-20 01:21:19 +02:00
//If the sponsor time is in between these times, skip it
//Checks if the last time skipped to is not too close to now, to make sure not to get too many
// sponsor times in a row (from one troll)
//the last term makes 0 second start times possible only if the video is not setup to start at a different time from zero
return ( Math . abs ( currentVideoTime - startTime ) < 3 && startTime >= lastTime && startTime <= currentVideoTime ) ||
( lastTime == - 1 && startTime == 0 && youtubeVideoStartTime == null )
2019-08-02 02:01:33 +02:00
}
//skip fromt he start time to the end time for a certain index sponsor time
function skipToTime ( v , index , sponsorTimes , openNotice ) {
2019-08-20 01:21:19 +02:00
v . currentTime = sponsorTimes [ index ] [ 1 ] ;
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
lastSponsorTimeSkipped = sponsorTimes [ index ] [ 0 ] ;
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
let currentUUID = UUIDs [ index ] ;
lastSponsorTimeSkippedUUID = currentUUID ;
if ( openNotice ) {
//send out the message saying that a sponsor message was skipped
if ( ! dontShowNotice ) {
new SkipNotice ( this , currentUUID ) ;
//auto-upvote this sponsor
if ( trackViewCount ) {
vote ( 1 , currentUUID , null ) ;
}
}
2019-08-15 04:08:23 +02:00
}
2019-08-15 17:12:46 +02:00
2019-08-20 01:21:19 +02:00
//send telemetry that a this sponsor was skipped happened
if ( trackViewCount ) {
sendRequestToServer ( "GET" , "/api/viewedVideoSponsorTime?UUID=" + currentUUID ) ;
}
2019-08-02 02:01:33 +02:00
}
2019-08-20 01:07:14 +02:00
function unskipSponsorTime ( UUID ) {
2019-08-20 01:21:19 +02:00
if ( sponsorTimes != null ) {
//add a tiny bit of time to make sure it is not skipped again
v . currentTime = sponsorTimes [ UUIDs . indexOf ( UUID ) ] [ 0 ] + 0.001 ;
}
2019-08-20 01:07:14 +02:00
}
2019-07-10 03:44:41 +02:00
2019-08-20 01:07:14 +02:00
function reskipSponsorTime ( UUID ) {
2019-08-20 01:21:19 +02:00
if ( sponsorTimes != null ) {
//add a tiny bit of time to make sure it is not skipped again
v . currentTime = sponsorTimes [ UUIDs . indexOf ( UUID ) ] [ 1 ] ;
}
2019-07-10 03:44:41 +02:00
}
2019-07-13 01:04:24 +02:00
function removePlayerControlsButton ( ) {
2019-08-21 20:10:49 +02:00
if ( ! sponsorVideoID ) return ;
2019-08-20 21:27:30 +02:00
document . getElementById ( "changeStartSponsor" ) . style . display = "none" ;
2019-08-20 01:21:19 +02:00
document . getElementById ( "submitButton" ) . style . display = "none" ;
2019-07-13 01:04:24 +02:00
}
2019-08-21 20:10:49 +02:00
function createButton ( baseID , title , callback , imageName ) {
if ( document . getElementById ( baseID + "Button" ) != null ) return ;
2019-08-21 19:17:30 +02:00
// Button HTML
2019-08-20 21:27:30 +02:00
let newButton = document . createElement ( "button" ) ;
2019-08-21 20:10:49 +02:00
newButton . id = baseID + "Button" ;
2019-08-20 21:27:30 +02:00
newButton . className = "ytp-button playerButton" ;
2019-08-21 20:15:35 +02:00
newButton . setAttribute ( "title" , chrome . i18n . getMessage ( title ) ) ;
2019-08-20 21:27:30 +02:00
newButton . addEventListener ( "click" , callback ) ;
2019-08-21 19:17:30 +02:00
// Image HTML
2019-08-20 21:27:30 +02:00
let newButtonImage = document . createElement ( "img" ) ;
2019-08-21 20:10:49 +02:00
newButtonImage . id = baseID + "Image" ;
2019-08-20 21:27:30 +02:00
newButtonImage . className = "playerButtonImage" ;
newButtonImage . src = chrome . extension . getURL ( "icons/" + imageName ) ;
2019-08-21 19:17:30 +02:00
// Append image to button
newButton . appendChild ( newButtonImage ) ;
// Add the button to player
2019-08-20 21:27:30 +02:00
controls . prepend ( newButton ) ;
}
function getControls ( ) {
2019-08-21 00:26:35 +02:00
let controls = document . getElementsByClassName ( "ytp-right-controls" ) ;
return ( ! controls || controls . length === 0 ) ? false : controls [ controls . length - 1 ]
2019-08-20 21:27:30 +02:00
} ;
//adds the player controls buttons
function addButtons ( ) {
wait ( getControls ) . then ( result => {
2019-08-21 00:26:35 +02:00
controls = result ; // Global
// Add button if does not already exist in html
createButton ( "startSponsor" , "sponsorStart" , startSponsorClicked , "PlayerStartIconSponsorBlocker256px.png" ) ;
2019-08-21 20:10:49 +02:00
createButton ( "info" , "openPopup" , openInfoMenu , "PlayerInfoIconSponsorBlocker256px.png" )
2019-08-21 19:17:30 +02:00
createButton ( "delete" , "clearTimes" , clearSponsorTimes , "PlayerDeleteIconSponsorBlocker256px.png" ) ;
2019-08-21 20:10:49 +02:00
createButton ( "submit" , "SubmitTimes" , submitSponsorTimes , "PlayerUploadIconSponsorBlocker256px.png" ) ;
2019-08-20 21:27:30 +02:00
} ) ;
}
2019-07-13 01:04:24 +02:00
//adds or removes the player controls button to what it should be
function updateVisibilityOfPlayerControlsButton ( ) {
2019-08-20 01:21:19 +02:00
//not on a proper video yet
2019-08-20 21:27:30 +02:00
if ( ! sponsorVideoID ) return ;
2019-08-20 01:21:19 +02:00
if ( hideVideoPlayerControls ) {
removePlayerControlsButton ( ) ;
}
if ( hideInfoButtonPlayerControls ) {
document . getElementById ( "infoButton" ) . style . display = "none" ;
}
if ( hideDeleteButtonPlayerControls ) {
document . getElementById ( "deleteButton" ) . style . display = "none" ;
}
2019-07-13 01:04:24 +02:00
}
2019-07-12 16:42:39 +02:00
2019-07-12 22:44:50 +02:00
function startSponsorClicked ( ) {
2019-08-20 01:21:19 +02:00
//it can't update to this info yet
closeInfoMenu ( ) ;
toggleStartSponsorButton ( ) ;
//send back current time with message
chrome . runtime . sendMessage ( {
message : "addSponsorTime" ,
time : v . currentTime ,
2019-08-20 21:27:30 +02:00
videoID : sponsorVideoID
2019-08-20 01:21:19 +02:00
} , function ( response ) {
//see if the sponsorTimesSubmitting needs to be updated
updateSponsorTimesSubmitting ( ) ;
} ) ;
2019-08-02 02:01:33 +02:00
}
function updateSponsorTimesSubmitting ( ) {
2019-08-20 01:21:19 +02:00
chrome . runtime . sendMessage ( {
message : "getSponsorTimes" ,
2019-08-20 21:27:30 +02:00
videoID : sponsorVideoID
2019-08-20 01:21:19 +02:00
} , function ( response ) {
if ( response != undefined ) {
let sponsorTimes = response . sponsorTimes ;
//see if this data should be saved in the sponsorTimesSubmitting variable
if ( sponsorTimes != undefined ) {
sponsorTimesSubmitting = sponsorTimes ;
}
}
} ) ;
2019-07-12 22:50:26 +02:00
}
2019-08-21 19:17:30 +02:00
isSubmitLoaded = ( ) => ( document . getElementById ( "startSponsorImage" ) !== undefined ) ;
2019-07-22 22:46:50 +02:00
function changeStartSponsorButton ( showStartSponsor , uploadButtonVisible ) {
2019-08-20 21:27:30 +02:00
if ( ! sponsorVideoID ) return false ;
2019-08-21 19:17:30 +02:00
wait ( isSubmitLoaded ) . then ( result => {
//if it isn't visible, there is no data
let shouldHide = ( uploadButtonVisible && ! hideDeleteButtonPlayerControls ) ? "unset" : "none"
document . getElementById ( "deleteButton" ) . style . display = shouldHide ;
2019-07-22 00:19:56 +02:00
2019-08-20 01:21:19 +02:00
if ( showStartSponsor ) {
showingStartSponsor = true ;
document . getElementById ( "startSponsorImage" ) . src = chrome . extension . getURL ( "icons/PlayerStartIconSponsorBlocker256px.png" ) ;
2019-08-21 19:17:30 +02:00
document . getElementById ( "startSponsorButton" ) . setAttribute ( "title" , chrome . i18n . getMessage ( "sponsorStart" ) ) ;
2019-08-20 01:21:19 +02:00
if ( document . getElementById ( "startSponsorImage" ) . style . display != "none" && uploadButtonVisible && ! hideInfoButtonPlayerControls ) {
document . getElementById ( "submitButton" ) . style . display = "unset" ;
} else if ( ! uploadButtonVisible ) {
//disable submit button
document . getElementById ( "submitButton" ) . style . display = "none" ;
}
} else {
showingStartSponsor = false ;
document . getElementById ( "startSponsorImage" ) . src = chrome . extension . getURL ( "icons/PlayerStopIconSponsorBlocker256px.png" ) ;
2019-08-21 19:17:30 +02:00
document . getElementById ( "startSponsorButton" ) . setAttribute ( "title" , chrome . i18n . getMessage ( "sponsorEND" ) ) ;
2019-08-20 01:21:19 +02:00
//disable submit button
document . getElementById ( "submitButton" ) . style . display = "none" ;
}
2019-08-21 19:17:30 +02:00
} ) ;
2019-07-22 00:19:56 +02:00
}
function toggleStartSponsorButton ( ) {
2019-08-20 01:21:19 +02:00
changeStartSponsorButton ( ! showingStartSponsor , true ) ;
2019-07-22 00:19:56 +02:00
}
2019-07-29 21:42:14 +02:00
function openInfoMenu ( ) {
2019-08-20 01:21:19 +02:00
if ( document . getElementById ( "sponsorBlockPopupContainer" ) != null ) {
//it's already added
return ;
}
popupInitialised = false ;
//hide info button
document . getElementById ( "infoButton" ) . style . display = "none" ;
sendRequestToCustomServer ( 'GET' , chrome . extension . getURL ( "popup.html" ) , function ( xmlhttp ) {
if ( xmlhttp . readyState == 4 && xmlhttp . status == 200 ) {
var popup = document . createElement ( "div" ) ;
popup . id = "sponsorBlockPopupContainer" ;
popup . innerHTML = xmlhttp . responseText
//close button
let closeButton = document . createElement ( "div" ) ;
closeButton . innerText = "Close Popup" ;
closeButton . classList = "smallLink" ;
closeButton . setAttribute ( "align" , "center" ) ;
closeButton . addEventListener ( "click" , closeInfoMenu ) ;
//add the close button
popup . prepend ( closeButton ) ;
2019-07-30 19:27:20 +02:00
2019-08-20 01:21:19 +02:00
let parentNode = document . getElementById ( "secondary" ) ;
if ( parentNode == null ) {
//old youtube theme
parentNode = document . getElementById ( "watch7-sidebar-contents" ) ;
}
2019-07-29 21:42:14 +02:00
2019-08-20 01:21:19 +02:00
//make the logo source not 404
//query selector must be used since getElementByID doesn't work on a node and this isn't added to the document yet
let logo = popup . querySelector ( "#sponsorBlockPopupLogo" ) ;
logo . src = chrome . extension . getURL ( "icons/LogoSponsorBlocker256px.png" ) ;
2019-07-29 21:42:14 +02:00
2019-08-20 01:21:19 +02:00
//remove the style sheet and font that are not necessary
popup . querySelector ( "#sponorBlockPopupFont" ) . remove ( ) ;
popup . querySelector ( "#sponorBlockStyleSheet" ) . remove ( ) ;
2019-07-29 21:42:14 +02:00
2019-08-20 01:21:19 +02:00
parentNode . insertBefore ( popup , parentNode . firstChild ) ;
2019-07-29 21:42:14 +02:00
2019-08-20 01:21:19 +02:00
//run the popup init script
runThePopup ( ) ;
}
} ) ;
2019-07-29 21:42:14 +02:00
}
function closeInfoMenu ( ) {
2019-08-20 01:21:19 +02:00
let popup = document . getElementById ( "sponsorBlockPopupContainer" ) ;
if ( popup != null ) {
popup . remove ( ) ;
2019-07-29 21:42:14 +02:00
2019-08-20 01:21:19 +02:00
//show info button
document . getElementById ( "infoButton" ) . style . display = "unset" ;
}
2019-07-29 21:42:14 +02:00
}
2019-07-30 02:54:10 +02:00
function clearSponsorTimes ( ) {
2019-08-20 01:21:19 +02:00
//it can't update to this info yet
closeInfoMenu ( ) ;
2019-07-30 02:54:10 +02:00
2019-08-20 21:27:30 +02:00
let currentVideoID = sponsorVideoID ;
2019-07-30 02:54:10 +02:00
2019-08-20 01:21:19 +02:00
let sponsorTimeKey = 'sponsorTimes' + currentVideoID ;
chrome . storage . sync . get ( [ sponsorTimeKey ] , function ( result ) {
let sponsorTimes = result [ sponsorTimeKey ] ;
2019-07-30 02:54:10 +02:00
2019-08-20 01:21:19 +02:00
if ( sponsorTimes != undefined && sponsorTimes . length > 0 ) {
let confirmMessage = chrome . i18n . getMessage ( "clearThis" ) + getSponsorTimesMessage ( sponsorTimes ) ;
confirmMessage += chrome . i18n . getMessage ( "confirmMSG" )
if ( ! confirm ( confirmMessage ) ) return ;
2019-07-30 02:54:10 +02:00
2019-08-20 01:21:19 +02:00
//clear the sponsor times
let sponsorTimeKey = "sponsorTimes" + currentVideoID ;
chrome . storage . sync . set ( { [ sponsorTimeKey ] : [ ] } ) ;
2019-07-30 02:54:10 +02:00
2019-08-20 01:21:19 +02:00
//clear sponsor times submitting
sponsorTimesSubmitting = [ ] ;
2019-08-02 02:01:33 +02:00
2019-08-20 01:21:19 +02:00
//set buttons to be correct
changeStartSponsorButton ( true , false ) ;
}
} ) ;
2019-07-30 02:54:10 +02:00
}
2019-08-19 22:09:54 +02:00
//if skipNotice is null, it will not affect the UI
function vote ( type , UUID , skipNotice ) {
2019-08-20 01:21:19 +02:00
if ( skipNotice != null ) {
//add loading info
skipNotice . addVoteButtonInfo . bind ( skipNotice ) ( "Loading..." )
skipNotice . resetNoticeInfoMessage . bind ( skipNotice ) ( ) ;
2019-07-20 04:24:59 +02:00
}
2019-08-20 01:21:19 +02:00
chrome . runtime . sendMessage ( {
message : "submitVote" ,
type : type ,
UUID : UUID
} , function ( response ) {
if ( response != undefined ) {
//see if it was a success or failure
if ( skipNotice != null ) {
if ( response . successType == 1 ) {
//success
if ( type == 0 ) {
skipNotice . afterDownvote . bind ( skipNotice ) ( ) ;
}
} else if ( response . successType == 0 ) {
//failure: duplicate vote
skipNotice . addNoticeInfoMessage . bind ( skipNotice ) ( chrome . i18n . getMessage ( "voteFail" ) )
skipNotice . resetVoteButtonInfo . bind ( skipNotice ) ( ) ;
} else if ( response . successType == - 1 ) {
if ( response . statusCode == 502 ) {
skipNotice . addNoticeInfoMessage . bind ( skipNotice ) ( chrome . i18n . getMessage ( "serverDown" ) )
skipNotice . resetVoteButtonInfo . bind ( skipNotice ) ( ) ;
} else {
//failure: unknown error
skipNotice . addNoticeInfoMessage . bind ( skipNotice ) ( chrome . i18n . getMessage ( "connectionError" ) + response . statusCode ) ;
skipNotice . resetVoteButtonInfo . bind ( skipNotice ) ( ) ;
}
}
}
}
} ) ;
2019-07-16 01:13:09 +02:00
}
2019-07-18 01:42:13 +02:00
//Closes all notices that tell the user that a sponsor was just skipped
function closeAllSkipNotices ( ) {
2019-08-20 01:21:19 +02:00
let notices = document . getElementsByClassName ( "sponsorSkipNotice" ) ;
for ( let i = 0 ; i < notices . length ; i ++ ) {
notices [ i ] . remove ( ) ;
}
2019-07-18 01:42:13 +02:00
}
2019-07-10 04:10:25 +02:00
function dontShowNoticeAgain ( ) {
2019-08-20 01:21:19 +02:00
chrome . storage . sync . set ( { "dontShowNoticeAgain" : true } ) ;
2019-07-10 04:10:25 +02:00
2019-08-20 01:21:19 +02:00
dontShowNotice = true ;
2019-07-10 04:10:25 +02:00
2019-08-20 01:21:19 +02:00
closeAllSkipNotices ( ) ;
2019-07-10 04:10:25 +02:00
}
2019-07-29 21:42:14 +02:00
function sponsorMessageStarted ( callback ) {
2019-08-20 01:21:19 +02:00
v = document . querySelector ( 'video' ) ;
2019-07-09 05:43:06 +02:00
2019-08-20 01:21:19 +02:00
//send back current time
callback ( {
time : v . currentTime
} )
2019-07-12 22:50:26 +02:00
2019-08-20 01:21:19 +02:00
//update button
toggleStartSponsorButton ( ) ;
2019-07-10 03:15:43 +02:00
}
2019-07-22 00:19:56 +02:00
function submitSponsorTimes ( ) {
2019-08-20 01:21:19 +02:00
if ( document . getElementById ( "submitButton" ) . style . display == "none" ) {
//don't submit, not ready
return ;
}
2019-07-27 17:08:29 +02:00
2019-08-20 01:21:19 +02:00
//it can't update to this info yet
closeInfoMenu ( ) ;
2019-07-29 21:42:14 +02:00
2019-08-20 21:27:30 +02:00
let currentVideoID = sponsorVideoID ;
2019-07-29 17:36:57 +02:00
2019-08-20 01:21:19 +02:00
let sponsorTimeKey = 'sponsorTimes' + currentVideoID ;
chrome . storage . sync . get ( [ sponsorTimeKey ] , function ( result ) {
let sponsorTimes = result [ sponsorTimeKey ] ;
2019-07-29 17:36:57 +02:00
2019-08-20 01:21:19 +02:00
if ( sponsorTimes != undefined && sponsorTimes . length > 0 ) {
let confirmMessage = "Are you sure you want to submit this?\n\n" + getSponsorTimesMessage ( sponsorTimes ) ;
confirmMessage += "\n\nTo edit or delete values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
if ( ! confirm ( confirmMessage ) ) return ;
2019-07-29 17:36:57 +02:00
2019-08-20 01:21:19 +02:00
sendSubmitMessage ( ) ;
}
} ) ;
2019-07-29 17:36:57 +02:00
}
//send the message to the background js
//called after all the checks have been made that it's okay to do so
function sendSubmitMessage ( ) {
2019-08-20 01:21:19 +02:00
//add loading animation
document . getElementById ( "submitButtonImage" ) . src = chrome . extension . getURL ( "icons/PlayerUploadIconSponsorBlocker256px.png" ) ;
document . getElementById ( "submitButton" ) . style . animation = "rotate 1s 0s infinite" ;
2019-08-20 21:27:30 +02:00
let currentVideoID = sponsorVideoID ;
2019-08-20 01:21:19 +02:00
chrome . runtime . sendMessage ( {
message : "submitTimes" ,
videoID : currentVideoID
} , function ( response ) {
if ( response != undefined ) {
if ( response . statusCode == 200 ) {
//hide loading message
let submitButton = document . getElementById ( "submitButton" ) ;
//finish this animation
submitButton . style . animation = "rotate 1s" ;
//when the animation is over, hide the button
let animationEndListener = function ( ) {
changeStartSponsorButton ( true , false ) ;
submitButton . style . animation = "none" ;
submitButton . removeEventListener ( "animationend" , animationEndListener ) ;
} ;
submitButton . addEventListener ( "animationend" , animationEndListener ) ;
//clear the sponsor times
let sponsorTimeKey = "sponsorTimes" + currentVideoID ;
chrome . storage . sync . set ( { [ sponsorTimeKey ] : [ ] } ) ;
//request the sponsors from the server again
sponsorsLookup ( currentVideoID ) ;
} else {
//show that the upload failed
document . getElementById ( "submitButton" ) . style . animation = "unset" ;
document . getElementById ( "submitButtonImage" ) . src = chrome . extension . getURL ( "icons/PlayerUploadFailedIconSponsorBlocker256px.png" ) ;
if ( [ 400 , 429 , 409 , 502 ] . includes ( response . statusCode ) ) {
alert ( chrome . i18n . getMessage ( response . statusCode ) ) ;
} else {
alert ( chrome . i18n . getMessage ( "connectionError" ) + response . statusCode ) ;
}
}
2019-07-30 03:09:10 +02:00
}
2019-08-20 01:21:19 +02:00
} ) ;
2019-07-22 00:19:56 +02:00
}
2019-07-29 17:36:57 +02:00
//get the message that visually displays the video times
function getSponsorTimesMessage ( sponsorTimes ) {
2019-08-20 01:21:19 +02:00
let sponsorTimesMessage = "" ;
for ( let i = 0 ; i < sponsorTimes . length ; i ++ ) {
for ( let s = 0 ; s < sponsorTimes [ i ] . length ; s ++ ) {
let timeMessage = getFormattedTime ( sponsorTimes [ i ] [ s ] ) ;
//if this is an end time
if ( s == 1 ) {
timeMessage = " to " + timeMessage ;
} else if ( i > 0 ) {
//add commas if necessary
timeMessage = ", " + timeMessage ;
}
sponsorTimesMessage += timeMessage ;
}
2019-07-29 17:36:57 +02:00
}
2019-08-20 01:21:19 +02:00
return sponsorTimesMessage ;
2019-07-29 17:36:57 +02:00
}
//converts time in seconds to minutes:seconds
function getFormattedTime ( seconds ) {
2019-08-20 01:21:19 +02:00
let minutes = Math . floor ( seconds / 60 ) ;
let secondsDisplay = Math . round ( seconds - minutes * 60 ) ;
if ( secondsDisplay < 10 ) {
//add a zero
secondsDisplay = "0" + secondsDisplay ;
}
2019-07-29 17:36:57 +02:00
2019-08-20 01:21:19 +02:00
let formatted = minutes + ":" + secondsDisplay ;
2019-07-29 17:36:57 +02:00
2019-08-20 01:21:19 +02:00
return formatted ;
2019-07-29 17:36:57 +02:00
}
2019-07-20 21:33:52 +02:00
function sendRequestToServer ( type , address , callback ) {
2019-08-20 01:21:19 +02:00
let xmlhttp = new XMLHttpRequest ( ) ;
2019-07-20 21:33:52 +02:00
2019-08-20 01:21:19 +02:00
xmlhttp . open ( type , serverAddress + address , true ) ;
2019-07-20 21:33:52 +02:00
2019-08-20 01:21:19 +02:00
if ( callback != undefined ) {
xmlhttp . onreadystatechange = function ( ) {
callback ( xmlhttp , false ) ;
} ;
2019-07-20 21:33:52 +02:00
2019-08-20 01:21:19 +02:00
xmlhttp . onerror = function ( ev ) {
callback ( xmlhttp , true ) ;
} ;
}
2019-07-20 21:33:52 +02:00
2019-08-20 01:21:19 +02:00
//submit this request
xmlhttp . send ( ) ;
2019-07-20 21:33:52 +02:00
}
2019-07-22 03:08:23 +02:00
function sendRequestToCustomServer ( type , fullAddress , callback ) {
2019-08-20 01:21:19 +02:00
let xmlhttp = new XMLHttpRequest ( ) ;
2019-07-22 03:08:23 +02:00
2019-08-20 01:21:19 +02:00
xmlhttp . open ( type , fullAddress , true ) ;
2019-07-22 03:08:23 +02:00
2019-08-20 01:21:19 +02:00
if ( callback != undefined ) {
xmlhttp . onreadystatechange = function ( ) {
callback ( xmlhttp , false ) ;
} ;
2019-07-22 03:08:23 +02:00
2019-08-20 01:21:19 +02:00
xmlhttp . onerror = function ( ev ) {
callback ( xmlhttp , true ) ;
} ;
}
2019-07-22 03:08:23 +02:00
2019-08-20 01:21:19 +02:00
//submit this request
xmlhttp . send ( ) ;
2019-07-22 03:08:23 +02:00
}