mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-14 15:37:12 +03:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f30b9ec84 | ||
|
|
50862e3c03 | ||
|
|
20e90bbc34 | ||
|
|
2e212e6d10 | ||
|
|
2039bfa081 | ||
|
|
7dc8a99247 | ||
|
|
1b25ea7f95 | ||
|
|
1869382166 | ||
|
|
d58cd639c7 | ||
|
|
6cd2d4cf83 | ||
|
|
b681f5abd9 | ||
|
|
5b2a0feccf | ||
|
|
cd58f6bc73 | ||
|
|
aeabf806ac | ||
|
|
af7ba31c2f | ||
|
|
5b962b1b9d | ||
|
|
219a7ba8c3 | ||
|
|
933babb4e6 | ||
|
|
023ba2e051 | ||
|
|
1c833a8b1d |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
|||||||
run: npm run build:chrome
|
run: npm run build:chrome
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: Chrome Extension
|
name: ChromeExtension
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
# Create Firefox artifacts
|
# Create Firefox artifacts
|
||||||
@@ -29,6 +29,6 @@ jobs:
|
|||||||
run: npm run build:firefox
|
run: npm run build:firefox
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: Firefox Extension
|
name: FirefoxExtension
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "__MSG_fullName__",
|
"name": "__MSG_fullName__",
|
||||||
"short_name": "__MSG_Name__",
|
"short_name": "__MSG_Name__",
|
||||||
"version": "1.2.13",
|
"version": "1.2.14",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"description": "__MSG_Description__",
|
"description": "__MSG_Description__",
|
||||||
"content_scripts": [{
|
"content_scripts": [{
|
||||||
|
|||||||
398
src/content.ts
398
src/content.ts
@@ -15,11 +15,17 @@ utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
|
|||||||
var sponsorDataFound = false;
|
var sponsorDataFound = false;
|
||||||
var previousVideoID = null;
|
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: number[][] = null;
|
||||||
var UUIDs = [];
|
var UUIDs = [];
|
||||||
//what video id are these sponsors for
|
//what video id are these sponsors for
|
||||||
var sponsorVideoID = null;
|
var sponsorVideoID = null;
|
||||||
|
|
||||||
|
// Skips are scheduled to ensure precision.
|
||||||
|
// Skips are rescheduled every seeked event.
|
||||||
|
// Skips are canceled every seeking event
|
||||||
|
var currentSkipSchedule: NodeJS.Timeout = null;
|
||||||
|
var seekListenerSetUp = false
|
||||||
|
|
||||||
//these are sponsors that have been downvoted
|
//these are sponsors that have been downvoted
|
||||||
var hiddenSponsorTimes = [];
|
var hiddenSponsorTimes = [];
|
||||||
|
|
||||||
@@ -30,12 +36,15 @@ var sponsorSkipped = [];
|
|||||||
var video: HTMLVideoElement;
|
var video: HTMLVideoElement;
|
||||||
|
|
||||||
var onInvidious;
|
var onInvidious;
|
||||||
|
var onMobileYouTube;
|
||||||
|
|
||||||
//the video id of the last preview bar update
|
//the video id of the last preview bar update
|
||||||
var lastPreviewBarUpdate;
|
var lastPreviewBarUpdate;
|
||||||
|
|
||||||
//whether the duration listener listening for the duration changes of the video has been setup yet
|
//whether the duration listener listening for the duration changes of the video has been setup yet
|
||||||
var durationListenerSetUp = false;
|
var durationListenerSetUp = false;
|
||||||
|
// Timestamp of the last duration change
|
||||||
|
var lastDurationChange = 0;
|
||||||
|
|
||||||
//the channel this video is about
|
//the channel this video is about
|
||||||
var channelURL;
|
var channelURL;
|
||||||
@@ -47,7 +56,7 @@ var title;
|
|||||||
var channelWhitelisted = false;
|
var channelWhitelisted = false;
|
||||||
|
|
||||||
// create preview bar
|
// create preview bar
|
||||||
var previewBar = null;
|
var previewBar: PreviewBar = null;
|
||||||
|
|
||||||
// When not null, a sponsor is currently being previewed and auto skip should be enabled.
|
// When not null, a sponsor is currently being previewed and auto skip should be enabled.
|
||||||
// This is set to a timeout function when that happens that will reset it after 3 seconds.
|
// This is set to a timeout function when that happens that will reset it after 3 seconds.
|
||||||
@@ -92,7 +101,8 @@ var skipNoticeContentContainer = () => ({
|
|||||||
v: video,
|
v: video,
|
||||||
reskipSponsorTime,
|
reskipSponsorTime,
|
||||||
hiddenSponsorTimes,
|
hiddenSponsorTimes,
|
||||||
updatePreviewBar
|
updatePreviewBar,
|
||||||
|
onMobileYouTube
|
||||||
});
|
});
|
||||||
|
|
||||||
//get messages from the background script and the popup
|
//get messages from the background script and the popup
|
||||||
@@ -255,7 +265,7 @@ async function videoIDChange(id) {
|
|||||||
sponsorVideoID = id;
|
sponsorVideoID = id;
|
||||||
|
|
||||||
resetValues();
|
resetValues();
|
||||||
|
|
||||||
//id is not valid
|
//id is not valid
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
@@ -278,26 +288,19 @@ async function videoIDChange(id) {
|
|||||||
channelIDPromise.then(() => channelIDPromise.isFulfilled = true).catch(() => channelIDPromise.isRejected = true);
|
channelIDPromise.then(() => channelIDPromise.isFulfilled = true).catch(() => channelIDPromise.isRejected = true);
|
||||||
|
|
||||||
//setup the preview bar
|
//setup the preview bar
|
||||||
if (previewBar == null) {
|
if (previewBar === null) {
|
||||||
//create it
|
if (onMobileYouTube) {
|
||||||
utils.wait(getControls).then(result => {
|
// Mobile YouTube workaround
|
||||||
const progressElementSelectors = [
|
const observer = new MutationObserver(handleMobileControlsMutations);
|
||||||
// For YouTube
|
|
||||||
"ytp-progress-bar-container",
|
|
||||||
"no-model cue-range-markers",
|
|
||||||
// For Invidious/VideoJS
|
|
||||||
"vjs-progress-holder"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const selector of progressElementSelectors) {
|
observer.observe(document.getElementById("player-control-container"), {
|
||||||
const el = document.getElementsByClassName(selector);
|
attributes: true,
|
||||||
|
childList: true,
|
||||||
if (el && el.length && el[0]) {
|
subtree: true
|
||||||
previewBar = new PreviewBar(el[0]);
|
});
|
||||||
break;
|
} else {
|
||||||
}
|
utils.wait(getControls).then(createPreviewBar);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//warn them if they had unsubmitted times
|
//warn them if they had unsubmitted times
|
||||||
@@ -354,15 +357,120 @@ async function videoIDChange(id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
//see if video controls buttons should be added
|
//see if video controls buttons should be added
|
||||||
if (!onInvidious) {
|
if (!onInvidious) {
|
||||||
updateVisibilityOfPlayerControlsButton();
|
updateVisibilityOfPlayerControlsButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sponsorsLookup(id: string, channelIDPromise?) {
|
function handleMobileControlsMutations(): void {
|
||||||
|
let mobileYouTubeSelector = ".progress-bar-background";
|
||||||
|
|
||||||
|
updateVisibilityOfPlayerControlsButton().then((createdButtons) => {
|
||||||
|
if (createdButtons) {
|
||||||
|
if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length >= 2) {
|
||||||
|
changeStartSponsorButton(true, true);
|
||||||
|
} else if (sponsorTimesSubmitting != null && sponsorTimesSubmitting.length > 0 && sponsorTimesSubmitting[sponsorTimesSubmitting.length - 1].length < 2) {
|
||||||
|
changeStartSponsorButton(false, true);
|
||||||
|
} else {
|
||||||
|
changeStartSponsorButton(true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (previewBar !== null) {
|
||||||
|
if (document.body.contains(previewBar.container)) {
|
||||||
|
updatePreviewBarPositionMobile(document.getElementsByClassName(mobileYouTubeSelector)[0]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// The container does not exist anymore, remove that old preview bar
|
||||||
|
previewBar.remove();
|
||||||
|
previewBar = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the preview bar if needed (the function hasn't returned yet)
|
||||||
|
createPreviewBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a preview bar on the video
|
||||||
|
*/
|
||||||
|
function createPreviewBar(): void {
|
||||||
|
if (previewBar !== null) return;
|
||||||
|
|
||||||
|
const progressElementSelectors = [
|
||||||
|
// For mobile YouTube
|
||||||
|
".progress-bar-background",
|
||||||
|
// For YouTube
|
||||||
|
".ytp-progress-bar-container",
|
||||||
|
".no-model.cue-range-markers",
|
||||||
|
// For Invidious/VideoJS
|
||||||
|
".vjs-progress-holder"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const selector of progressElementSelectors) {
|
||||||
|
const el = document.querySelectorAll(selector);
|
||||||
|
|
||||||
|
if (el && el.length && el[0]) {
|
||||||
|
previewBar = new PreviewBar(el[0], onMobileYouTube);
|
||||||
|
|
||||||
|
updatePreviewBar();
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggered every time the video duration changes.
|
||||||
|
* This happens when the resolution changes or at random time to clear memory.
|
||||||
|
*/
|
||||||
|
function durationChangeListener() {
|
||||||
|
lastDurationChange = Date.now();
|
||||||
|
|
||||||
|
updatePreviewBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelSponsorSchedule(): void {
|
||||||
|
if (currentSkipSchedule !== null) {
|
||||||
|
clearTimeout(currentSkipSchedule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param currentTime Optional if you don't want to use the actual current time
|
||||||
|
*/
|
||||||
|
function startSponsorSchedule(currentTime?: number): void {
|
||||||
|
cancelSponsorSchedule();
|
||||||
|
|
||||||
|
if (sponsorTimes === null || Config.config.disableSkipping || channelWhitelisted){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentTime === undefined) currentTime = video.currentTime;
|
||||||
|
|
||||||
|
let skipInfo = getNextSkipIndex(currentTime);
|
||||||
|
|
||||||
|
let skipTime = skipInfo.array[skipInfo.index];
|
||||||
|
let timeUntilSponsor = skipTime[0] - currentTime;
|
||||||
|
|
||||||
|
currentSkipSchedule = setTimeout(() => {
|
||||||
|
if (video.currentTime >= skipTime[0] && video.currentTime < skipTime[1]) {
|
||||||
|
skipToTime(video, skipInfo.index, skipInfo.array, skipInfo.openNotice);
|
||||||
|
|
||||||
|
startSponsorSchedule();
|
||||||
|
} else {
|
||||||
|
startSponsorSchedule();
|
||||||
|
}
|
||||||
|
}, timeUntilSponsor * 1000 * (1 / video.playbackRate));
|
||||||
|
}
|
||||||
|
|
||||||
|
function sponsorsLookup(id: string, channelIDPromise?) {
|
||||||
video = document.querySelector('video') // Youtube video player
|
video = document.querySelector('video') // Youtube video player
|
||||||
//there is no video here
|
//there is no video here
|
||||||
if (video == null) {
|
if (video == null) {
|
||||||
@@ -374,7 +482,17 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
durationListenerSetUp = true;
|
durationListenerSetUp = true;
|
||||||
|
|
||||||
//wait until it is loaded
|
//wait until it is loaded
|
||||||
video.addEventListener('durationchange', updatePreviewBar);
|
video.addEventListener('durationchange', durationChangeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!seekListenerSetUp && !Config.config.disableSkipping) {
|
||||||
|
seekListenerSetUp = true;
|
||||||
|
|
||||||
|
video.addEventListener('seeked', () => startSponsorSchedule());
|
||||||
|
video.addEventListener('play', () => startSponsorSchedule());
|
||||||
|
video.addEventListener('ratechange', () => startSponsorSchedule());
|
||||||
|
video.addEventListener('seeking', cancelSponsorSchedule);
|
||||||
|
video.addEventListener('pause', cancelSponsorSchedule);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channelIDPromise !== undefined) {
|
if (channelIDPromise !== undefined) {
|
||||||
@@ -427,6 +545,29 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
UUIDs = smallUUIDs;
|
UUIDs = smallUUIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See if there are any zero second sponsors
|
||||||
|
let zeroSecondSponsor = false;
|
||||||
|
for (const time of sponsorTimes) {
|
||||||
|
if (time[0] <= 0) {
|
||||||
|
zeroSecondSponsor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!zeroSecondSponsor) {
|
||||||
|
for (const time of sponsorTimesSubmitting) {
|
||||||
|
if (time[0] <= 0) {
|
||||||
|
zeroSecondSponsor = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zeroSecondSponsor) {
|
||||||
|
startSponsorSchedule(0);
|
||||||
|
} else {
|
||||||
|
startSponsorSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
// Reset skip save
|
// Reset skip save
|
||||||
sponsorSkipped = [];
|
sponsorSkipped = [];
|
||||||
|
|
||||||
@@ -474,13 +615,6 @@ function sponsorsLookup(id: string, channelIDPromise?) {
|
|||||||
sponsorLookupRetries++;
|
sponsorLookupRetries++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
//add the event to run on the videos "ontimeupdate"
|
|
||||||
if (!Config.config.disableSkipping) {
|
|
||||||
video.ontimeupdate = function () {
|
|
||||||
sponsorCheck();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getYouTubeVideoID(url: string) {
|
function getYouTubeVideoID(url: string) {
|
||||||
@@ -499,7 +633,9 @@ function getYouTubeVideoID(url: string) {
|
|||||||
// Check if valid hostname
|
// Check if valid hostname
|
||||||
if (Config.config && Config.config.invidiousInstances.includes(urlObject.host)) {
|
if (Config.config && Config.config.invidiousInstances.includes(urlObject.host)) {
|
||||||
onInvidious = true;
|
onInvidious = true;
|
||||||
} else if (!["www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) {
|
} else if (urlObject.host === "m.youtube.com") {
|
||||||
|
onMobileYouTube = true;
|
||||||
|
} else if (!["m.youtube.com", "www.youtube.com", "www.youtube-nocookie.com"].includes(urlObject.host)) {
|
||||||
if (!Config.config) {
|
if (!Config.config) {
|
||||||
// Call this later, in case this is an Invidious tab
|
// Call this later, in case this is an Invidious tab
|
||||||
utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoID(url)));
|
utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoID(url)));
|
||||||
@@ -572,6 +708,15 @@ function getChannelID() {
|
|||||||
channelWhitelisted = false;
|
channelWhitelisted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is required on mobile YouTube and will keep getting called whenever the preview bar disapears
|
||||||
|
*/
|
||||||
|
function updatePreviewBarPositionMobile(parent: Element) {
|
||||||
|
if (document.getElementById("previewbar") === null) {
|
||||||
|
previewBar.updatePosition(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updatePreviewBar() {
|
function updatePreviewBar() {
|
||||||
let localSponsorTimes = sponsorTimes;
|
let localSponsorTimes = sponsorTimes;
|
||||||
if (localSponsorTimes == null) localSponsorTimes = [];
|
if (localSponsorTimes == null) localSponsorTimes = [];
|
||||||
@@ -608,73 +753,56 @@ function whitelistCheck() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//video skipping
|
/**
|
||||||
function sponsorCheck() {
|
* Returns info about the next upcoming sponsor skip
|
||||||
if (Config.config.disableSkipping) {
|
*/
|
||||||
// Make sure this isn't called again
|
function getNextSkipIndex(currentTime: number): {array: number[][], index: number, openNotice: boolean} {
|
||||||
video.ontimeupdate = null;
|
let sponsorStartTimes = getStartTimes(sponsorTimes);
|
||||||
return;
|
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true);
|
||||||
} else if (channelWhitelisted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let skipHappened = false;
|
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
|
||||||
|
|
||||||
if (sponsorTimes != null) {
|
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting);
|
||||||
//see if any sponsor start time was just passed
|
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false);
|
||||||
for (let i = 0; i < sponsorTimes.length; i++) {
|
|
||||||
//if something was skipped
|
|
||||||
if (checkSponsorTime(sponsorTimes, i, true)) {
|
|
||||||
skipHappened = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!skipHappened) {
|
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
|
||||||
//check for the "preview" sponsors (currently edited by this user)
|
|
||||||
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
|
|
||||||
//must be a finished sponsor and be valid
|
|
||||||
if (sponsorTimesSubmitting[i].length > 1 && sponsorTimesSubmitting[i][1] > sponsorTimesSubmitting[i][0]) {
|
|
||||||
checkSponsorTime(sponsorTimesSubmitting, i, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//don't keep track until they are loaded in
|
if (minPreviewSponsorTimeIndex == -1 || sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
|
||||||
if (sponsorTimes !== null || sponsorTimesSubmitting.length > 0) {
|
return {
|
||||||
lastTime = video.currentTime;
|
array: sponsorTimes,
|
||||||
|
index: minSponsorTimeIndex,
|
||||||
|
openNotice: true
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
array: sponsorTimesSubmitting,
|
||||||
|
index: minPreviewSponsorTimeIndex,
|
||||||
|
openNotice: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkSponsorTime(sponsorTimes, index, openNotice): boolean {
|
/**
|
||||||
//this means part of the video was just skipped
|
* Gets just the start times from a sponsor times array.
|
||||||
if (Math.abs(video.currentTime - lastTime) > 1 && lastTime != -1) {
|
* Optionally specify a minimum
|
||||||
//make lastTime as if the video was playing normally
|
*
|
||||||
lastTime = video.currentTime - 0.0001;
|
* @param sponsorTimes
|
||||||
|
* @param minimum
|
||||||
|
* @param hideHiddenSponsors
|
||||||
|
*/
|
||||||
|
function getStartTimes(sponsorTimes: number[][], minimum?: number, hideHiddenSponsors: boolean = false): number[] {
|
||||||
|
let startTimes: number[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < sponsorTimes.length; i++) {
|
||||||
|
if ((minimum === undefined || sponsorTimes[i][0] >= minimum) && (!hideHiddenSponsors || !hiddenSponsorTimes.includes(i))) {
|
||||||
|
startTimes.push(sponsorTimes[i][0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkIfTimeToSkip(video.currentTime, sponsorTimes[index][0], sponsorTimes[index][1]) && !hiddenSponsorTimes.includes(index)) {
|
return startTimes;
|
||||||
//skip it
|
|
||||||
skipToTime(video, index, sponsorTimes, openNotice);
|
|
||||||
|
|
||||||
//something was skipped
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkIfTimeToSkip(currentVideoTime, startTime, endTime) {
|
//skip from fhe start time to the end time for a certain index sponsor time
|
||||||
//If the sponsor time is in between these times, skip it
|
|
||||||
//Checks if the last time skipped to is not too close to now, to make sure not to get too many
|
|
||||||
// sponsor times in a row (from one troll)
|
|
||||||
//the last term makes 0 second start times possible only if the video is not setup to start at a different time from zero
|
|
||||||
return (Math.abs(currentVideoTime - startTime) < 3 && startTime >= lastTime && startTime <= currentVideoTime) ||
|
|
||||||
(lastTime == -1 && startTime == 0 && currentVideoTime < endTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
//skip fromt he start time to the end time for a certain index sponsor time
|
|
||||||
function skipToTime(v, index, sponsorTimes, openNotice) {
|
function skipToTime(v, index, sponsorTimes, openNotice) {
|
||||||
if (!Config.config.disableAutoSkip || previewResetter !== null) {
|
if (!Config.config.disableAutoSkip || previewResetter !== null) {
|
||||||
v.currentTime = sponsorTimes[index][1];
|
v.currentTime = sponsorTimes[index][1];
|
||||||
@@ -725,16 +853,27 @@ function reskipSponsorTime(UUID) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function createButton(baseID, title, callback, imageName, isDraggable=false) {
|
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
|
||||||
if (document.getElementById(baseID + "Button") != null) return;
|
if (document.getElementById(baseID + "Button") != null) return false;
|
||||||
|
|
||||||
// Button HTML
|
// Button HTML
|
||||||
let newButton = document.createElement("button");
|
let newButton = document.createElement("button");
|
||||||
newButton.draggable = isDraggable;
|
newButton.draggable = isDraggable;
|
||||||
newButton.id = baseID + "Button";
|
newButton.id = baseID + "Button";
|
||||||
newButton.className = "ytp-button playerButton";
|
newButton.classList.add("playerButton");
|
||||||
|
if (!onMobileYouTube) {
|
||||||
|
newButton.classList.add("ytp-button");
|
||||||
|
} else {
|
||||||
|
newButton.classList.add("icon-button");
|
||||||
|
newButton.style.padding = "0";
|
||||||
|
}
|
||||||
newButton.setAttribute("title", chrome.i18n.getMessage(title));
|
newButton.setAttribute("title", chrome.i18n.getMessage(title));
|
||||||
newButton.addEventListener("click", callback);
|
newButton.addEventListener("click", (event: Event) => {
|
||||||
|
callback();
|
||||||
|
|
||||||
|
// Prevents the contols from closing when clicked
|
||||||
|
if (onMobileYouTube) event.stopPropagation();
|
||||||
|
});
|
||||||
|
|
||||||
// Image HTML
|
// Image HTML
|
||||||
let newButtonImage = document.createElement("img");
|
let newButtonImage = document.createElement("img");
|
||||||
@@ -748,40 +887,56 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) {
|
|||||||
|
|
||||||
// Add the button to player
|
// Add the button to player
|
||||||
controls.prepend(newButton);
|
controls.prepend(newButton);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getControls() {
|
function getControls(): HTMLElement | boolean {
|
||||||
let controls = document.getElementsByClassName("ytp-right-controls");
|
let controlsSelectors = [
|
||||||
|
// YouTube
|
||||||
|
".ytp-right-controls",
|
||||||
|
// Mobile YouTube
|
||||||
|
".player-controls-top",
|
||||||
|
// Invidious/videojs video element's controls element
|
||||||
|
".vjs-control-bar"
|
||||||
|
]
|
||||||
|
|
||||||
if (!controls || controls.length === 0) {
|
for (const controlsSelector of controlsSelectors) {
|
||||||
// The invidious video element's controls element
|
let controls = document.querySelectorAll(controlsSelector);
|
||||||
controls = document.getElementsByClassName("vjs-control-bar");
|
|
||||||
return (!controls || controls.length === 0) ? false : controls[controls.length - 1];
|
if (controls && controls.length > 0) {
|
||||||
} else {
|
return <HTMLElement> controls[controls.length - 1];
|
||||||
return controls[controls.length - 1];
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
//adds all the player controls buttons
|
//adds all the player controls buttons
|
||||||
async function createButtons() {
|
async function createButtons(): Promise<boolean> {
|
||||||
let result = await utils.wait(getControls).catch();
|
let result = await utils.wait(getControls).catch();
|
||||||
|
|
||||||
//set global controls variable
|
//set global controls variable
|
||||||
controls = result;
|
controls = result;
|
||||||
|
|
||||||
// Add button if does not already exist in html
|
let createdButton = false;
|
||||||
createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png");
|
|
||||||
createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png")
|
// Add button if does not already exist in html
|
||||||
createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png");
|
createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton;
|
||||||
createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png");
|
createdButton = createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") || createdButton;
|
||||||
}
|
createdButton = createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png") || createdButton;
|
||||||
//adds or removes the player controls button to what it should be
|
createdButton = createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png") || createdButton;
|
||||||
async function updateVisibilityOfPlayerControlsButton() {
|
|
||||||
//not on a proper video yet
|
return createdButton;
|
||||||
if (!sponsorVideoID) return;
|
}
|
||||||
|
|
||||||
|
//adds or removes the player controls button to what it should be
|
||||||
|
async function updateVisibilityOfPlayerControlsButton(): Promise<boolean> {
|
||||||
|
//not on a proper video yet
|
||||||
|
if (!sponsorVideoID) return false;
|
||||||
|
|
||||||
|
let createdButtons = await createButtons();
|
||||||
|
|
||||||
await createButtons();
|
|
||||||
|
|
||||||
if (Config.config.hideVideoPlayerControls || onInvidious) {
|
if (Config.config.hideVideoPlayerControls || onInvidious) {
|
||||||
document.getElementById("startSponsorButton").style.display = "none";
|
document.getElementById("startSponsorButton").style.display = "none";
|
||||||
document.getElementById("submitButton").style.display = "none";
|
document.getElementById("submitButton").style.display = "none";
|
||||||
@@ -799,6 +954,8 @@ async function updateVisibilityOfPlayerControlsButton() {
|
|||||||
if (Config.config.hideDeleteButtonPlayerControls || onInvidious) {
|
if (Config.config.hideDeleteButtonPlayerControls || onInvidious) {
|
||||||
document.getElementById("deleteButton").style.display = "none";
|
document.getElementById("deleteButton").style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createdButtons;
|
||||||
}
|
}
|
||||||
|
|
||||||
function startSponsorClicked() {
|
function startSponsorClicked() {
|
||||||
@@ -831,22 +988,17 @@ function updateSponsorTimesSubmitting() {
|
|||||||
sponsorTimesSubmitting = sponsorTimes;
|
sponsorTimesSubmitting = sponsorTimes;
|
||||||
|
|
||||||
updatePreviewBar();
|
updatePreviewBar();
|
||||||
|
|
||||||
|
// Restart skipping schedule
|
||||||
|
startSponsorSchedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//is the submit button on the player loaded yet
|
|
||||||
function isSubmitButtonLoaded() {
|
|
||||||
return document.getElementById("submitButton") !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
async function changeStartSponsorButton(showStartSponsor, uploadButtonVisible) {
|
||||||
if(!sponsorVideoID) return false;
|
if(!sponsorVideoID) return false;
|
||||||
|
|
||||||
//make sure submit button is loaded
|
|
||||||
await utils.wait(isSubmitButtonLoaded);
|
|
||||||
|
|
||||||
//if it isn't visible, there is no data
|
//if it isn't visible, there is no data
|
||||||
let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
|
let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
|
||||||
document.getElementById("deleteButton").style.display = shouldHide;
|
document.getElementById("deleteButton").style.display = shouldHide;
|
||||||
|
|||||||
@@ -23,18 +23,30 @@ let barTypes = {
|
|||||||
class PreviewBar {
|
class PreviewBar {
|
||||||
container: HTMLUListElement;
|
container: HTMLUListElement;
|
||||||
parent: any;
|
parent: any;
|
||||||
|
onMobileYouTube: boolean;
|
||||||
|
|
||||||
constructor(parent) {
|
constructor(parent, onMobileYouTube) {
|
||||||
this.container = document.createElement('ul');
|
this.container = document.createElement('ul');
|
||||||
this.container.id = 'previewbar';
|
this.container.id = 'previewbar';
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
|
||||||
this.updatePosition();
|
this.onMobileYouTube = onMobileYouTube;
|
||||||
|
|
||||||
|
this.updatePosition(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePosition() {
|
updatePosition(parent) {
|
||||||
//below the seek bar
|
//below the seek bar
|
||||||
// this.parent.insertAdjacentElement("afterEnd", this.container);
|
// this.parent.insertAdjacentElement("afterEnd", this.container);
|
||||||
|
|
||||||
|
this.parent = parent;
|
||||||
|
|
||||||
|
if (this.onMobileYouTube) {
|
||||||
|
parent.style.backgroundColor = "rgba(255, 255, 255, 0.3)";
|
||||||
|
parent.style.opacity = "1";
|
||||||
|
|
||||||
|
this.container.style.transform = "none";
|
||||||
|
}
|
||||||
|
|
||||||
//on the seek bar
|
//on the seek bar
|
||||||
this.parent.insertAdjacentElement("afterBegin", this.container);
|
this.parent.insertAdjacentElement("afterBegin", this.container);
|
||||||
@@ -70,7 +82,7 @@ class PreviewBar {
|
|||||||
bar.setAttribute('data-vs-segment-type', types[i]);
|
bar.setAttribute('data-vs-segment-type', types[i]);
|
||||||
|
|
||||||
bar.style.backgroundColor = barTypes[types[i]].color;
|
bar.style.backgroundColor = barTypes[types[i]].color;
|
||||||
bar.style.opacity = barTypes[types[i]].opacity;
|
if (!this.onMobileYouTube) bar.style.opacity = barTypes[types[i]].opacity;
|
||||||
bar.style.width = width + '%';
|
bar.style.width = width + '%';
|
||||||
bar.style.left = (timestamps[i][0] / duration * 100) + "%";
|
bar.style.left = (timestamps[i][0] / duration * 100) + "%";
|
||||||
bar.style.position = "absolute"
|
bar.style.position = "absolute"
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ class SkipNotice {
|
|||||||
noticeElement.classList.add("sponsorSkipObject");
|
noticeElement.classList.add("sponsorSkipObject");
|
||||||
noticeElement.classList.add("sponsorSkipNotice");
|
noticeElement.classList.add("sponsorSkipNotice");
|
||||||
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
|
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
|
||||||
|
if (contentContainer().onMobileYouTube) {
|
||||||
|
noticeElement.style.bottom = "4em";
|
||||||
|
noticeElement.style.zoom = "0.8";
|
||||||
|
}
|
||||||
|
|
||||||
//add mouse enter and leave listeners
|
//add mouse enter and leave listeners
|
||||||
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
|
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
|
||||||
@@ -173,7 +177,8 @@ class SkipNotice {
|
|||||||
noticeElement.appendChild(secondRow);
|
noticeElement.appendChild(secondRow);
|
||||||
|
|
||||||
//get reference node
|
//get reference node
|
||||||
let referenceNode = document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
let referenceNode = document.getElementById("player-container-id")
|
||||||
|
|| document.getElementById("movie_player") || document.querySelector("#player-container .video-js");
|
||||||
if (referenceNode == null) {
|
if (referenceNode == null) {
|
||||||
//for embeds
|
//for embeds
|
||||||
let player = document.getElementById("player");
|
let player = document.getElementById("player");
|
||||||
|
|||||||
23
src/popup.ts
23
src/popup.ts
@@ -719,17 +719,8 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
sponsorTimes.splice(index, 1);
|
sponsorTimes.splice(index, 1);
|
||||||
|
|
||||||
//save this
|
//save this
|
||||||
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
|
||||||
messageHandler.query({
|
|
||||||
active: true,
|
|
||||||
currentWindow: true
|
|
||||||
}, tabs => {
|
|
||||||
messageHandler.sendMessage(
|
|
||||||
tabs[0].id,
|
|
||||||
{message: "sponsorDataChanged"}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
//update display
|
//update display
|
||||||
displaySponsorTimes();
|
displaySponsorTimes();
|
||||||
|
|
||||||
@@ -750,6 +741,16 @@ async function runThePopup(messageListener?: MessageListener) {
|
|||||||
//hide submission section
|
//hide submission section
|
||||||
document.getElementById("submissionSection").style.display = "none";
|
document.getElementById("submissionSection").style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageHandler.query({
|
||||||
|
active: true,
|
||||||
|
currentWindow: true
|
||||||
|
}, tabs => {
|
||||||
|
messageHandler.sendMessage(
|
||||||
|
tabs[0].id,
|
||||||
|
{message: "sponsorDataChanged"}
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearTimes() {
|
function clearTimes() {
|
||||||
|
|||||||
Reference in New Issue
Block a user