Merge pull request #119 from ajayyy/experimental-ajay

Notice countdown counter, reskip, formatting fixes + sponsor check fixes
This commit is contained in:
Ajay Ramachandran 2019-08-19 20:19:48 -04:00 committed by GitHub
commit f4c7e11ae1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 2694 additions and 2578 deletions

View file

@ -1,121 +1,127 @@
{
"Name": {
"message": "SponsorBlock",
"description": "Name of the extension."
},
"fullName": {
"message": "SponsorBlock for YouTube - Skip Sponsorships",
"description": "Name of the extension."
},
"Name": {
"message": "SponsorBlock",
"description": "Name of the extension."
},
"fullName": {
"message": "SponsorBlock for YouTube - Skip Sponsorships",
"description": "Name of the extension."
},
"Description": {
"message": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
"description": "Description of the extension."
},
"helpPage": {
"message": "index_en.html"
},
"400": {
"message": "Server said this request was invalid"
},
"429": {
"message": "You have submitted too many sponsor times for this one video, are you sure there are this many?"
},
"409": {
"message": "This has already been submitted before"
},
"502": {
"message": "It seems the server is down. Contact the dev to inform them."
},
"channelWhitelisted": {
"message": "Channel Whitelisted!"
},
"Sponsor": {
"message": "Sponsor"
},
"Sponsors": {
"message": "Sponsors"
},
"Description": {
"message": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
"description": "Description of the extension."
},
"helpPage": {
"message": "index_en.html"
},
"400": {
"message": "Server said this request was invalid"
},
"429": {
"message": "You have submitted too many sponsor times for this one video, are you sure there are this many?"
},
"409": {
"message": "This has already been submitted before"
},
"502": {
"message": "It seems the server is down. Contact the dev to inform them."
},
"channelWhitelisted": {
"message": "Channel Whitelisted!"
},
"Sponsor": {
"message": "Sponsor"
},
"Sponsors": {
"message": "Sponsors"
},
"Segment": {
"message": "sponsor segment"
},
"Segments": {
"message": "sponsor segments"
},
"noticeTitle": {
"message": "Sponsor Skipped"
},
"noticeClosingMessage": {
"message": "closes in 7s"
},
"reportButtonTitle": {
"message": "Report"
},
"reportButtonInfo": {
"message": "Report this sponsor submission as incorrect."
},
"Dismiss": {
"message": "Dismiss"
},
"Loading": {
"message": "Loading..."
},
"Mins": {
"message": "Minutes"
},
"Secs": {
"message": "Seconds"
},
"Hide": {
"message": "Never Show"
},
"hitGoBack": {
"message": "Hit unskip to get to where you came from."
},
"goBack": {
"message": "Unskip"
},
"confirmMSG": {
"message": "\n\nTo edit or delete individual values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
},
"clearThis": {
"message": "Are you sure you want to clear this?\n\n"
},
"Unknown": {
"message": "There was an error submitting your sponsor times, please try again later."
},
"message": "sponsor segment"
},
"Segments": {
"message": "sponsor segments"
},
"noticeTitle": {
"message": "Sponsor Skipped"
},
"reportButtonTitle": {
"message": "Report"
},
"reportButtonInfo": {
"message": "Report this sponsor submission as incorrect."
},
"Dismiss": {
"message": "Dismiss"
},
"Loading": {
"message": "Loading..."
},
"Mins": {
"message": "Minutes"
},
"Secs": {
"message": "Seconds"
},
"Hide": {
"message": "Never Show"
},
"hitGoBack": {
"message": "Hit unskip to get to where you came from."
},
"unskip": {
"message": "Unskip"
},
"reskip": {
"message": "Reskip"
},
"paused": {
"message": "Paused"
},
"confirmMSG": {
"message": "\n\nTo edit or delete individual values, click the info button or open the extension popup by clicking the extension icon in the top right corner."
},
"clearThis": {
"message": "Are you sure you want to clear this?\n\n"
},
"Unknown": {
"message": "There was an error submitting your sponsor times, please try again later."
},
"sponsorFound": {
"message": "This video's sponsors are in the database!"
},
"sponsor404": {
"message": "No sponsors found"
},
"sponsorStart": {
"message": "Sponsorship Starts Now"
},
"sponsorEnd": {
"message": "Sponsorship Ends Now"
},
"noVideoID": {
"message": "This probably isn't a YouTube tab, or you clicked too early. \n If you know this is a YouTube tab,\n close this popup and open it again."
},
"Voted": {
"message": "Voted!"
},
"voteFail": {
"message": "You have already voted this way before."
},
"serverDown": {
"message": "It seems the sever is down. Contact the dev immediately."
},
"connectionError": {
"message": "A connection error has occured. Error code: "
},
"wantToSubmit": {
"message": "Do you want to submit the sponsor times for video id"
},
"leftTimes": {
"message": "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted)."
}
"sponsorFound": {
"message": "This video's sponsors are in the database!"
},
"sponsor404": {
"message": "No sponsors found"
},
"sponsorStart": {
"message": "Sponsorship Starts Now"
},
"sponsorEnd": {
"message": "Sponsorship Ends Now"
},
"noVideoID": {
"message": "This probably isn't a YouTube tab, or you clicked too early. \n If you know this is a YouTube tab,\n close this popup and open it again."
},
"success": {
"message": "Success!"
},
"voted": {
"message": "Voted!"
},
"voteFail": {
"message": "You have already voted this way before."
},
"serverDown": {
"message": "It seems the sever is down. Contact the dev immediately."
},
"connectionError": {
"message": "A connection error has occured. Error code: "
},
"wantToSubmit": {
"message": "Do you want to submit the sponsor times for video id"
},
"leftTimes": {
"message": "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted)."
}
}

