mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-07 20:17:05 +03:00
Compare commits
111 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
137ba895bb | ||
|
|
ecc48de396 | ||
|
|
aa95687b56 | ||
|
|
a8147738ef | ||
|
|
4a3d36b952 | ||
|
|
f9bd82db35 | ||
|
|
c8438b9d59 | ||
|
|
5347340c1c | ||
|
|
524e443f4d | ||
|
|
b9091c3a97 | ||
|
|
5445146b56 | ||
|
|
13d0e4a33a | ||
|
|
8f0a9d97f6 | ||
|
|
5feed6bfcc | ||
|
|
5916baf5ea | ||
|
|
1c3a857fcf | ||
|
|
640ad58c65 | ||
|
|
41aa58e004 | ||
|
|
6b3eb09198 | ||
|
|
44c4671977 | ||
|
|
ac118173a5 | ||
|
|
3f815a18c4 | ||
|
|
e281b90699 | ||
|
|
012a36b931 | ||
|
|
43e3d03e9a | ||
|
|
5adeeed634 | ||
|
|
29a8608f9d | ||
|
|
67c4acbc5e | ||
|
|
a5d605f539 | ||
|
|
66b6985c5e | ||
|
|
0025785a78 | ||
|
|
ba284aec2f | ||
|
|
5ffe207a86 | ||
|
|
3a4d867ae3 | ||
|
|
7a2c57aae9 | ||
|
|
05faa7e138 | ||
|
|
455189d916 | ||
|
|
1c05de3098 | ||
|
|
577baa508b | ||
|
|
aebb4313bc | ||
|
|
d42377a5cd | ||
|
|
f254a99d6f | ||
|
|
19a1a5efda | ||
|
|
28322f19b5 | ||
|
|
c7d03aa423 | ||
|
|
60242df3c9 | ||
|
|
1aab52edbe | ||
|
|
2580577ce0 | ||
|
|
1ab33375ec | ||
|
|
e1f5046ace | ||
|
|
699ca91a94 | ||
|
|
30c12e3983 | ||
|
|
15d6a48359 | ||
|
|
b700d4eec0 | ||
|
|
5be8ecb32b | ||
|
|
ccafbf663c | ||
|
|
3f7e9e22ec | ||
|
|
e5d9c75392 | ||
|
|
b28087f723 | ||
|
|
866cc33f0e | ||
|
|
02448307ab | ||
|
|
b34b3f5651 | ||
|
|
7c787b77e8 | ||
|
|
1b5d5f8a3a | ||
|
|
6707d6df8d | ||
|
|
0c669d6b83 | ||
|
|
883871123a | ||
|
|
301e16b8f1 | ||
|
|
df1bc9d7a6 | ||
|
|
e1f1814748 | ||
|
|
074f7c5456 | ||
|
|
2a64afe9dc | ||
|
|
4c12bb9c2f | ||
|
|
22e7c6a40d | ||
|
|
a9ea22f505 | ||
|
|
2067b1c787 | ||
|
|
410f5fc138 | ||
|
|
077efd2de3 | ||
|
|
62632792cc | ||
|
|
7e2925a1e3 | ||
|
|
b964d93ea9 | ||
|
|
baba619fe7 | ||
|
|
dce036b0e6 | ||
|
|
c6c8d7de49 | ||
|
|
02e11503cb | ||
|
|
2b5402fa57 | ||
|
|
7ad5e426fb | ||
|
|
bbbb4f4877 | ||
|
|
9a32710ef8 | ||
|
|
d25792f39a | ||
|
|
5ee279dec7 | ||
|
|
e6fa832cb8 | ||
|
|
64befaebfc | ||
|
|
5425c54fca | ||
|
|
aae0998426 | ||
|
|
f6c9e8e235 | ||
|
|
18909ffef6 | ||
|
|
3a037818a8 | ||
|
|
101d94f46e | ||
|
|
38bb50a472 | ||
|
|
3b3653af67 | ||
|
|
6be7408d80 | ||
|
|
6d67559627 | ||
|
|
db46d0438f | ||
|
|
a5580daebd | ||
|
|
809be3b2fb | ||
|
|
0319c507d3 | ||
|
|
8ffab867e1 | ||
|
|
fcf7141733 | ||
|
|
1c1fb6006c | ||
|
|
6cb07b5be3 |
10
README.md
10
README.md
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
# SponsorBlock
|
# SponsorBlock
|
||||||
|
|
||||||
SponsorBlock is an extension that will skip over sponsored segments of YouTube videos. SponsorBlock is a crowdsourced browser extension that let's anyone submit the start and end time's of sponsored segments of YouTube videos. Once one person submits this information, everyone else with this extension will skip right over the sponsored segment.
|
SponsorBlock is an extension that will skip over sponsored segments of YouTube videos. SponsorBlock is a crowdsourced browser extension that lets anyone submit the start and end times of sponsored segments of YouTube videos. Once one person submits this information, everyone else with this extension will skip right over the sponsored segment.
|
||||||
|
|
||||||
# Available for Chrome and Firefox
|
# Available for Chrome and Firefox
|
||||||
|
|
||||||
@@ -21,9 +21,13 @@ To make sure that this project doesn't die, I have made the database publicly do
|
|||||||
|
|
||||||
Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea.
|
Hopefully this project can be combined with projects like [this](https://github.com/Sponsoff/sponsorship_remover) and use this data to create a neural network to predict when sponsored segments happen. That project is sadly abandoned now, so I have decided to attempt to revive this idea.
|
||||||
|
|
||||||
|
# API
|
||||||
|
|
||||||
|
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs).
|
||||||
|
|
||||||
# Previous extension
|
# Previous extension
|
||||||
|
|
||||||
This project is partially based off of [this experimental extension](https://github.com/OfficialNoob/YTSponsorSkip). That extension has the basic video skipping functionality.
|
This project is partially based off of [this experimental extension](https://github.com/OfficialNoob/YTSponsorSkip), which has the basic video skipping functionality.
|
||||||
|
|
||||||
# Build Yourself
|
# Build Yourself
|
||||||
|
|
||||||
@@ -35,4 +39,4 @@ The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) is u
|
|||||||
|
|
||||||
Some icons made by <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
Some icons made by <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> and are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||||
|
|
||||||
Some icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
Some icons made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> are licensed by <a href="http://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a>
|
||||||
|
|||||||
238
background.js
238
background.js
@@ -1,72 +1,79 @@
|
|||||||
var previousVideoID = null
|
|
||||||
|
|
||||||
//the id of this user, randomly generated once per install
|
|
||||||
var userID = null;
|
|
||||||
|
|
||||||
//the last video id loaded, to make sure it is a video id change
|
|
||||||
var sponsorVideoID = null;
|
|
||||||
|
|
||||||
//when a new tab is highlighted
|
|
||||||
chrome.tabs.onActivated.addListener(
|
|
||||||
function(activeInfo) {
|
|
||||||
chrome.tabs.get(activeInfo.tabId, function(tab) {
|
|
||||||
let id = getYouTubeVideoID(tab.url);
|
|
||||||
|
|
||||||
//if this even is a YouTube tab
|
|
||||||
if (id) {
|
|
||||||
videoIDChange(id, activeInfo.tabId);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
//when a tab changes URLs
|
|
||||||
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
|
||||||
if (changeInfo != undefined && changeInfo.url != undefined) {
|
chrome.tabs.sendMessage(tabId, {
|
||||||
let id = getYouTubeVideoID(changeInfo.url);
|
message: 'update',
|
||||||
|
});
|
||||||
//if URL changed and is youtube video message contentScript the video id
|
|
||||||
if (changeInfo.url && id) {
|
|
||||||
videoIDChange(id, tabId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||||
if (request.message == "submitTimes") {
|
switch(request.message) {
|
||||||
submitTimes(request.videoID, callback);
|
case "submitTimes":
|
||||||
|
submitTimes(request.videoID, callback);
|
||||||
//this allows the callback to be called later by the submitTimes function
|
|
||||||
return true;
|
//this allows the callback to be called later by the submitTimes function
|
||||||
} else if (request.message == "addSponsorTime") {
|
return true;
|
||||||
addSponsorTime(request.time, request.videoID);
|
case "addSponsorTime":
|
||||||
} else if (request.message == "getSponsorTimes") {
|
addSponsorTime(request.time, request.videoID, callback);
|
||||||
getSponsorTimes(request.videoID, function(sponsorTimes) {
|
|
||||||
callback({
|
//this allows the callback to be called later
|
||||||
sponsorTimes: sponsorTimes
|
return true;
|
||||||
})
|
case "getSponsorTimes":
|
||||||
});
|
getSponsorTimes(request.videoID, function(sponsorTimes) {
|
||||||
|
callback({
|
||||||
//this allows the callback to be called later
|
sponsorTimes: sponsorTimes
|
||||||
return true;
|
})
|
||||||
} else if (request.message == "submitVote") {
|
});
|
||||||
submitVote(request.type, request.UUID, callback);
|
|
||||||
|
//this allows the callback to be called later
|
||||||
//this allows the callback to be called later
|
return true;
|
||||||
return true;
|
case "submitVote":
|
||||||
}
|
submitVote(request.type, request.UUID, callback);
|
||||||
|
|
||||||
|
//this allows the callback to be called later
|
||||||
|
return true;
|
||||||
|
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"
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//add help page on install
|
//add help page on install
|
||||||
chrome.runtime.onInstalled.addListener(function (object) {
|
chrome.runtime.onInstalled.addListener(function (object) {
|
||||||
chrome.storage.sync.get(["shownInstallPage"], function(result) {
|
// TODO (shownInstallPage): remove shownInstallPage logic after sufficient amount of time,
|
||||||
let shownInstallPage = result.shownInstallPage;
|
// so that people have time to upgrade and move to shownInstallPage-free code.
|
||||||
if (shownInstallPage == undefined || !shownInstallPage) {
|
chrome.storage.sync.get(["userID", "shownInstallPage"], function(result) {
|
||||||
//open up the install page
|
const userID = result.userID;
|
||||||
chrome.tabs.create({url: chrome.extension.getURL("/help/index.html")});
|
// TODO (shownInstallPage): delete row below
|
||||||
|
const shownInstallPage = result.shownInstallPage;
|
||||||
|
|
||||||
//save that this happened
|
// If there is no userID, then it is the first install.
|
||||||
chrome.storage.sync.set({shownInstallPage: true});
|
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/index.html")});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -85,7 +92,7 @@ function getSponsorTimes(videoID, callback) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addSponsorTime(time, videoID) {
|
function addSponsorTime(time, videoID, callback) {
|
||||||
getSponsorTimes(videoID, function(sponsorTimes) {
|
getSponsorTimes(videoID, function(sponsorTimes) {
|
||||||
//add to sponsorTimes
|
//add to sponsorTimes
|
||||||
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
if (sponsorTimes.length > 0 && sponsorTimes[sponsorTimes.length - 1].length < 2) {
|
||||||
@@ -101,14 +108,16 @@ function addSponsorTime(time, videoID) {
|
|||||||
|
|
||||||
//save this info
|
//save this info
|
||||||
let sponsorTimeKey = "sponsorTimes" + videoID;
|
let sponsorTimeKey = "sponsorTimes" + videoID;
|
||||||
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes});
|
chrome.storage.sync.set({[sponsorTimeKey]: sponsorTimes}, callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitVote(type, UUID, callback) {
|
function submitVote(type, UUID, callback) {
|
||||||
getUserID(function(userID) {
|
chrome.storage.sync.get(["userID"], function(result) {
|
||||||
|
let userID = result.userID;
|
||||||
|
|
||||||
//publish this vote
|
//publish this vote
|
||||||
sendRequestToServer('GET', "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
sendRequestToServer("GET", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
||||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||||
callback({
|
callback({
|
||||||
successType: 1
|
successType: 1
|
||||||
@@ -133,16 +142,16 @@ function submitVote(type, UUID, callback) {
|
|||||||
function submitTimes(videoID, callback) {
|
function submitTimes(videoID, callback) {
|
||||||
//get the video times from storage
|
//get the video times from storage
|
||||||
let sponsorTimeKey = 'sponsorTimes' + videoID;
|
let sponsorTimeKey = 'sponsorTimes' + videoID;
|
||||||
chrome.storage.sync.get([sponsorTimeKey], function(result) {
|
chrome.storage.sync.get([sponsorTimeKey, "userID"], function(result) {
|
||||||
let sponsorTimes = result[sponsorTimeKey];
|
let sponsorTimes = result[sponsorTimeKey];
|
||||||
|
let userID = result.userID;
|
||||||
|
|
||||||
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
|
||||||
//submit these times
|
//submit these times
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
getUserID(function(userIDStorage) {
|
|
||||||
//submit the sponsorTime
|
//submit the sponsorTime
|
||||||
sendRequestToServer('GET', "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
sendRequestToServer("GET", "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
||||||
+ "&userID=" + userIDStorage, function(xmlhttp, error) {
|
+ "&userID=" + userID, function(xmlhttp, error) {
|
||||||
if (xmlhttp.readyState == 4 && !error) {
|
if (xmlhttp.readyState == 4 && !error) {
|
||||||
callback({
|
callback({
|
||||||
statusCode: xmlhttp.status
|
statusCode: xmlhttp.status
|
||||||
@@ -166,81 +175,12 @@ function submitTimes(videoID, callback) {
|
|||||||
statusCode: -1
|
statusCode: -1
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function videoIDChange(currentVideoID, tabId) {
|
|
||||||
//send a message to the content script
|
|
||||||
chrome.tabs.sendMessage(tabId, {
|
|
||||||
message: 'ytvideoid',
|
|
||||||
id: currentVideoID
|
|
||||||
});
|
|
||||||
|
|
||||||
//not a url change
|
|
||||||
if (sponsorVideoID == currentVideoID){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sponsorVideoID = currentVideoID;
|
|
||||||
|
|
||||||
//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.notifications.create("stillThere" + Math.random(), {
|
|
||||||
type: "basic",
|
|
||||||
title: "Do you want to submit the sponsor times for watch?v=" + 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"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//set the previous video id to the currentID
|
|
||||||
previousVideoID = currentVideoID;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
previousVideoID = currentVideoID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUserID(callback) {
|
|
||||||
if (userID != null) {
|
|
||||||
callback(userID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if it is not cached yet, grab it from storage
|
|
||||||
chrome.storage.sync.get(["userID"], function(result) {
|
|
||||||
let userIDStorage = result.userID;
|
|
||||||
if (userIDStorage != undefined) {
|
|
||||||
userID = userIDStorage;
|
|
||||||
callback(userID);
|
|
||||||
} else {
|
|
||||||
//double check if a UUID hasn't been created since this was first called
|
|
||||||
if (userID != null) {
|
|
||||||
callback(userID);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//generate a userID
|
|
||||||
userID = generateUUID();
|
|
||||||
|
|
||||||
//save this UUID
|
|
||||||
chrome.storage.sync.set({"userID": userID});
|
|
||||||
|
|
||||||
callback(userID);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendRequestToServer(type, address, callback) {
|
function sendRequestToServer(type, address, callback) {
|
||||||
let xmlhttp = new XMLHttpRequest();
|
let xmlhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
@@ -260,11 +200,21 @@ function sendRequestToServer(type, address, callback) {
|
|||||||
xmlhttp.send();
|
xmlhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYouTubeVideoID(url) { // Return video id or false
|
function generateUUID(length = 36) {
|
||||||
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
var match = url.match(regExp);
|
let result = "";
|
||||||
return (match && match[7].length == 11) ? match[7] : false;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//uuid generator function from https://gist.github.com/jed/982883
|
|
||||||
function generateUUID(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,generateUUID)}
|
|
||||||
18
content.css
18
content.css
@@ -1,3 +1,21 @@
|
|||||||
|
#previewbar {
|
||||||
|
overflow: visible;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
transform: scaleY(0.6) translateY(-30%) translateY(1.5px);
|
||||||
|
z-index: 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
.previewbar {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.popup {
|
.popup {
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
286
content.js
286
content.js
@@ -1,25 +1,47 @@
|
|||||||
//was sponsor data found when doing SponsorsLookup
|
//was sponsor data found when doing SponsorsLookup
|
||||||
var sponsorDataFound = false;
|
var sponsorDataFound = false;
|
||||||
|
var previousVideoID = null;
|
||||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||||
var sponsorTimes = null;
|
var sponsorTimes = null;
|
||||||
var UUIDs = null;
|
var UUIDs = null;
|
||||||
//what video id are these sponsors for
|
//what video id are these sponsors for
|
||||||
var sponsorVideoID = null;
|
var sponsorVideoID = null;
|
||||||
|
|
||||||
if(id = getYouTubeVideoID(document.URL)){ // Direct Links
|
//these are sponsors that have been downvoted
|
||||||
videoIDChange(id);
|
var hiddenSponsorTimes = [];
|
||||||
}
|
|
||||||
|
//the time this video is starting at when first played, if not zero
|
||||||
|
var youtubeVideoStartTime = null;
|
||||||
|
|
||||||
//the video
|
//the video
|
||||||
var v;
|
var v;
|
||||||
|
|
||||||
|
var listenerAdded;
|
||||||
|
|
||||||
|
//the channel this video is about
|
||||||
|
var channelURL;
|
||||||
|
|
||||||
|
//is this channel whitelised from getting sponsors skipped
|
||||||
|
var channelWhitelisted = false;
|
||||||
|
|
||||||
|
// create preview bar
|
||||||
|
let progressBar = document.getElementsByClassName("ytp-progress-bar-container")[0] || document.getElementsByClassName("no-model cue-range-markers")[0];
|
||||||
|
var previewBar = new PreviewBar(progressBar);
|
||||||
|
|
||||||
|
if(id = getYouTubeVideoID(document.URL)){ // Direct Links
|
||||||
|
videoIDChange(id);
|
||||||
|
}
|
||||||
|
|
||||||
//the last time looked at (used to see if this time is in the interval)
|
//the last time looked at (used to see if this time is in the interval)
|
||||||
var lastTime = -1;
|
var lastTime = -1;
|
||||||
|
|
||||||
//the actual time (not video time) that the last skip happened
|
//the actual time (not video time) that the last skip happened
|
||||||
var lastUnixTimeSkipped = -1;
|
var lastUnixTimeSkipped = -1;
|
||||||
|
|
||||||
|
//the amount of times the sponsor lookup has retried
|
||||||
|
//this only happens if there is an error
|
||||||
|
var sponsorLookupRetries = 0;
|
||||||
|
|
||||||
//the last time in the video a sponsor was skipped
|
//the last time in the video a sponsor was skipped
|
||||||
//used for the go back button
|
//used for the go back button
|
||||||
var lastSponsorTimeSkipped = null;
|
var lastSponsorTimeSkipped = null;
|
||||||
@@ -68,14 +90,14 @@ chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
|
|||||||
|
|
||||||
//get messages from the background script and the popup
|
//get messages from the background script and the popup
|
||||||
chrome.runtime.onMessage.addListener(messageListener);
|
chrome.runtime.onMessage.addListener(messageListener);
|
||||||
|
|
||||||
function messageListener(request, sender, sendResponse) {
|
function messageListener(request, sender, sendResponse) {
|
||||||
//message from background script
|
|
||||||
if (request.message == "ytvideoid") {
|
|
||||||
videoIDChange(request.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
//messages from popup script
|
//messages from popup script
|
||||||
|
|
||||||
|
if (request.message == "update") {
|
||||||
|
if(id = getYouTubeVideoID(document.URL)) videoIDChange(id);
|
||||||
|
}
|
||||||
|
|
||||||
if (request.message == "sponsorStart") {
|
if (request.message == "sponsorStart") {
|
||||||
sponsorMessageStarted(sendResponse);
|
sponsorMessageStarted(sendResponse);
|
||||||
}
|
}
|
||||||
@@ -89,6 +111,7 @@ function messageListener(request, sender, sendResponse) {
|
|||||||
sendResponse({
|
sendResponse({
|
||||||
found: sponsorDataFound,
|
found: sponsorDataFound,
|
||||||
sponsorTimes: sponsorTimes,
|
sponsorTimes: sponsorTimes,
|
||||||
|
hiddenSponsorTimes: hiddenSponsorTimes,
|
||||||
UUIDs: UUIDs
|
UUIDs: UUIDs
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,6 +129,33 @@ function messageListener(request, sender, sendResponse) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.message == "skipToTime") {
|
||||||
|
v.currentTime = request.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.message == "getCurrentTime") {
|
||||||
|
sendResponse({
|
||||||
|
currentTime: v.currentTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.message == "getChannelURL") {
|
||||||
|
sendResponse({
|
||||||
|
channelURL: channelURL
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.message == "isChannelWhitelisted") {
|
||||||
|
sendResponse({
|
||||||
|
value: channelWhitelisted
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.message == "whitelistChange") {
|
||||||
|
channelWhitelisted = request.value;
|
||||||
|
sponsorsLookup(getYouTubeVideoID(document.URL));
|
||||||
|
}
|
||||||
|
|
||||||
if (request.message == "showNoticeAgain") {
|
if (request.message == "showNoticeAgain") {
|
||||||
dontShowNotice = false;
|
dontShowNotice = false;
|
||||||
}
|
}
|
||||||
@@ -153,10 +203,35 @@ document.onkeydown = function(e){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function videoIDChange(id) {
|
function videoIDChange(id) {
|
||||||
|
|
||||||
//not a url change
|
//not a url change
|
||||||
if (sponsorVideoID == id){
|
if (sponsorVideoID == id) return;
|
||||||
return;
|
|
||||||
|
//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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//close popup
|
||||||
|
closeInfoMenu();
|
||||||
|
|
||||||
//reset last sponsor times
|
//reset last sponsor times
|
||||||
lastTime = -1;
|
lastTime = -1;
|
||||||
@@ -166,11 +241,21 @@ function videoIDChange(id) {
|
|||||||
sponsorTimes = null;
|
sponsorTimes = null;
|
||||||
UUIDs = null;
|
UUIDs = null;
|
||||||
sponsorVideoID = id;
|
sponsorVideoID = id;
|
||||||
|
sponsorLookupRetries = 0;
|
||||||
|
|
||||||
|
//empty the preview bar
|
||||||
|
previewBar.set([], [], 0);
|
||||||
|
|
||||||
|
//see if there is a video start time
|
||||||
|
youtubeVideoStartTime = getYouTubeVideoStartTime(document.URL);
|
||||||
|
|
||||||
//reset sponsor data found check
|
//reset sponsor data found check
|
||||||
sponsorDataFound = false;
|
sponsorDataFound = false;
|
||||||
sponsorsLookup(id);
|
sponsorsLookup(id);
|
||||||
|
|
||||||
|
//make sure everything is properly added
|
||||||
|
updateVisibilityOfPlayerControlsButton(true);
|
||||||
|
|
||||||
//reset sponsor times submitting
|
//reset sponsor times submitting
|
||||||
sponsorTimesSubmitting = [];
|
sponsorTimesSubmitting = [];
|
||||||
|
|
||||||
@@ -216,13 +301,19 @@ function videoIDChange(id) {
|
|||||||
hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls;
|
hideDeleteButtonPlayerControls = result.hideDeleteButtonPlayerControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVisibilityOfPlayerControlsButton();
|
updateVisibilityOfPlayerControlsButton(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sponsorsLookup(id) {
|
function sponsorsLookup(id) {
|
||||||
v = document.querySelector('video') // Youtube video player
|
v = document.querySelector('video') // Youtube video player
|
||||||
|
|
||||||
|
//there is no video here
|
||||||
|
if (v == null) {
|
||||||
|
setTimeout(() => sponsorsLookup(id), 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//check database for sponsor times
|
//check database for sponsor times
|
||||||
sendRequestToServer('GET', "/api/getVideoSponsorTimes?videoID=" + id, function(xmlhttp) {
|
sendRequestToServer('GET', "/api/getVideoSponsorTimes?videoID=" + id, function(xmlhttp) {
|
||||||
@@ -231,7 +322,22 @@ function sponsorsLookup(id) {
|
|||||||
|
|
||||||
sponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes;
|
sponsorTimes = JSON.parse(xmlhttp.responseText).sponsorTimes;
|
||||||
UUIDs = JSON.parse(xmlhttp.responseText).UUIDs;
|
UUIDs = JSON.parse(xmlhttp.responseText).UUIDs;
|
||||||
} else if (xmlhttp.readyState == 4) {
|
|
||||||
|
//update the preview bar
|
||||||
|
//leave the type blank for now until categories are added
|
||||||
|
console.log(v.duration)
|
||||||
|
if (isNaN(v.duration)) {
|
||||||
|
//wait until it is loaded
|
||||||
|
v.addEventListener('durationchange', updatePreviewBar);
|
||||||
|
} else {
|
||||||
|
//set it now
|
||||||
|
updatePreviewBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
getChannelID();
|
||||||
|
|
||||||
|
sponsorLookupRetries = 0;
|
||||||
|
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 404) {
|
||||||
sponsorDataFound = false;
|
sponsorDataFound = false;
|
||||||
|
|
||||||
//check if this video was uploaded recently
|
//check if this video was uploaded recently
|
||||||
@@ -246,6 +352,13 @@ function sponsorsLookup(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sponsorLookupRetries = 0;
|
||||||
|
} else if (xmlhttp.readyState == 4 && sponsorLookupRetries < 90) {
|
||||||
|
//some error occurred, try again in a second
|
||||||
|
setTimeout(() => sponsorsLookup(id), 1000);
|
||||||
|
|
||||||
|
sponsorLookupRetries++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -255,6 +368,54 @@ function sponsorsLookup(id) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updatePreviewBar() {
|
||||||
|
previewBar.set(sponsorTimes, [], v.duration);
|
||||||
|
|
||||||
|
//the listener is only needed once
|
||||||
|
v.removeEventListener('durationchange', updatePreviewBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChannelID() {
|
||||||
|
//get channel id
|
||||||
|
let channelContainers = document.querySelectorAll("#owner-name");
|
||||||
|
let channelURLContainer = null;
|
||||||
|
|
||||||
|
for (let i = 0; i < channelContainers.length; i++) {
|
||||||
|
if (channelContainers[i].firstElementChild != null) {
|
||||||
|
channelURLContainer = channelContainers[i].firstElementChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelContainers.length == 0) {
|
||||||
|
//old YouTube theme
|
||||||
|
channelContainers = document.getElementsByClassName("yt-user-info");
|
||||||
|
if (channelContainers.length != 0) {
|
||||||
|
channelURLContainer = channelContainers[0].firstElementChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channelURLContainer == null) {
|
||||||
|
//try later
|
||||||
|
setTimeout(getChannelID, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
channelURL = channelURLContainer.getAttribute("href");
|
||||||
|
|
||||||
|
//see if this is a whitelisted channel
|
||||||
|
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
|
||||||
|
let whitelistedChannels = result.whitelistedChannels;
|
||||||
|
|
||||||
|
if (whitelistedChannels != undefined && whitelistedChannels.includes(channelURL)) {
|
||||||
|
//reset sponsor times to nothing
|
||||||
|
sponsorTimes = [];
|
||||||
|
UUIDs = [];
|
||||||
|
|
||||||
|
channelWhitelisted = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//video skipping
|
//video skipping
|
||||||
function sponsorCheck() {
|
function sponsorCheck() {
|
||||||
let skipHappened = false;
|
let skipHappened = false;
|
||||||
@@ -293,7 +454,7 @@ function checkSponsorTime(sponsorTimes, index, openNotice) {
|
|||||||
lastTime = v.currentTime - 0.0001;
|
lastTime = v.currentTime - 0.0001;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkIfTimeToSkip(v.currentTime, sponsorTimes[index][0])) {
|
if (checkIfTimeToSkip(v.currentTime, sponsorTimes[index][0]) && !hiddenSponsorTimes.includes(index)) {
|
||||||
//skip it
|
//skip it
|
||||||
skipToTime(v, index, sponsorTimes, openNotice);
|
skipToTime(v, index, sponsorTimes, openNotice);
|
||||||
|
|
||||||
@@ -310,9 +471,9 @@ function checkIfTimeToSkip(currentVideoTime, startTime) {
|
|||||||
//If the sponsor time is in between these times, skip it
|
//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
|
//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)
|
// sponsor times in a row (from one troll)
|
||||||
//the last term makes 0 second start times possible
|
//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) < 0.3 && startTime >= lastTime && startTime <= currentVideoTime &&
|
return (Math.abs(currentVideoTime - startTime) < 0.3 && startTime >= lastTime && startTime <= currentVideoTime &&
|
||||||
(lastUnixTimeSkipped == -1 || currentTime - lastUnixTimeSkipped > 500)) || (lastTime == -1 && startTime == 0);
|
(lastUnixTimeSkipped == -1 || currentTime - lastUnixTimeSkipped > 500)) || (lastTime == -1 && startTime == 0 && youtubeVideoStartTime == null)
|
||||||
}
|
}
|
||||||
|
|
||||||
//skip fromt he start time to the end time for a certain index sponsor time
|
//skip fromt he start time to the end time for a certain index sponsor time
|
||||||
@@ -367,8 +528,15 @@ function addPlayerControlsButton() {
|
|||||||
//add the image to the button
|
//add the image to the button
|
||||||
startSponsorButton.appendChild(startSponsorImage);
|
startSponsorButton.appendChild(startSponsorImage);
|
||||||
|
|
||||||
let referenceNode = document.getElementsByClassName("ytp-right-controls")[0];
|
let controls = document.getElementsByClassName("ytp-right-controls");
|
||||||
|
let referenceNode = controls[controls.length - 1];
|
||||||
|
|
||||||
|
if (referenceNode == undefined) {
|
||||||
|
//page not loaded yet
|
||||||
|
setTimeout(addPlayerControlsButton, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
referenceNode.prepend(startSponsorButton);
|
referenceNode.prepend(startSponsorButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,6 +547,9 @@ function removePlayerControlsButton() {
|
|||||||
|
|
||||||
//adds or removes the player controls button to what it should be
|
//adds or removes the player controls button to what it should be
|
||||||
function updateVisibilityOfPlayerControlsButton() {
|
function updateVisibilityOfPlayerControlsButton() {
|
||||||
|
//not on a proper video yet
|
||||||
|
if (!getYouTubeVideoID(document.URL)) return;
|
||||||
|
|
||||||
addPlayerControlsButton();
|
addPlayerControlsButton();
|
||||||
addInfoButton();
|
addInfoButton();
|
||||||
addDeleteButton();
|
addDeleteButton();
|
||||||
@@ -482,7 +653,15 @@ function addInfoButton() {
|
|||||||
//add the image to the button
|
//add the image to the button
|
||||||
infoButton.appendChild(infoImage);
|
infoButton.appendChild(infoImage);
|
||||||
|
|
||||||
let referenceNode = document.getElementsByClassName("ytp-right-controls")[0];
|
let controls = document.getElementsByClassName("ytp-right-controls");
|
||||||
|
let referenceNode = controls[controls.length - 1];
|
||||||
|
|
||||||
|
if (referenceNode == undefined) {
|
||||||
|
//page not loaded yet
|
||||||
|
setTimeout(addInfoButton, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
referenceNode.prepend(infoButton);
|
referenceNode.prepend(infoButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +689,15 @@ function addDeleteButton() {
|
|||||||
//add the image to the button
|
//add the image to the button
|
||||||
deleteButton.appendChild(deleteImage);
|
deleteButton.appendChild(deleteImage);
|
||||||
|
|
||||||
let referenceNode = document.getElementsByClassName("ytp-right-controls")[0];
|
let controls = document.getElementsByClassName("ytp-right-controls");
|
||||||
|
let referenceNode = controls[controls.length - 1];
|
||||||
|
|
||||||
|
if (referenceNode == undefined) {
|
||||||
|
//page not loaded yet
|
||||||
|
setTimeout(addDeleteButton, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
referenceNode.prepend(deleteButton);
|
referenceNode.prepend(deleteButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +725,15 @@ function addSubmitButton() {
|
|||||||
//add the image to the button
|
//add the image to the button
|
||||||
submitButton.appendChild(submitImage);
|
submitButton.appendChild(submitImage);
|
||||||
|
|
||||||
let referenceNode = document.getElementsByClassName("ytp-right-controls")[0];
|
let controls = document.getElementsByClassName("ytp-right-controls");
|
||||||
|
let referenceNode = controls[controls.length - 1];
|
||||||
|
|
||||||
|
if (referenceNode == undefined) {
|
||||||
|
//page not loaded yet
|
||||||
|
setTimeout(addSubmitButton, 100);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
referenceNode.prepend(submitButton);
|
referenceNode.prepend(submitButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,6 +965,26 @@ function afterDownvote(UUID) {
|
|||||||
//add element to div
|
//add element to div
|
||||||
document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingText);
|
document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingText);
|
||||||
document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingInfoText);
|
document.getElementById("sponsorTimesVoteButtonsContainer" + UUID).appendChild(thanksForVotingInfoText);
|
||||||
|
|
||||||
|
//remove this sponsor from the sponsors looked up
|
||||||
|
//find which one it is
|
||||||
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
if (UUIDs[i] == 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addLoadingInfo(message, UUID) {
|
function addLoadingInfo(message, UUID) {
|
||||||
@@ -859,7 +1074,7 @@ function dontShowNoticeAgain() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function sponsorMessageStarted(callback) {
|
function sponsorMessageStarted(callback) {
|
||||||
let v = document.querySelector('video');
|
v = document.querySelector('video');
|
||||||
|
|
||||||
//send back current time
|
//send back current time
|
||||||
callback({
|
callback({
|
||||||
@@ -916,13 +1131,22 @@ function sendSubmitMessage(){
|
|||||||
//finish this animation
|
//finish this animation
|
||||||
submitButton.style.animation = "rotate 1s";
|
submitButton.style.animation = "rotate 1s";
|
||||||
//when the animation is over, hide the button
|
//when the animation is over, hide the button
|
||||||
submitButton.addEventListener("animationend", function() {
|
let animationEndListener = function() {
|
||||||
changeStartSponsorButton(true, false);
|
changeStartSponsorButton(true, false);
|
||||||
});
|
|
||||||
|
submitButton.style.animation = "none";
|
||||||
|
|
||||||
|
submitButton.removeEventListener("animationend", animationEndListener);
|
||||||
|
};
|
||||||
|
|
||||||
|
submitButton.addEventListener("animationend", animationEndListener);
|
||||||
|
|
||||||
//clear the sponsor times
|
//clear the sponsor times
|
||||||
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
||||||
chrome.storage.sync.set({[sponsorTimeKey]: []});
|
chrome.storage.sync.set({[sponsorTimeKey]: []});
|
||||||
|
|
||||||
|
//request the sponsors from the server again
|
||||||
|
sponsorsLookup(currentVideoID);
|
||||||
} else {
|
} else {
|
||||||
//for a more detailed error message, they should check the popup
|
//for a more detailed error message, they should check the popup
|
||||||
//show that the upload failed
|
//show that the upload failed
|
||||||
@@ -1018,15 +1242,3 @@ function sendRequestToCustomServer(type, fullAddress, callback) {
|
|||||||
//submit this request
|
//submit this request
|
||||||
xmlhttp.send();
|
xmlhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYouTubeVideoID(url) { // Returns with video id else returns false
|
|
||||||
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
|
||||||
var match = url.match(regExp);
|
|
||||||
var id = new URL(url).searchParams.get("v");
|
|
||||||
if (url.includes("/embed/")) {
|
|
||||||
//it is an embed, don't search for v
|
|
||||||
id = match[7];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (match && match[7].length == 11) ? id : false;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "SponsorBlock for YouTube - Skip Sponsorships",
|
"name": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||||
"short_name": "SponsorBlock",
|
"short_name": "SponsorBlock",
|
||||||
"version": "1.0.26",
|
"version": "1.0.35",
|
||||||
"description": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
"description": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"js": [
|
"js": [
|
||||||
"config.js",
|
"config.js",
|
||||||
|
"utils/previewBar.js",
|
||||||
|
"utils.js",
|
||||||
"content.js",
|
"content.js",
|
||||||
"popup.js"
|
"popup.js"
|
||||||
],
|
],
|
||||||
@@ -32,12 +34,9 @@
|
|||||||
"icons/downvote.png",
|
"icons/downvote.png",
|
||||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||||
"popup.html",
|
"popup.html"
|
||||||
"help/index.html",
|
|
||||||
"help/style.css"
|
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"tabs",
|
|
||||||
"storage",
|
"storage",
|
||||||
"notifications",
|
"notifications",
|
||||||
"https://sponsor.ajay.app/*"
|
"https://sponsor.ajay.app/*"
|
||||||
@@ -48,9 +47,11 @@
|
|||||||
},
|
},
|
||||||
"background": {
|
"background": {
|
||||||
"scripts":[
|
"scripts":[
|
||||||
|
"utils.js",
|
||||||
"config.js",
|
"config.js",
|
||||||
"background.js"
|
"background.js"
|
||||||
]
|
],
|
||||||
|
"persistent": false
|
||||||
},
|
},
|
||||||
"icons": {
|
"icons": {
|
||||||
"16": "icons/IconSponsorBlocker16px.png",
|
"16": "icons/IconSponsorBlocker16px.png",
|
||||||
|
|||||||
36
popup.css
36
popup.css
@@ -80,12 +80,44 @@ h1.popupElement {
|
|||||||
|
|
||||||
.mediumLink.popupElement {
|
.mediumLink.popupElement {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
padding-left: 15px;
|
margin-left: 25px;
|
||||||
padding-right: 15px;
|
margin-right: 25px;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tinyLink.popupElement {
|
||||||
|
font-size: 10px;
|
||||||
|
text-decoration: underline;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.whitelistButton.popupElement {
|
||||||
|
background-color:#3acc3a;
|
||||||
|
-moz-border-radius:28px;
|
||||||
|
-webkit-border-radius:28px;
|
||||||
|
border-radius:28px;
|
||||||
|
border: none;
|
||||||
|
display:inline-block;
|
||||||
|
cursor:pointer;
|
||||||
|
color:#ffffff;
|
||||||
|
font-size:16px;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
.greenButton.popupElement {
|
.greenButton.popupElement {
|
||||||
background-color:#ec1c1c;
|
background-color:#ec1c1c;
|
||||||
-moz-border-radius:28px;
|
-moz-border-radius:28px;
|
||||||
|
|||||||
43
popup.html
43
popup.html
@@ -25,7 +25,18 @@
|
|||||||
<div id="downloadedSponsorMessageTimes" class="popupElement">
|
<div id="downloadedSponsorMessageTimes" class="popupElement">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button id="whitelistChannel" class="whitelistButton popupElement">Whitelist Channel</button>
|
||||||
|
<button id="unwhitelistChannel" class="whitelistButton popupElement" style="display: none">Remove Channel From Whitelist</button>
|
||||||
|
</div>
|
||||||
|
<sub class="popupElement">
|
||||||
|
Whitelist the channels who do sponsorships ethically to encourage good behavior, or maybe if they are just entertaining and funny. Or don't, that's your call.
|
||||||
|
</sub>
|
||||||
|
|
||||||
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<button id="reportAnIssue" class="dangerButton popupElement">Vote On A Sponsor Time</button>
|
<button id="reportAnIssue" class="dangerButton popupElement">Vote On A Sponsor Time</button>
|
||||||
@@ -82,6 +93,8 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</b>
|
</b>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
<button id="clearTimes" class="smallButton popupElement">Clear Times</button>
|
<button id="clearTimes" class="smallButton popupElement">Clear Times</button>
|
||||||
|
|
||||||
@@ -101,6 +114,31 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="setUsernameContainer" class="popupElement">
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<button id="setUsernameButton" class="warningButton popupElement">Set Username</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="setUsername" class="popupElement" style="display: none">
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<h3>Set Username</h3>
|
||||||
|
|
||||||
|
<div id="setUsernameStatusContainer" style="display: none">
|
||||||
|
<h2 id="setUsernameStatus"></h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<input id="usernameInput" hint="Username"></input>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
<button id="submitUsername" class="warningButton popupElement">Submit Username</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="discordButtonContainer" class="popupElement" style="display: none">
|
<div id="discordButtonContainer" class="popupElement" style="display: none">
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -108,7 +146,7 @@
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
Come join the official discord server to give suggestions and feedback!
|
Come join the official discord server to give suggestions and feedback!
|
||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@@ -182,5 +220,6 @@
|
|||||||
|
|
||||||
<!-- Scripts that need to load after the html -->
|
<!-- Scripts that need to load after the html -->
|
||||||
<script src="config.js"></script>
|
<script src="config.js"></script>
|
||||||
|
<script src="utils.js"></script>
|
||||||
<script src="popup.js"></script>
|
<script src="popup.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
327
popup.js
327
popup.js
@@ -25,6 +25,8 @@ function runThePopup() {
|
|||||||
var SB = {};
|
var SB = {};
|
||||||
|
|
||||||
["sponsorStart",
|
["sponsorStart",
|
||||||
|
"whitelistChannel",
|
||||||
|
"unwhitelistChannel",
|
||||||
"clearTimes",
|
"clearTimes",
|
||||||
"submitTimes",
|
"submitTimes",
|
||||||
"showNoticeAgain",
|
"showNoticeAgain",
|
||||||
@@ -52,6 +54,14 @@ function runThePopup() {
|
|||||||
// submitTimesInfoMessage
|
// submitTimesInfoMessage
|
||||||
"submitTimesInfoMessageContainer",
|
"submitTimesInfoMessageContainer",
|
||||||
"submitTimesInfoMessage",
|
"submitTimesInfoMessage",
|
||||||
|
// Username
|
||||||
|
"setUsernameContainer",
|
||||||
|
"setUsernameButton",
|
||||||
|
"setUsernameStatusContainer",
|
||||||
|
"setUsernameStatus",
|
||||||
|
"setUsername",
|
||||||
|
"usernameInput",
|
||||||
|
"submitUsername",
|
||||||
// More
|
// More
|
||||||
"submissionSection",
|
"submissionSection",
|
||||||
"mainControls",
|
"mainControls",
|
||||||
@@ -63,6 +73,8 @@ function runThePopup() {
|
|||||||
|
|
||||||
//setup click listeners
|
//setup click listeners
|
||||||
SB.sponsorStart.addEventListener("click", sendSponsorStartMessage);
|
SB.sponsorStart.addEventListener("click", sendSponsorStartMessage);
|
||||||
|
SB.whitelistChannel.addEventListener("click", whitelistChannel);
|
||||||
|
SB.unwhitelistChannel.addEventListener("click", unwhitelistChannel);
|
||||||
SB.clearTimes.addEventListener("click", clearTimes);
|
SB.clearTimes.addEventListener("click", clearTimes);
|
||||||
SB.submitTimes.addEventListener("click", submitTimes);
|
SB.submitTimes.addEventListener("click", submitTimes);
|
||||||
SB.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
SB.showNoticeAgain.addEventListener("click", showNoticeAgain);
|
||||||
@@ -74,6 +86,8 @@ function runThePopup() {
|
|||||||
SB.showDeleteButtonPlayerControls.addEventListener("click", showDeleteButtonPlayerControls);
|
SB.showDeleteButtonPlayerControls.addEventListener("click", showDeleteButtonPlayerControls);
|
||||||
SB.disableSponsorViewTracking.addEventListener("click", disableSponsorViewTracking);
|
SB.disableSponsorViewTracking.addEventListener("click", disableSponsorViewTracking);
|
||||||
SB.enableSponsorViewTracking.addEventListener("click", enableSponsorViewTracking);
|
SB.enableSponsorViewTracking.addEventListener("click", enableSponsorViewTracking);
|
||||||
|
SB.setUsernameButton.addEventListener("click", setUsernameButton);
|
||||||
|
SB.submitUsername.addEventListener("click", submitUsername);
|
||||||
SB.optionsButton.addEventListener("click", openOptions);
|
SB.optionsButton.addEventListener("click", openOptions);
|
||||||
SB.reportAnIssue.addEventListener("click", reportAnIssue);
|
SB.reportAnIssue.addEventListener("click", reportAnIssue);
|
||||||
SB.hideDiscordButton.addEventListener("click", hideDiscordButton);
|
SB.hideDiscordButton.addEventListener("click", hideDiscordButton);
|
||||||
@@ -118,7 +132,7 @@ function runThePopup() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//if the don't show notice again letiable is true, an option to
|
//if the don't show notice again letiable is true, an option to
|
||||||
// disable should be available
|
// disable should be available
|
||||||
chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
|
chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
|
||||||
@@ -197,17 +211,25 @@ function runThePopup() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
chrome.tabs.query({
|
chrome.tabs.query({
|
||||||
active: true,
|
active: true,
|
||||||
currentWindow: true
|
currentWindow: true
|
||||||
}, loadTabData);
|
}, onTabs);
|
||||||
|
|
||||||
|
function onTabs(tabs) {
|
||||||
|
chrome.tabs.sendMessage(tabs[0].id, {message: 'getVideoID'}, function(result) {
|
||||||
|
if (result != undefined && result.videoID) {
|
||||||
|
currentVideoID = result.videoID;
|
||||||
|
|
||||||
|
loadTabData(tabs);
|
||||||
|
} else if (result == undefined && chrome.runtime.lastError) {
|
||||||
|
//this isn't a YouTube video then, or at least the content script is not loaded
|
||||||
|
displayNoVideo();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function loadTabData(tabs) {
|
function loadTabData(tabs) {
|
||||||
//set current videoID
|
|
||||||
currentVideoID = getYouTubeVideoID(tabs[0].url);
|
|
||||||
|
|
||||||
if (!currentVideoID) {
|
if (!currentVideoID) {
|
||||||
//this isn't a YouTube video then
|
//this isn't a YouTube video then
|
||||||
displayNoVideo();
|
displayNoVideo();
|
||||||
@@ -268,6 +290,26 @@ function runThePopup() {
|
|||||||
SB.videoFound.innerHTML = "No sponsors found"
|
SB.videoFound.innerHTML = "No sponsors found"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//see if whitelist button should be swapped
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id,
|
||||||
|
{message: 'isChannelWhitelisted'},
|
||||||
|
function(response) {
|
||||||
|
if (response.value) {
|
||||||
|
SB.whitelistChannel.style.display = "none";
|
||||||
|
SB.unwhitelistChannel.style.display = "unset";
|
||||||
|
|
||||||
|
SB.downloadedSponsorMessageTimes.innerText = "Channel Whitelisted!";
|
||||||
|
SB.downloadedSponsorMessageTimes.style.fontWeight = "bold";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVideoID(request) {
|
function setVideoID(request) {
|
||||||
@@ -343,14 +385,23 @@ function runThePopup() {
|
|||||||
function displayDownloadedSponsorTimes(request) {
|
function displayDownloadedSponsorTimes(request) {
|
||||||
if (request.sponsorTimes != undefined) {
|
if (request.sponsorTimes != undefined) {
|
||||||
//set it to the message
|
//set it to the message
|
||||||
SB.downloadedSponsorMessageTimes.innerText = getSponsorTimesMessage(request.sponsorTimes);
|
if (SB.downloadedSponsorMessageTimes.innerText != "Channel Whitelisted!") {
|
||||||
|
SB.downloadedSponsorMessageTimes.innerText = getSponsorTimesMessage(request.sponsorTimes);
|
||||||
|
}
|
||||||
|
|
||||||
//add them as buttons to the issue reporting container
|
//add them as buttons to the issue reporting container
|
||||||
let container = document.getElementById("issueReporterTimeButtons");
|
let container = document.getElementById("issueReporterTimeButtons");
|
||||||
for (let i = 0; i < request.sponsorTimes.length; i++) {
|
for (let i = 0; i < request.sponsorTimes.length; i++) {
|
||||||
let sponsorTimeButton = document.createElement("button");
|
let sponsorTimeButton = document.createElement("button");
|
||||||
sponsorTimeButton.className = "warningButton popupElement";
|
sponsorTimeButton.className = "warningButton popupElement";
|
||||||
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i][0]) + " to " + getFormattedTime(request.sponsorTimes[i][1]);
|
|
||||||
|
let extraInfo = "";
|
||||||
|
if (request.hiddenSponsorTimes.includes(i)) {
|
||||||
|
//this one is hidden
|
||||||
|
extraInfo = " (hidden)";
|
||||||
|
}
|
||||||
|
|
||||||
|
sponsorTimeButton.innerText = getFormattedTime(request.sponsorTimes[i][0]) + " to " + getFormattedTime(request.sponsorTimes[i][1]) + extraInfo;
|
||||||
|
|
||||||
let votingButtons = document.createElement("div");
|
let votingButtons = document.createElement("div");
|
||||||
|
|
||||||
@@ -439,8 +490,11 @@ function runThePopup() {
|
|||||||
let index = i;
|
let index = i;
|
||||||
deleteButton.addEventListener("click", () => deleteSponsorTime(index));
|
deleteButton.addEventListener("click", () => deleteSponsorTime(index));
|
||||||
|
|
||||||
let spacer = document.createElement("span");
|
let previewButton = document.createElement("span");
|
||||||
spacer.innerText = " ";
|
previewButton.id = "sponsorTimePreviewButton" + i;
|
||||||
|
previewButton.innerText = "Preview";
|
||||||
|
previewButton.className = "mediumLink popupElement";
|
||||||
|
previewButton.addEventListener("click", () => previewSponsorTime(index));
|
||||||
|
|
||||||
let editButton = document.createElement("span");
|
let editButton = document.createElement("span");
|
||||||
editButton.id = "sponsorTimeEditButton" + i;
|
editButton.id = "sponsorTimeEditButton" + i;
|
||||||
@@ -462,19 +516,46 @@ function runThePopup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentSponsorTimeContainer.innerText = currentSponsorTimeMessage;
|
currentSponsorTimeContainer.innerText = currentSponsorTimeMessage;
|
||||||
currentSponsorTimeContainer.addEventListener("click", () => editSponsorTime(index));
|
|
||||||
|
|
||||||
sponsorTimesContainer.appendChild(currentSponsorTimeContainer);
|
sponsorTimesContainer.appendChild(currentSponsorTimeContainer);
|
||||||
sponsorTimesContainer.appendChild(deleteButton);
|
sponsorTimesContainer.appendChild(deleteButton);
|
||||||
|
|
||||||
//only if it is a complete sponsor time
|
//only if it is a complete sponsor time
|
||||||
if (sponsorTimes[i].length > 1) {
|
if (sponsorTimes[i].length > 1) {
|
||||||
|
sponsorTimesContainer.appendChild(previewButton);
|
||||||
sponsorTimesContainer.appendChild(editButton);
|
sponsorTimesContainer.appendChild(editButton);
|
||||||
|
|
||||||
|
currentSponsorTimeContainer.addEventListener("click", () => editSponsorTime(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sponsorTimesContainer;
|
return sponsorTimesContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function previewSponsorTime(index) {
|
||||||
|
let skipTime = sponsorTimes[index][0];
|
||||||
|
|
||||||
|
if (document.getElementById("startTimeMinutes" + index) != null) {
|
||||||
|
//edit is currently open, use that time
|
||||||
|
|
||||||
|
skipTime = getSponsorTimeEditTimes("startTime", index);
|
||||||
|
|
||||||
|
//save the edit
|
||||||
|
saveSponsorTimeEdit(index, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id, {
|
||||||
|
message: "skipToTime",
|
||||||
|
time: skipTime - 2
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function editSponsorTime(index) {
|
function editSponsorTime(index) {
|
||||||
if (document.getElementById("startTimeMinutes" + index) != null) {
|
if (document.getElementById("startTimeMinutes" + index) != null) {
|
||||||
@@ -487,6 +568,13 @@ function runThePopup() {
|
|||||||
|
|
||||||
let sponsorTimeContainer = document.getElementById("sponsorTimeContainer" + index);
|
let sponsorTimeContainer = document.getElementById("sponsorTimeContainer" + index);
|
||||||
|
|
||||||
|
//the button to set the current time
|
||||||
|
let startTimeNowButton = document.createElement("span");
|
||||||
|
startTimeNowButton.id = "startTimeNowButton" + index;
|
||||||
|
startTimeNowButton.innerText = "(Now)";
|
||||||
|
startTimeNowButton.className = "tinyLink popupElement";
|
||||||
|
startTimeNowButton.addEventListener("click", () => setEditTimeToCurrentTime("startTime", index));
|
||||||
|
|
||||||
//get sponsor time minutes and seconds boxes
|
//get sponsor time minutes and seconds boxes
|
||||||
let startTimeMinutes = document.createElement("input");
|
let startTimeMinutes = document.createElement("input");
|
||||||
startTimeMinutes.id = "startTimeMinutes" + index;
|
startTimeMinutes.id = "startTimeMinutes" + index;
|
||||||
@@ -501,7 +589,7 @@ function runThePopup() {
|
|||||||
startTimeSeconds.type = "text";
|
startTimeSeconds.type = "text";
|
||||||
startTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][0]);
|
startTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][0]);
|
||||||
startTimeSeconds.style.width = "60px";
|
startTimeSeconds.style.width = "60px";
|
||||||
|
|
||||||
let endTimeMinutes = document.createElement("input");
|
let endTimeMinutes = document.createElement("input");
|
||||||
endTimeMinutes.id = "endTimeMinutes" + index;
|
endTimeMinutes.id = "endTimeMinutes" + index;
|
||||||
endTimeMinutes.className = "sponsorTime popupElement";
|
endTimeMinutes.className = "sponsorTime popupElement";
|
||||||
@@ -515,6 +603,13 @@ function runThePopup() {
|
|||||||
endTimeSeconds.type = "text";
|
endTimeSeconds.type = "text";
|
||||||
endTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][1]);
|
endTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][1]);
|
||||||
endTimeSeconds.style.width = "60px";
|
endTimeSeconds.style.width = "60px";
|
||||||
|
|
||||||
|
//the button to set the current time
|
||||||
|
let endTimeNowButton = document.createElement("span");
|
||||||
|
endTimeNowButton.id = "endTimeNowButton" + index;
|
||||||
|
endTimeNowButton.innerText = "(Now)";
|
||||||
|
endTimeNowButton.className = "tinyLink popupElement";
|
||||||
|
endTimeNowButton.addEventListener("click", () => setEditTimeToCurrentTime("endTime", index));
|
||||||
|
|
||||||
let colonText = document.createElement("span");
|
let colonText = document.createElement("span");
|
||||||
colonText.innerText = ":";
|
colonText.innerText = ":";
|
||||||
@@ -527,6 +622,7 @@ function runThePopup() {
|
|||||||
sponsorTimeContainer.removeChild(sponsorTimeContainer.firstChild);
|
sponsorTimeContainer.removeChild(sponsorTimeContainer.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sponsorTimeContainer.appendChild(startTimeNowButton);
|
||||||
sponsorTimeContainer.appendChild(startTimeMinutes);
|
sponsorTimeContainer.appendChild(startTimeMinutes);
|
||||||
sponsorTimeContainer.appendChild(colonText);
|
sponsorTimeContainer.appendChild(colonText);
|
||||||
sponsorTimeContainer.appendChild(startTimeSeconds);
|
sponsorTimeContainer.appendChild(startTimeSeconds);
|
||||||
@@ -534,6 +630,7 @@ function runThePopup() {
|
|||||||
sponsorTimeContainer.appendChild(endTimeMinutes);
|
sponsorTimeContainer.appendChild(endTimeMinutes);
|
||||||
sponsorTimeContainer.appendChild(colonText);
|
sponsorTimeContainer.appendChild(colonText);
|
||||||
sponsorTimeContainer.appendChild(endTimeSeconds);
|
sponsorTimeContainer.appendChild(endTimeSeconds);
|
||||||
|
sponsorTimeContainer.appendChild(endTimeNowButton);
|
||||||
|
|
||||||
//add save button and remove edit button
|
//add save button and remove edit button
|
||||||
let saveButton = document.createElement("span");
|
let saveButton = document.createElement("span");
|
||||||
@@ -547,16 +644,37 @@ function runThePopup() {
|
|||||||
|
|
||||||
sponsorTimesContainer.replaceChild(saveButton, editButton);
|
sponsorTimesContainer.replaceChild(saveButton, editButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setEditTimeToCurrentTime(idStartName, index) {
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id,
|
||||||
|
{message: "getCurrentTime"},
|
||||||
|
function (response) {
|
||||||
|
let minutes = document.getElementById(idStartName + "Minutes" + index);
|
||||||
|
let seconds = document.getElementById(idStartName + "Seconds" + index);
|
||||||
|
|
||||||
|
minutes.value = getTimeInMinutes(response.currentTime);
|
||||||
|
seconds.value = getTimeInFormattedSeconds(response.currentTime);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//id start name is whether it is the startTime or endTime
|
||||||
|
//gives back the time in seconds
|
||||||
|
function getSponsorTimeEditTimes(idStartName, index) {
|
||||||
|
let minutes = document.getElementById(idStartName + "Minutes" + index);
|
||||||
|
let seconds = document.getElementById(idStartName + "Seconds" + index);
|
||||||
|
|
||||||
|
return parseInt(minutes.value) * 60 + parseFloat(seconds.value);
|
||||||
|
}
|
||||||
|
|
||||||
function saveSponsorTimeEdit(index) {
|
function saveSponsorTimeEdit(index, closeEditMode = true) {
|
||||||
let startTimeMinutes = document.getElementById("startTimeMinutes" + index);
|
sponsorTimes[index][0] = getSponsorTimeEditTimes("startTime", index);
|
||||||
let startTimeSeconds = document.getElementById("startTimeSeconds" + index);
|
sponsorTimes[index][1] = getSponsorTimeEditTimes("endTime", index);
|
||||||
|
|
||||||
let endTimeMinutes = document.getElementById("endTimeMinutes" + index);
|
|
||||||
let endTimeSeconds = document.getElementById("endTimeSeconds" + index);
|
|
||||||
|
|
||||||
sponsorTimes[index][0] = parseInt(startTimeMinutes.value) * 60 + parseFloat(startTimeSeconds.value);
|
|
||||||
sponsorTimes[index][1] = parseInt(endTimeMinutes.value) * 60 + parseFloat(endTimeSeconds.value);
|
|
||||||
|
|
||||||
//save this
|
//save this
|
||||||
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
||||||
@@ -572,9 +690,11 @@ function runThePopup() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
displaySponsorTimes();
|
if (closeEditMode) {
|
||||||
|
displaySponsorTimes();
|
||||||
|
|
||||||
showSubmitTimesIfNecessary();
|
showSubmitTimesIfNecessary();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//deletes the sponsor time submitted at an index
|
//deletes the sponsor time submitted at an index
|
||||||
@@ -885,11 +1005,64 @@ function runThePopup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//make the options div visisble
|
//make the options div visible
|
||||||
function openOptions() {
|
function openOptions() {
|
||||||
document.getElementById("optionsButtonContainer").style.display = "none";
|
document.getElementById("optionsButtonContainer").style.display = "none";
|
||||||
document.getElementById("options").style.display = "unset";
|
document.getElementById("options").style.display = "unset";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//make the options username setting option visible
|
||||||
|
function setUsernameButton() {
|
||||||
|
//get the userID
|
||||||
|
chrome.storage.sync.get(["userID"], function(result) {
|
||||||
|
//get username from the server
|
||||||
|
sendRequestToServer("GET", "/api/getUsername?userID=" + result.userID, function (xmlhttp, error) {
|
||||||
|
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||||
|
SB.usernameInput.value = JSON.parse(xmlhttp.responseText).userName;
|
||||||
|
|
||||||
|
SB.submitUsername.style.display = "unset";
|
||||||
|
SB.usernameInput.style.display = "unset";
|
||||||
|
|
||||||
|
SB.setUsernameContainer.style.display = "none";
|
||||||
|
SB.setUsername.style.display = "unset";
|
||||||
|
} else {
|
||||||
|
SB.setUsername.style.display = "unset";
|
||||||
|
SB.submitUsername.style.display = "none";
|
||||||
|
SB.usernameInput.style.display = "none";
|
||||||
|
|
||||||
|
SB.setUsernameStatus.innerText = "Couldn't connect to server. Error code: " + xmlhttp.status;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//submit the new username
|
||||||
|
function submitUsername() {
|
||||||
|
//add loading indicator
|
||||||
|
SB.setUsernameStatusContainer.style.display = "unset";
|
||||||
|
SB.setUsernameStatus.innerText = "Loading...";
|
||||||
|
|
||||||
|
//get the userID
|
||||||
|
chrome.storage.sync.get(["userID"], function(result) {
|
||||||
|
sendRequestToServer("POST", "/api/setUsername?userID=" + result.userID + "&username=" + SB.usernameInput.value, function (xmlhttp, error) {
|
||||||
|
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||||
|
//submitted
|
||||||
|
SB.submitUsername.style.display = "none";
|
||||||
|
SB.usernameInput.style.display = "none";
|
||||||
|
|
||||||
|
SB.setUsernameStatus.innerText = "Success!";
|
||||||
|
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 400) {
|
||||||
|
SB.setUsernameStatus.innerText = "Bad Request";
|
||||||
|
} else {
|
||||||
|
SB.setUsernameStatus.innerText = getErrorMessage(EN_US, xmlhttp.status);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
SB.setUsernameContainer.style.display = "none";
|
||||||
|
SB.setUsername.style.display = "unset";
|
||||||
|
}
|
||||||
|
|
||||||
//this is not a YouTube video page
|
//this is not a YouTube video page
|
||||||
function displayNoVideo() {
|
function displayNoVideo() {
|
||||||
@@ -966,6 +1139,103 @@ function runThePopup() {
|
|||||||
|
|
||||||
return formatted;
|
return formatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function whitelistChannel() {
|
||||||
|
//get the channel url
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id,
|
||||||
|
{message: 'getChannelURL'},
|
||||||
|
function(response) {
|
||||||
|
//get whitelisted channels
|
||||||
|
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
|
||||||
|
let whitelistedChannels = result.whitelistedChannels;
|
||||||
|
if (whitelistedChannels == undefined) {
|
||||||
|
whitelistedChannels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//add on this channel
|
||||||
|
whitelistedChannels.push(response.channelURL);
|
||||||
|
|
||||||
|
//change button
|
||||||
|
SB.whitelistChannel.style.display = "none";
|
||||||
|
SB.unwhitelistChannel.style.display = "unset";
|
||||||
|
|
||||||
|
SB.downloadedSponsorMessageTimes.innerText = "Channel Whitelisted!";
|
||||||
|
SB.downloadedSponsorMessageTimes.style.fontWeight = "bold";
|
||||||
|
|
||||||
|
//save this
|
||||||
|
chrome.storage.sync.set({whitelistedChannels: whitelistedChannels});
|
||||||
|
|
||||||
|
//send a message to the client
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id, {
|
||||||
|
message: 'whitelistChange',
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function unwhitelistChannel() {
|
||||||
|
//get the channel url
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id,
|
||||||
|
{message: 'getChannelURL'},
|
||||||
|
function(response) {
|
||||||
|
//get whitelisted channels
|
||||||
|
chrome.storage.sync.get(["whitelistedChannels"], function(result) {
|
||||||
|
let whitelistedChannels = result.whitelistedChannels;
|
||||||
|
if (whitelistedChannels == undefined) {
|
||||||
|
whitelistedChannels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove this channel
|
||||||
|
let index = whitelistedChannels.indexOf(response.channelURL);
|
||||||
|
whitelistedChannels.splice(index, 1);
|
||||||
|
|
||||||
|
//change button
|
||||||
|
SB.whitelistChannel.style.display = "unset";
|
||||||
|
SB.unwhitelistChannel.style.display = "none";
|
||||||
|
|
||||||
|
SB.downloadedSponsorMessageTimes.innerText = "";
|
||||||
|
SB.downloadedSponsorMessageTimes.style.fontWeight = "unset";
|
||||||
|
|
||||||
|
//save this
|
||||||
|
chrome.storage.sync.set({whitelistedChannels: whitelistedChannels});
|
||||||
|
|
||||||
|
//send a message to the client
|
||||||
|
chrome.tabs.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
chrome.tabs.sendMessage(
|
||||||
|
tabs[0].id, {
|
||||||
|
message: 'whitelistChange',
|
||||||
|
value: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//converts time in seconds to minutes
|
//converts time in seconds to minutes
|
||||||
function getTimeInMinutes(seconds) {
|
function getTimeInMinutes(seconds) {
|
||||||
@@ -1004,13 +1274,6 @@ function runThePopup() {
|
|||||||
xmlhttp.send();
|
xmlhttp.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYouTubeVideoID(url) { // Returns with video id else returns false
|
|
||||||
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
|
||||||
var match = url.match(regExp);
|
|
||||||
var id = new URL(url).searchParams.get("v");
|
|
||||||
return (match && match[7].length == 11) ? id : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//end of function
|
//end of function
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1020,4 +1283,4 @@ if (chrome.tabs != undefined) {
|
|||||||
|
|
||||||
//this means it is actually opened in the popup
|
//this means it is actually opened in the popup
|
||||||
runThePopup();
|
runThePopup();
|
||||||
}
|
}
|
||||||
|
|||||||
37
utils.js
Normal file
37
utils.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
function getYouTubeVideoID(url) {
|
||||||
|
//Attempt to parse url
|
||||||
|
let urlObject = null;
|
||||||
|
try {
|
||||||
|
urlObject = new URL(url);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[SB] Unable to parse URL: " + url);
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if valid hostname
|
||||||
|
if(!["www.youtube.com","www.youtube-nocookie.com"].includes(urlObject.host)) return false;
|
||||||
|
|
||||||
|
//Get ID from searchParam
|
||||||
|
if ((urlObject.pathname == "/watch" || urlObject.pathname == "/watch/") && urlObject.searchParams.has("v")) {
|
||||||
|
id = urlObject.searchParams.get("v");
|
||||||
|
return id.length == 11 ? id : false;
|
||||||
|
} else if (urlObject.pathname.startsWith("/embed/")) {
|
||||||
|
try {
|
||||||
|
return urlObject.pathname.substr(7, 11);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("[SB] Video ID not valid for " + url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//returns the start time of the video if there was one specified (ex. ?t=5s)
|
||||||
|
function getYouTubeVideoStartTime(url) {
|
||||||
|
let searchParams = new URL(url).searchParams;
|
||||||
|
let startTime = searchParams.get("t");
|
||||||
|
if (startTime == null) {
|
||||||
|
startTime = searchParams.get("time_continue");
|
||||||
|
}
|
||||||
|
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
86
utils/previewBar.js
Normal file
86
utils/previewBar.js
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
This is based on code from VideoSegments.
|
||||||
|
https://github.com/videosegments/videosegments/commits/f1e111bdfe231947800c6efdd51f62a4e7fef4d4/segmentsbar/segmentsbar.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
let barTypes = {
|
||||||
|
"undefined": {
|
||||||
|
color: "#00d400",
|
||||||
|
opacity: "0.5"
|
||||||
|
},
|
||||||
|
"sponsor": {
|
||||||
|
color: "#00d400",
|
||||||
|
opacity: "0.5"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PreviewBar {
|
||||||
|
constructor(parent) {
|
||||||
|
this.container = document.createElement('ul');
|
||||||
|
this.container.id = 'previewbar';
|
||||||
|
this.parent = parent;
|
||||||
|
this.bars = []
|
||||||
|
|
||||||
|
this.updatePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePosition() {
|
||||||
|
//below the seek bar
|
||||||
|
// this.parent.insertAdjacentElement("afterEnd", this.container);
|
||||||
|
|
||||||
|
//on the seek bar
|
||||||
|
this.parent.insertAdjacentElement("afterBegin", this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateColor(segment, color, opacity) {
|
||||||
|
let bars = document.querySelectorAll('[data-vs-segment-type=' + segment + ']');
|
||||||
|
for (let bar of bars) {
|
||||||
|
bar.style.backgroundColor = color;
|
||||||
|
bar.style.opacity = opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set(timestamps, types, duration) {
|
||||||
|
while (this.container.firstChild) {
|
||||||
|
this.container.removeChild(this.container.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!timestamps || !types) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// to avoid rounding error resulting in width more than 100%
|
||||||
|
duration = Math.floor(duration * 100) / 100;
|
||||||
|
let width;
|
||||||
|
for (let i = 0; i < timestamps.length; i++) {
|
||||||
|
width = (timestamps[i][1] - timestamps[i][0]) / duration * 100;
|
||||||
|
width = Math.floor(width * 100) / 100;
|
||||||
|
|
||||||
|
let bar = this.createBar();
|
||||||
|
bar.setAttribute('data-vs-segment-type', types[i]);
|
||||||
|
|
||||||
|
bar.style.backgroundColor = barTypes[types[i]].color;
|
||||||
|
bar.style.opacity = barTypes[types[i]].opacity;
|
||||||
|
bar.style.width = width + '%';
|
||||||
|
bar.style.left = (timestamps[i][0] / duration * 100) + "%";
|
||||||
|
bar.style.position = "absolute"
|
||||||
|
|
||||||
|
this.container.insertAdjacentElement('beforeEnd', bar);
|
||||||
|
this.bars[i] = bar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createBar() {
|
||||||
|
let bar = document.createElement('li');
|
||||||
|
bar.classList.add('previewbar');
|
||||||
|
bar.innerHTML = ' ';
|
||||||
|
return bar;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this.container.remove();
|
||||||
|
this.container = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user