mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-10 13:37:04 +03:00
Compare commits
83 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5916baf5ea | ||
|
|
1c3a857fcf | ||
|
|
640ad58c65 | ||
|
|
41aa58e004 | ||
|
|
6b3eb09198 | ||
|
|
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 |
@@ -3,7 +3,7 @@
|
||||
|
||||
# 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
|
||||
|
||||
@@ -23,11 +23,11 @@ Hopefully this project can be combined with projects like [this](https://github.
|
||||
|
||||
# API
|
||||
|
||||
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs)
|
||||
You can read the API docs [here](https://github.com/ajayyy/SponsorBlockServer#api-docs).
|
||||
|
||||
# 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
|
||||
|
||||
@@ -39,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/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>
|
||||
|
||||
188
background.js
188
background.js
@@ -1,35 +1,7 @@
|
||||
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) {
|
||||
if (changeInfo != undefined && changeInfo.url != undefined) {
|
||||
let id = getYouTubeVideoID(changeInfo.url);
|
||||
|
||||
//if URL changed and is youtube video message contentScript the video id
|
||||
if (changeInfo.url && id) {
|
||||
videoIDChange(id, tabId);
|
||||
}
|
||||
}
|
||||
chrome.tabs.sendMessage(tabId, {
|
||||
message: 'update',
|
||||
});
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
@@ -57,19 +29,50 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
|
||||
//this allows the callback to be called later
|
||||
return true;
|
||||
}
|
||||
} else if (request.message == "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
|
||||
chrome.runtime.onInstalled.addListener(function (object) {
|
||||
chrome.storage.sync.get(["shownInstallPage"], function(result) {
|
||||
let shownInstallPage = result.shownInstallPage;
|
||||
if (shownInstallPage == undefined || !shownInstallPage) {
|
||||
//open up the install page
|
||||
chrome.tabs.create({url: chrome.extension.getURL("/help/index.html")});
|
||||
// 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;
|
||||
|
||||
//save that this happened
|
||||
chrome.storage.sync.set({shownInstallPage: true});
|
||||
// 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/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
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -109,9 +112,11 @@ function addSponsorTime(time, videoID, callback) {
|
||||
}
|
||||
|
||||
function submitVote(type, UUID, callback) {
|
||||
getUserID(function(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) {
|
||||
sendRequestToServer("GET", "/api/voteOnSponsorTime?UUID=" + UUID + "&userID=" + userID + "&type=" + type, function(xmlhttp, error) {
|
||||
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
|
||||
callback({
|
||||
successType: 1
|
||||
@@ -136,16 +141,16 @@ function submitVote(type, UUID, callback) {
|
||||
function submitTimes(videoID, callback) {
|
||||
//get the video times from storage
|
||||
let sponsorTimeKey = 'sponsorTimes' + videoID;
|
||||
chrome.storage.sync.get([sponsorTimeKey], function(result) {
|
||||
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++) {
|
||||
getUserID(function(userIDStorage) {
|
||||
//submit the sponsorTime
|
||||
sendRequestToServer('GET', "/api/postVideoSponsorTimes?videoID=" + videoID + "&startTime=" + sponsorTimes[i][0] + "&endTime=" + sponsorTimes[i][1]
|
||||
+ "&userID=" + userIDStorage, function(xmlhttp, error) {
|
||||
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
|
||||
@@ -169,81 +174,12 @@ function submitTimes(videoID, callback) {
|
||||
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) {
|
||||
let xmlhttp = new XMLHttpRequest();
|
||||
|
||||
@@ -263,11 +199,21 @@ function sendRequestToServer(type, address, callback) {
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function getYouTubeVideoID(url) { // Return video id or false
|
||||
var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
|
||||
var match = url.match(regExp);
|
||||
return (match && match[7].length == 11) ? match[7] : false;
|
||||
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];
|
||||
}
|
||||
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)}
|
||||
103
content.js
103
content.js
@@ -1,6 +1,6 @@
|
||||
//was sponsor data found when doing SponsorsLookup
|
||||
var sponsorDataFound = false;
|
||||
|
||||
var previousVideoID = null;
|
||||
//the actual sponsorTimes if loaded and UUIDs associated with them
|
||||
var sponsorTimes = null;
|
||||
var UUIDs = null;
|
||||
@@ -10,10 +10,6 @@ var sponsorVideoID = null;
|
||||
//the time this video is starting at when first played, if not zero
|
||||
var youtubeVideoStartTime = null;
|
||||
|
||||
if(id = getYouTubeVideoID(document.URL)){ // Direct Links
|
||||
videoIDChange(id);
|
||||
}
|
||||
|
||||
//the video
|
||||
var v;
|
||||
|
||||
@@ -23,12 +19,20 @@ var channelURL;
|
||||
//is this channel whitelised from getting sponsors skipped
|
||||
var channelWhitelisted = false;
|
||||
|
||||
if(id = getYouTubeVideoID(document.URL)){ // Direct Links
|
||||
videoIDChange(id);
|
||||
}
|
||||
|
||||
//the last time looked at (used to see if this time is in the interval)
|
||||
var lastTime = -1;
|
||||
|
||||
//the actual time (not video time) that the last skip happened
|
||||
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
|
||||
//used for the go back button
|
||||
var lastSponsorTimeSkipped = null;
|
||||
@@ -77,14 +81,14 @@ chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
|
||||
|
||||
//get messages from the background script and the popup
|
||||
chrome.runtime.onMessage.addListener(messageListener);
|
||||
|
||||
|
||||
function messageListener(request, sender, sendResponse) {
|
||||
//message from background script
|
||||
if (request.message == "ytvideoid") {
|
||||
videoIDChange(request.id);
|
||||
}
|
||||
|
||||
//messages from popup script
|
||||
|
||||
if (request.message == "update") {
|
||||
if(id = getYouTubeVideoID(document.URL)) videoIDChange(id);
|
||||
}
|
||||
|
||||
if (request.message == "sponsorStart") {
|
||||
sponsorMessageStarted(sendResponse);
|
||||
}
|
||||
@@ -115,6 +119,16 @@ 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
|
||||
@@ -179,11 +193,33 @@ document.onkeydown = function(e){
|
||||
}
|
||||
|
||||
function videoIDChange(id) {
|
||||
//not a url change
|
||||
if (sponsorVideoID == id){
|
||||
return;
|
||||
}
|
||||
|
||||
//not a url change
|
||||
if (sponsorVideoID == id) 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();
|
||||
|
||||
@@ -195,6 +231,7 @@ function videoIDChange(id) {
|
||||
sponsorTimes = null;
|
||||
UUIDs = null;
|
||||
sponsorVideoID = id;
|
||||
sponsorLookupRetries = 0;
|
||||
|
||||
//see if there is a video start time
|
||||
youtubeVideoStartTime = getYouTubeVideoStartTime(document.URL);
|
||||
@@ -275,7 +312,8 @@ function sponsorsLookup(id) {
|
||||
|
||||
getChannelID();
|
||||
|
||||
} else if (xmlhttp.readyState == 4) {
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (xmlhttp.readyState == 4 && xmlhttp.status == 404) {
|
||||
sponsorDataFound = false;
|
||||
|
||||
//check if this video was uploaded recently
|
||||
@@ -290,6 +328,13 @@ function sponsorsLookup(id) {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (xmlhttp.readyState == 4 && sponsorLookupRetries < 15) {
|
||||
//some error occurred, try again in a second
|
||||
setTimeout(() => sponsorsLookup(id), 1000);
|
||||
|
||||
sponsorLookupRetries++;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1048,6 +1093,9 @@ function sendSubmitMessage(){
|
||||
//clear the sponsor times
|
||||
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
||||
chrome.storage.sync.set({[sponsorTimeKey]: []});
|
||||
|
||||
//request the sponsors from the server again
|
||||
sponsorsLookup(currentVideoID);
|
||||
} else {
|
||||
//for a more detailed error message, they should check the popup
|
||||
//show that the upload failed
|
||||
@@ -1143,26 +1191,3 @@ function sendRequestToCustomServer(type, fullAddress, callback) {
|
||||
//submit this request
|
||||
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;
|
||||
}
|
||||
|
||||
//returns the start time of the video if there was one specified (ex. ?t=5s)
|
||||
function getYouTubeVideoStartTime(url) {
|
||||
let searchParams = new URL(url).searchParams;
|
||||
var startTime = searchParams.get("t");
|
||||
if (startTime == null) {
|
||||
startTime = searchParams.get("time_continue");
|
||||
}
|
||||
|
||||
return startTime;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "SponsorBlock for YouTube - Skip Sponsorships",
|
||||
"short_name": "SponsorBlock",
|
||||
"version": "1.0.29",
|
||||
"version": "1.0.33",
|
||||
"description": "Skip over sponsorship on YouTube videos. Report sponsors on videos you watch to save the time of others.",
|
||||
"content_scripts": [
|
||||
{
|
||||
@@ -11,6 +11,7 @@
|
||||
"all_frames": true,
|
||||
"js": [
|
||||
"config.js",
|
||||
"utils.js",
|
||||
"content.js",
|
||||
"popup.js"
|
||||
],
|
||||
@@ -32,12 +33,9 @@
|
||||
"icons/downvote.png",
|
||||
"icons/PlayerInfoIconSponsorBlocker256px.png",
|
||||
"icons/PlayerDeleteIconSponsorBlocker256px.png",
|
||||
"popup.html",
|
||||
"help/index.html",
|
||||
"help/style.css"
|
||||
"popup.html"
|
||||
],
|
||||
"permissions": [
|
||||
"tabs",
|
||||
"storage",
|
||||
"notifications",
|
||||
"https://sponsor.ajay.app/*"
|
||||
@@ -48,9 +46,11 @@
|
||||
},
|
||||
"background": {
|
||||
"scripts":[
|
||||
"utils.js",
|
||||
"config.js",
|
||||
"background.js"
|
||||
]
|
||||
],
|
||||
"persistent": false
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/IconSponsorBlocker16px.png",
|
||||
|
||||
10
popup.css
10
popup.css
@@ -80,8 +80,14 @@ h1.popupElement {
|
||||
|
||||
.mediumLink.popupElement {
|
||||
font-size: 15px;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
margin-left: 25px;
|
||||
margin-right: 25px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tinyLink.popupElement {
|
||||
font-size: 10px;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@
|
||||
|
||||
</div>
|
||||
</b>
|
||||
|
||||
<br/>
|
||||
|
||||
<button id="clearTimes" class="smallButton popupElement">Clear Times</button>
|
||||
|
||||
@@ -193,5 +195,6 @@
|
||||
|
||||
<!-- Scripts that need to load after the html -->
|
||||
<script src="config.js"></script>
|
||||
<script src="utils.js"></script>
|
||||
<script src="popup.js"></script>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
166
popup.js
166
popup.js
@@ -123,26 +123,6 @@ function runThePopup() {
|
||||
}
|
||||
});
|
||||
|
||||
//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";
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
//if the don't show notice again letiable is true, an option to
|
||||
// disable should be available
|
||||
chrome.storage.sync.get(["dontShowNoticeAgain"], function(result) {
|
||||
@@ -221,17 +201,25 @@ function runThePopup() {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
chrome.tabs.query({
|
||||
active: 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) {
|
||||
//set current videoID
|
||||
currentVideoID = getYouTubeVideoID(tabs[0].url);
|
||||
|
||||
if (!currentVideoID) {
|
||||
//this isn't a YouTube video then
|
||||
displayNoVideo();
|
||||
@@ -292,6 +280,26 @@ function runThePopup() {
|
||||
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) {
|
||||
@@ -465,8 +473,11 @@ function runThePopup() {
|
||||
let index = i;
|
||||
deleteButton.addEventListener("click", () => deleteSponsorTime(index));
|
||||
|
||||
let spacer = document.createElement("span");
|
||||
spacer.innerText = " ";
|
||||
let previewButton = document.createElement("span");
|
||||
previewButton.id = "sponsorTimePreviewButton" + i;
|
||||
previewButton.innerText = "Preview";
|
||||
previewButton.className = "mediumLink popupElement";
|
||||
previewButton.addEventListener("click", () => previewSponsorTime(index));
|
||||
|
||||
let editButton = document.createElement("span");
|
||||
editButton.id = "sponsorTimeEditButton" + i;
|
||||
@@ -488,19 +499,46 @@ function runThePopup() {
|
||||
}
|
||||
|
||||
currentSponsorTimeContainer.innerText = currentSponsorTimeMessage;
|
||||
currentSponsorTimeContainer.addEventListener("click", () => editSponsorTime(index));
|
||||
|
||||
sponsorTimesContainer.appendChild(currentSponsorTimeContainer);
|
||||
sponsorTimesContainer.appendChild(deleteButton);
|
||||
|
||||
//only if it is a complete sponsor time
|
||||
if (sponsorTimes[i].length > 1) {
|
||||
sponsorTimesContainer.appendChild(previewButton);
|
||||
sponsorTimesContainer.appendChild(editButton);
|
||||
|
||||
currentSponsorTimeContainer.addEventListener("click", () => editSponsorTime(index));
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (document.getElementById("startTimeMinutes" + index) != null) {
|
||||
@@ -513,6 +551,13 @@ function runThePopup() {
|
||||
|
||||
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
|
||||
let startTimeMinutes = document.createElement("input");
|
||||
startTimeMinutes.id = "startTimeMinutes" + index;
|
||||
@@ -527,7 +572,7 @@ function runThePopup() {
|
||||
startTimeSeconds.type = "text";
|
||||
startTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][0]);
|
||||
startTimeSeconds.style.width = "60px";
|
||||
|
||||
|
||||
let endTimeMinutes = document.createElement("input");
|
||||
endTimeMinutes.id = "endTimeMinutes" + index;
|
||||
endTimeMinutes.className = "sponsorTime popupElement";
|
||||
@@ -541,6 +586,13 @@ function runThePopup() {
|
||||
endTimeSeconds.type = "text";
|
||||
endTimeSeconds.value = getTimeInFormattedSeconds(sponsorTimes[index][1]);
|
||||
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");
|
||||
colonText.innerText = ":";
|
||||
@@ -553,6 +605,7 @@ function runThePopup() {
|
||||
sponsorTimeContainer.removeChild(sponsorTimeContainer.firstChild);
|
||||
}
|
||||
|
||||
sponsorTimeContainer.appendChild(startTimeNowButton);
|
||||
sponsorTimeContainer.appendChild(startTimeMinutes);
|
||||
sponsorTimeContainer.appendChild(colonText);
|
||||
sponsorTimeContainer.appendChild(startTimeSeconds);
|
||||
@@ -560,6 +613,7 @@ function runThePopup() {
|
||||
sponsorTimeContainer.appendChild(endTimeMinutes);
|
||||
sponsorTimeContainer.appendChild(colonText);
|
||||
sponsorTimeContainer.appendChild(endTimeSeconds);
|
||||
sponsorTimeContainer.appendChild(endTimeNowButton);
|
||||
|
||||
//add save button and remove edit button
|
||||
let saveButton = document.createElement("span");
|
||||
@@ -573,16 +627,37 @@ function runThePopup() {
|
||||
|
||||
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) {
|
||||
let startTimeMinutes = document.getElementById("startTimeMinutes" + index);
|
||||
let startTimeSeconds = document.getElementById("startTimeSeconds" + 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);
|
||||
function saveSponsorTimeEdit(index, closeEditMode = true) {
|
||||
sponsorTimes[index][0] = getSponsorTimeEditTimes("startTime", index);
|
||||
sponsorTimes[index][1] = getSponsorTimeEditTimes("endTime", index);
|
||||
|
||||
//save this
|
||||
let sponsorTimeKey = "sponsorTimes" + currentVideoID;
|
||||
@@ -598,9 +673,11 @@ function runThePopup() {
|
||||
});
|
||||
});
|
||||
|
||||
displaySponsorTimes();
|
||||
if (closeEditMode) {
|
||||
displaySponsorTimes();
|
||||
|
||||
showSubmitTimesIfNecessary();
|
||||
showSubmitTimesIfNecessary();
|
||||
}
|
||||
}
|
||||
|
||||
//deletes the sponsor time submitted at an index
|
||||
@@ -1127,13 +1204,6 @@ function runThePopup() {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1143,4 +1213,4 @@ if (chrome.tabs != undefined) {
|
||||
|
||||
//this means it is actually opened in the popup
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user