View file

@ -1,221 +1,221 @@
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
chrome.tabs.sendMessage(tabId, {
message: 'update',
message: 'update',
});
});
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
switch(request.message) {
case "submitTimes":
case "submitTimes":
submitTimes(request.videoID, callback);
//this allows the callback to be called later by the submitTimes function
return true;
case "addSponsorTime":
case "addSponsorTime":
addSponsorTime(request.time, request.videoID, callback);
//this allows the callback to be called later
return true;
case "getSponsorTimes":
case "getSponsorTimes":
getSponsorTimes(request.videoID, function(sponsorTimes) {
callback({
callback({
sponsorTimes: sponsorTimes
})
})
});
//this allows the callback to be called later
return true;
case "submitVote":
case "submitVote":
submitVote(request.type, request.UUID, callback);
//this allows the callback to be called later
return true;
case "alertPrevious":
case "alertPrevious":
chrome.notifications.create("stillThere" + Math.random(), {
type: "basic",
title: "Do you want to submit the sponsor times for video id " + request.previousVideoID + "?",
message: "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted).",
iconUrl: "./icons/LogoSponsorBlocker256px.png"
type: "basic",
title: "Do you want to submit the sponsor times for video id " + request.previousVideoID + "?",
message: "You seem to have left some sponsor times unsubmitted. Go back to that page to submit them (they are not deleted).",
iconUrl: "./icons/LogoSponsorBlocker256px.png"
});
}
});
//add help page on install
chrome.runtime.onInstalled.addListener(function (object) {
// TODO (shownInstallPage): remove shownInstallPage logic after sufficient amount of time,
// so that people have time to upgrade and move to shownInstallPage-free code.
chrome.storage.sync.get(["userID", "shownInstallPage"], function(result) {
const userID = result.userID;
// TODO (shownInstallPage): delete row below
const shownInstallPage = result.shownInstallPage;
// TODO (shownInstallPage): remove shownInstallPage logic after sufficient amount of time,
// so that people have time to upgrade and move to shownInstallPage-free code.
chrome.storage.sync.get(["userID", "shownInstallPage"], function(result) {
const userID = result.userID;
// TODO (shownInstallPage): delete row below
const shownInstallPage = result.shownInstallPage;
// If there is no userID, then it is the first install.
if (!userID){
// Show install page, if there is no user id
// and there is no shownInstallPage.
// TODO (shownInstallPage): remove this if statement, but leave contents
if (!shownInstallPage){
//open up the install page
chrome.tabs.create({url: chrome.extension.getURL("/help/"+chrome.i18n.getMessage("helpPage"))});
}
// If there is no userID, then it is the first install.
if (!userID){
// Show install page, if there is no user id
// and there is no shownInstallPage.
// TODO (shownInstallPage): remove this if statement, but leave contents
if (!shownInstallPage){
//open up the install page
chrome.tabs.create({url: chrome.extension.getURL("/help/"+chrome.i18n.getMessage("helpPage"))});
}
// TODO (shownInstallPage): delete if statement and contents
// If shownInstallPage is set, remove it.
if (!!shownInstallPage){
chrome.storage.sync.remove("shownInstallPage");
}
// TODO (shownInstallPage): delete if statement and contents
// If shownInstallPage is set, remove it.
if (!!shownInstallPage){
chrome.storage.sync.remove("shownInstallPage");
}
//generate a userID
const newUserID = generateUUID();
//save this UUID
chrome.storage.sync.set({
"userID": newUserID,
//the last video id loaded, to make sure it is a video id change
"sponsorVideoID": null,
"previousVideoID": null
});
}
});
//generate a userID
const newUserID = generateUUID();
//save this UUID
chrome.storage.sync.set({
"userID": newUserID,
//the last video id loaded, to make sure it is a video id change
"sponsorVideoID": null,
"previousVideoID": null
});
}
});
});
//gets the sponsor times from memory
function getSponsorTimes(videoID, callback) {
let sponsorTimes = [];
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimesStorage = result[sponsorTimeKey];
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
sponsorTimes = sponsorTimesStorage;
}
let sponsorTimes = [];
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.get([sponsorTimeKey], function(result) {
let sponsorTimesStorage = result[sponsorTimeKey];
if (sponsorTimesStorage != undefined && sponsorTimesStorage.length > 0) {
sponsorTimes = sponsorTimesStorage;
}
callback(sponsorTimes)
});
callback(sponsorTimes)
});
}
function addSponsorTime(time, videoID, callback) {
getSponsorTimes(videoID, function(sponsorTimes) {
//add to sponsorTimes
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
//it is an end time
sponsorTimes[sponsorTimes.length - 1][1] = time;
} else {
//it is a start time
let sponsorTimesIndex = sponsorTimes.length;
sponsorTimes[sponsorTimesIndex] = [];
getSponsorTimes(videoID, function(sponsorTimes) {
//add to sponsorTimes
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
//it is an end time
sponsorTimes[sponsorTimes.length - 1][1] = time;
} else {
//it is a start time
let sponsorTimesIndex = sponsorTimes.length;
sponsorTimes[sponsorTimesIndex] = [];
sponsorTimes[sponsorTimesIndex][0] = time;
}
sponsorTimes[sponsorTimesIndex][0] = time;
}
//save this info
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, callback);
});
//save this info
let sponsorTimeKey = "sponsorTimes" + videoID;
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, callback);
});
}
function submitVote(type, UUID, callback) {
chrome.storage.sync.get(["userID"], function(result) {
let userID = result.userID;
chrome.storage.sync.get(["userID"], function(result) {
let userID = result.userID;
//publish this vote
sendRequestToServer("GET", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
callback({
successType: 1
});
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
//duplicate vote
callback({
successType: 0,
statusCode: xmlhttp.status
});
} else if (error) {
//error while connect
callback({
successType: -1,
statusCode: xmlhttp.status
});
}
//publish this vote
sendRequestToServer("GET", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
callback({
successType: 1
});
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 405) {
//duplicate vote
callback({
successType: 0,
statusCode: xmlhttp.status
});
} else if (error) {
//error while connect
callback({
successType: -1,
statusCode: xmlhttp.status
});
}
})
})
})
}
function submitTimes(videoID, callback) {
//get the video times from storage
let sponsorTimeKey = 'sponsorTimes' + videoID;
chrome.storage.sync.get([sponsorTimeKey, "userID"], function(result) {
let sponsorTimes = result[sponsorTimeKey];
let userID = result.userID;
//get the video times from storage
let sponsorTimeKey = 'sponsorTimes' + videoID;
chrome.storage.sync.get([sponsorTimeKey, "userID"], function(result) {
let sponsorTimes = result[sponsorTimeKey];
let userID = result.userID;
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//submit these times
for (let i = 0; i < sponsorTimes.length; i++) {
//submit the sponsorTime
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
+ "&userID=" + userID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && !error) {
callback({
statusCode: xmlhttp.status
});
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//submit these times
for (let i = 0; i < sponsorTimes.length; i++) {
//submit the sponsorTime
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
+ "&userID=" + userID, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && !error) {
callback({
statusCode: xmlhttp.status
});
if (xmlhttp.status == 200) {
//add these to the storage log
chrome.storage.sync.get(["sponsorTimesContributed"], function(result) {
let currentContributionAmount = 0;
if (result.sponsorTimesContributed != undefined) {
//current contribution amount is known
currentContributionAmount = result.sponsorTimesContributed;
}
if (xmlhttp.status == 200) {
//add these to the storage log
chrome.storage.sync.get(["sponsorTimesContributed"], function(result) {
let currentContributionAmount = 0;
if (result.sponsorTimesContributed != undefined) {
//current contribution amount is known
currentContributionAmount = result.sponsorTimesContributed;
}
//save the amount contributed
chrome.storage.sync.set({"sponsorTimesContributed": currentContributionAmount + sponsorTimes.length});
//save the amount contributed
chrome.storage.sync.set({"sponsorTimesContributed": currentContributionAmount + sponsorTimes.length});
});
}
} else if (error) {
callback({
statusCode: -1
});
}
});
}
} else if (error) {
callback({
statusCode: -1
});
}
});
}
}
});
}
});
}
function sendRequestToServer(type, address, callback) {
let xmlhttp = new XMLHttpRequest();
let xmlhttp = new XMLHttpRequest();
xmlhttp.open(type, serverAddress + address, true);
xmlhttp.open(type, serverAddress + address, true);
if (callback != undefined) {
xmlhttp.onreadystatechange = function () {
callback(xmlhttp, false);
};
if (callback != undefined) {
xmlhttp.onreadystatechange = function () {
callback(xmlhttp, false);
};
xmlhttp.onerror = function(ev) {
callback(xmlhttp, true);
};
}
xmlhttp.onerror = function(ev) {
callback(xmlhttp, true);
};
}
//submit this request
xmlhttp.send();
//submit this request
xmlhttp.send();
}
function generateUUID(length = 36) {
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
let isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
if (window.crypto && window.crypto.getRandomValues) {
values = new Uint32Array(length);
window.crypto.getRandomValues(values);
for (i = 0; i < length; i++) {
result += charset[values[i] % charset.length];
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
let result = "";
let isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]';
if (window.crypto && window.crypto.getRandomValues) {
values = new Uint32Array(length);
window.crypto.getRandomValues(values);
for (i = 0; i < length; i++) {
result += charset[values[i] % charset.length];
}
return result;
} else {
for (let i = 0; i < length; i++) {
result += charset[Math.floor(Math.random() * charset.length)];
}
return result;
}
return result;
} else {
for (let i = 0; i < length; i++) {
result += charset[Math.floor(Math.random() * charset.length)];
}
return result;
}
}

View file

@ -58,6 +58,11 @@
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.sponsorBlockSpacer {
background-color: rgb(100, 100, 100);
border-color: rgb(100, 100, 100);
@ -82,6 +87,10 @@
padding-right: 5px;
}
.sponsorSkipNoticeFadeOut {
animation: fadeOut 3s cubic-bezier(0.55, 0.055, 0.675, 0.19);
}
.sponsorSkipNoticeTimeLeft {
color: #eeeeee;
@ -105,11 +114,6 @@
border-left: 1px solid rgb(150, 150, 150);
}
.sponsorSkipNoticeCloseButton {
height: 10px;
width: 10px;
}
.sponsorSkipNoticeButton {
background: none;
color: rgb(235, 235, 235);
@ -119,6 +123,23 @@
cursor: pointer;
margin-right: 10px;
padding: 2px 5px;
}
.sponsorSkipNoticeButton:hover {
background-color: rgba(235, 235, 235,0.2);
border-radius: 4px;
transition: background-color 0.4s;
}
.sponsorTimesVoteButtonsContainer {
float: left;
padding: 2px 5px;
margin-right: 4px;
}
.sponsorSkipNoticeRightSection {
@ -131,8 +152,17 @@
}
.sponsorSkipNoticeRightButton {
margin-left: 7px;
padding: 0px;
margin-right: 0;
}
.sponsorSkipNoticeCloseButton {
height: 10px;
width: 10px;
padding: 2px 5px;
margin-left: 2px;
float: right;
}
.sponsorSkipMessage {

1716
content.js

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,8 @@
{
"browser_specific_settings": {
"gecko": {
"id": "sponsorBlocker@ajay.app",
"strict_min_version": "57.0"
}
}
}

View file

@ -1,68 +0,0 @@
{
"name": "SponsorBlock - YouTube Sponsorship Blocker",
"short_name": "SponsorBlock",
"version": "1.0.12",
"description": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
"content_scripts": [
{
"matches": [
"https://*.youtube.com/*"
],
"js": [
"config.js",
"content.js",
"popup.js"
],
"css": [
"content.css",
"./libs/Source+Sans+Pro.css",
"popup.css"
]
}
],
"web_accessible_resources": [
"icons/LogoSponsorBlocker256px.png",
"icons/IconSponsorBlocker256px.png",
"icons/PlayerStartIconSponsorBlocker256px.png",
"icons/PlayerStopIconSponsorBlocker256px.png",
"icons/PlayerUploadIconSponsorBlocker256px.png",
"icons/PlayerUploadFailedIconSponsorBlocker256px.png",
"icons/upvote.png",
"icons/downvote.png",
"icons/PlayerInfoIconSponsorBlocker256px.png",
"icons/PlayerDeleteIconSponsorBlocker256px.png",
"popup.html",
"help/index.html",
"help/style.css"
],
"permissions": [
"tabs",
"storage",
"notifications",
"https://sponsor.ajay.app/*"
],
"browser_action": {
"default_title": "SponsorBlock",
"default_popup": "popup.html"
},
"background": {
"scripts":[
"config.js",
"background.js"
]
},
"icons": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/LogoSponsorBlocker64px.png",
"128": "icons/LogoSponsorBlocker128px.png",
"256": "icons/LogoSponsorBlocker256px.png"
},
"browser_specific_settings": {
"gecko": {
"id": "sponsorBlocker@ajay.app",
"strict_min_version": "57.0"
}
},
"manifest_version": 2
}

View file

@ -1,7 +1,7 @@
{
"name": "__MSG_fullName__",
"short_name": "__MSG_Name__",
"version": "1.0.38",
"version": "1.0.39",
"default_locale": "en",
"description": "__MSG_Description__",
"content_scripts": [
@ -13,6 +13,7 @@
"js": [
"config.js",
"utils/previewBar.js",
"utils/skipNotice.js",
"utils.js",
"content.js",
"popup.js"

View file

@ -10,8 +10,8 @@ h1.popupElement {
margin-block-start: 0.67em;
margin-block-end: 0.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
font-weight: bold;
margin-inline-end: 0px;
font-weight: bold;
}
h2.popupElement {
@ -36,9 +36,9 @@ sub.popupElement {
/* end reset */
.popupElement {
font-family: 'Source Sans Pro', sans-serif;
font-family: 'Source Sans Pro', sans-serif;
color: black;
color: black;
}
h1.popupElement {
@ -109,43 +109,43 @@ h1.popupElement {
padding:8px 37px;
text-decoration:none;
text-shadow:0px 0px 0px #27663c;
}
.whitelistButton:hover.popupElement {
background-color:#218b26;
}
.whitelistButton:focus.popupElement {
outline: none;
background-color:#218b26;
}
.whitelistButton:active.popupElement {
position:relative;
top:1px;
}
}
.whitelistButton:hover.popupElement {
background-color:#218b26;
}
.whitelistButton:focus.popupElement {
outline: none;
background-color:#218b26;
}
.whitelistButton:active.popupElement {
position:relative;
top:1px;
}
.greenButton.popupElement {
background-color:#ec1c1c;
-moz-border-radius:28px;
-webkit-border-radius:28px;
border-radius:28px;
border:1px solid #d31919;
display:inline-block;
cursor:pointer;
color:#ffffff;
font-size:16px;
padding:8px 37px;
text-decoration:none;
text-shadow:0px 0px 0px #662727;
background-color:#ec1c1c;
-moz-border-radius:28px;
-webkit-border-radius:28px;
border-radius:28px;
border:1px solid #d31919;
display:inline-block;
cursor:pointer;
color:#ffffff;
font-size:16px;
padding:8px 37px;
text-decoration:none;
text-shadow:0px 0px 0px #662727;
}
.greenButton:hover.popupElement {
background-color:#bf2a2a;
background-color:#bf2a2a;
}
.greenButton:focus.popupElement {
outline: none;
background-color:#bf2a2a;
}
.greenButton:active.popupElement {
position:relative;
top:1px;
position:relative;
top:1px;
}
.dangerButton.popupElement {

2459
popup.js

File diff suppressed because it is too large Load diff

364
utils/skipNotice.js Normal file
View file

@ -0,0 +1,364 @@
'use strict';
//The notice that tells the user that a sponsor was just skipped
class SkipNotice {
constructor(parent, UUID) {
this.parent = parent;
this.UUID = UUID;
this.maxCountdownTime = () => 4;
//the countdown until this notice closes
this.countdownTime = this.maxCountdownTime();
//the id for the setInterval running the countdown
this.countdownInterval = -1;
//the unskip button's callback
this.unskipCallback = this.unskip.bind(this);
//add notice
let amountOfPreviousNotices = document.getElementsByClassName("sponsorSkipNotice").length;
//this is the suffix added at the end of every id
this.idSuffix = this.UUID + amountOfPreviousNotices;
if (amountOfPreviousNotices > 0) {
//already exists
let previousNotice = document.getElementsByClassName("sponsorSkipNotice")[0];
previousNotice.classList.add("secondSkipNotice")
}
let noticeElement = document.createElement("div");
//what sponsor time this is about
noticeElement.id = "sponsorSkipNotice" + this.idSuffix;
noticeElement.classList.add("sponsorSkipObject");
noticeElement.classList.add("sponsorSkipNotice");
noticeElement.style.zIndex = 50 + amountOfPreviousNotices;
//add mouse enter and leave listeners
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
noticeElement.addEventListener("mouseleave", this.startCountdown.bind(this));
//the row that will contain the info
let firstRow = document.createElement("tr");
firstRow.id = "sponsorSkipNoticeFirstRow" + this.idSuffix;
let logoColumn = document.createElement("td");
let logoElement = document.createElement("img");
logoElement.id = "sponsorSkipLogo" + this.idSuffix;
logoElement.className = "sponsorSkipLogo sponsorSkipObject";
logoElement.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png");
let noticeMessage = document.createElement("span");
noticeMessage.id = "sponsorSkipMessage" + this.idSuffix;
noticeMessage.classList.add("sponsorSkipMessage");
noticeMessage.classList.add("sponsorSkipObject");
noticeMessage.innerText = chrome.i18n.getMessage("noticeTitle");
//create the first column
logoColumn.appendChild(logoElement);
logoColumn.appendChild(noticeMessage);
//add the x button
let closeButtonContainer = document.createElement("td");
closeButtonContainer.className = "sponsorSkipNoticeRightSection";
closeButtonContainer.style.top = "11px";
let timeLeft = document.createElement("span");
timeLeft.id = "sponsorSkipNoticeTimeLeft" + this.idSuffix;
timeLeft.innerText = this.countdownTime + "s";
timeLeft.className = "sponsorSkipObject sponsorSkipNoticeTimeLeft";
let hideButton = document.createElement("img");
hideButton.src = chrome.extension.getURL("icons/close.png");
hideButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeCloseButton sponsorSkipNoticeRightButton";
hideButton.addEventListener("click", this.close.bind(this));
closeButtonContainer.appendChild(timeLeft);
closeButtonContainer.appendChild(hideButton);
//add all objects to first row
firstRow.appendChild(logoColumn);
firstRow.appendChild(closeButtonContainer);
let spacer = document.createElement("hr");
spacer.id = "sponsorSkipNoticeSpacer" + this.idSuffix;
spacer.className = "sponsorBlockSpacer";
//the row that will contain the buttons
let secondRow = document.createElement("tr");
secondRow.id = "sponsorSkipNoticeSecondRow" + this.idSuffix;
//thumbs up and down buttons
let voteButtonsContainer = document.createElement("td");
voteButtonsContainer.id = "sponsorTimesVoteButtonsContainer" + this.idSuffix;
voteButtonsContainer.className = "sponsorTimesVoteButtonsContainer"
let reportText = document.createElement("span");
reportText.id = "sponsorTimesReportText" + this.idSuffix;
reportText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
reportText.innerText = chrome.i18n.getMessage("reportButtonTitle");
reportText.style.marginRight = "5px";
reportText.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
let downvoteButton = document.createElement("img");
downvoteButton.id = "sponsorTimesDownvoteButtonsContainer" + this.idSuffix;
downvoteButton.className = "sponsorSkipObject voteButton";
downvoteButton.src = chrome.extension.getURL("icons/report.png");
downvoteButton.addEventListener("click", () => vote(0, this.UUID, this));
downvoteButton.setAttribute("title", chrome.i18n.getMessage("reportButtonInfo"));
//add downvote and report text to container
voteButtonsContainer.appendChild(reportText);
voteButtonsContainer.appendChild(downvoteButton);
//add unskip button
let unskipContainer = document.createElement("td");
unskipContainer.className = "sponsorSkipNoticeUnskipSection";
let unskipButton = document.createElement("button");
unskipButton.id = "sponsorSkipUnskipButton" + this.idSuffix;
unskipButton.innerText = chrome.i18n.getMessage("unskip");
unskipButton.className = "sponsorSkipObject sponsorSkipNoticeButton";
unskipButton.addEventListener("click", this.unskipCallback);
unskipButton.style.marginLeft = "4px";
unskipContainer.appendChild(unskipButton);
//add don't show again button
let dontshowContainer = document.createElement("td");
dontshowContainer.className = "sponsorSkipNoticeRightSection";
let dontShowAgainButton = document.createElement("button");
dontShowAgainButton.innerText = chrome.i18n.getMessage("Hide");
dontShowAgainButton.className = "sponsorSkipObject sponsorSkipNoticeButton sponsorSkipNoticeRightButton";
dontShowAgainButton.addEventListener("click", dontShowNoticeAgain);
dontshowContainer.appendChild(dontShowAgainButton);
//add to row
secondRow.appendChild(voteButtonsContainer);
secondRow.appendChild(unskipContainer);
secondRow.appendChild(dontshowContainer);
noticeElement.appendChild(firstRow);
noticeElement.appendChild(spacer);
noticeElement.appendChild(secondRow);
//get reference node
let referenceNode = document.getElementById("movie_player");
if (referenceNode == null) {
//for embeds
let player = document.getElementById("player");
referenceNode = player.firstChild;
let index = 1;
//find the child that is the video player (sometimes it is not the first)
while (!referenceNode.classList.contains("html5-video-player") || !referenceNode.classList.contains("ytp-embed")) {
referenceNode = player.children[index];
index++;
}
}
referenceNode.prepend(noticeElement);
this.startCountdown();
}
//called every second to lower the countdown before hiding the notice
countdown() {
this.countdownTime--;
if (this.countdownTime <= 0) {
//remove this from setInterval
clearInterval(this.countdownInterval);
//time to close this notice
this.close();
return;
}
if (this.countdownTime == 3) {
//start fade out animation
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
notice.style.removeProperty("animation");
notice.classList.add("sponsorSkipNoticeFadeOut");
}
this.updateTimerDisplay();
}
pauseCountdown() {
//remove setInterval
clearInterval(this.countdownInterval);
this.countdownInterval = -1;
//reset countdown
this.countdownTime = this.maxCountdownTime();
//inform the user
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
timeLeft.innerText = chrome.i18n.getMessage("paused");
//remove the fade out class if it exists
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
notice.classList.remove("sponsorSkipNoticeFadeOut");
notice.style.animation = "none";
}
startCountdown() {
//if it has already started, don't start it again
if (this.countdownInterval != -1) return;
this.countdownInterval = setInterval(this.countdown.bind(this), 1000);
this.updateTimerDisplay();
}
updateTimerDisplay() {
//update the timer display
let timeLeft = document.getElementById("sponsorSkipNoticeTimeLeft" + this.idSuffix);
timeLeft.innerText = this.countdownTime + "s";
}
unskip() {
unskipSponsorTime(this.UUID);
//change unskip button to a reskip button
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
unskipButton.innerText = chrome.i18n.getMessage("reskip");
unskipButton.removeEventListener("click", this.unskipCallback);
//setup new callback
this.unskipCallback = this.reskip.bind(this);
unskipButton.addEventListener("click", this.unskipCallback);
//change max duration to however much of the sponsor is left
this.maxCountdownTime = function() {
let sponsorTime = sponsorTimes[UUIDs.indexOf(this.UUID)];
let duration = Math.round(sponsorTime[1] - v.currentTime);
return Math.max(duration, 4);
};
this.countdownTime = this.maxCountdownTime();
this.updateTimerDisplay();
}
reskip() {
reskipSponsorTime(this.UUID);
//change unskip button to a reskip button
let unskipButton = document.getElementById("sponsorSkipUnskipButton" + this.idSuffix);
unskipButton.innerText = chrome.i18n.getMessage("unskip");
unskipButton.removeEventListener("click", this.unskipCallback);
//setup new callback
this.unskipCallback = this.unskip.bind(this);
unskipButton.addEventListener("click", this.unskipCallback);
//reset duration
this.maxCountdownTime = () => 4;
this.countdownTime = this.maxCountdownTime();
this.updateTimerDisplay();
}
afterDownvote() {
this.addVoteButtonInfo(chrome.i18n.getMessage("voted"));
this.addNoticeInfoMessage(chrome.i18n.getMessage("hitGoBack"));
//remove this sponsor from the sponsors looked up
//find which one it is
for (let i = 0; i < sponsorTimes.length; i++) {
if (UUIDs[i] == this.UUID) {
//this one is the one to hide
//add this as a hidden sponsorTime
hiddenSponsorTimes.push(i);
let sponsorTimesLeft = sponsorTimes.slice();
for (let j = 0; j < hiddenSponsorTimes.length; j++) {
//remove this sponsor time
sponsorTimesLeft.splice(hiddenSponsorTimes[j], 1);
}
//update the preview
previewBar.set(sponsorTimesLeft, [], v.duration);
break;
}
}
}
addNoticeInfoMessage(message) {
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
if (previousInfoMessage != null) {
//remove it
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
}
//add info
let thanksForVotingText = document.createElement("p");
thanksForVotingText.id = "sponsorTimesInfoMessage" + this.idSuffix;
thanksForVotingText.className = "sponsorTimesInfoMessage";
thanksForVotingText.innerText = message;
//add element to div
document.getElementById("sponsorSkipNotice" + this.idSuffix).insertBefore(thanksForVotingText, document.getElementById("sponsorSkipNoticeSpacer" + this.idSuffix));
}
resetNoticeInfoMessage() {
let previousInfoMessage = document.getElementById("sponsorTimesInfoMessage" + this.idSuffix);
if (previousInfoMessage != null) {
//remove it
document.getElementById("sponsorSkipNotice" + this.idSuffix).removeChild(previousInfoMessage);
}
}
addVoteButtonInfo(message) {
this.resetVoteButtonInfo();
//hide report button and text for it
let downvoteButton = document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix);
if (downvoteButton != null) {
downvoteButton.style.display = "none";
}
let downvoteButtonText = document.getElementById("sponsorTimesReportText" + this.idSuffix);
if (downvoteButtonText != null) {
downvoteButtonText.style.display = "none";
}
//add info
let thanksForVotingText = document.createElement("td");
thanksForVotingText.id = "sponsorTimesVoteButtonInfoMessage" + this.idSuffix;
thanksForVotingText.className = "sponsorTimesInfoMessage sponsorTimesVoteButtonMessage";
thanksForVotingText.innerText = message;
//add element to div
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).prepend(thanksForVotingText);
}
resetVoteButtonInfo() {
let previousInfoMessage = document.getElementById("sponsorTimesVoteButtonInfoMessage" + this.idSuffix);
if (previousInfoMessage != null) {
//remove it
document.getElementById("sponsorSkipNoticeSecondRow" + this.idSuffix).removeChild(previousInfoMessage);
}
//show button again
document.getElementById("sponsorTimesDownvoteButtonsContainer" + this.idSuffix).style.removeProperty("display");
}
//close this notice
close() {
let notice = document.getElementById("sponsorSkipNotice" + this.idSuffix);
if (notice != null) {
notice.remove();
}
}
}