Compare commits

...

35 Commits

Author SHA1 Message Date
Ajay Ramachandran
1f30b9ec84 Merge pull request #280 from ajayyy/mobile-youtube
Mobile YouTube support + Precise skipping
2020-02-19 11:40:07 -05:00
Ajay Ramachandran
50862e3c03 Increased version number 2020-02-19 11:25:14 -05:00
Ajay Ramachandran
20e90bbc34 Fixed schedule not updating when new sponsors arrive 2020-02-19 00:54:30 -05:00
Ajay Ramachandran
2e212e6d10 Improved mobile preview bar 2020-02-19 00:14:08 -05:00
Ajay Ramachandran
2039bfa081 Made buttons on mobile not close the menu. 2020-02-19 00:10:05 -05:00
Ajay Ramachandran
7dc8a99247 Added button support to mobile. 2020-02-19 00:00:22 -05:00
Ajay Ramachandran
1b25ea7f95 Shrunk notice on mobile 2020-02-18 19:29:20 -05:00
Ajay Ramachandran
1869382166 Fixed popup issues. 2020-02-18 19:03:34 -05:00
Ajay Ramachandran
d58cd639c7 Added zero second preview sponsors. 2020-02-18 18:45:33 -05:00
Ajay Ramachandran
6cd2d4cf83 Added back whitelist support 2020-02-18 18:44:06 -05:00
Ajay Ramachandran
b681f5abd9 Added support for preview sponsors in new skipping method. 2020-02-18 18:43:45 -05:00
Ajay Ramachandran
5b2a0feccf Switched to new skipping mechanic 2020-02-18 18:29:02 -05:00
Ajay Ramachandran
cd58f6bc73 Skip notice improvement. 2020-02-18 15:57:40 -05:00
Ajay Ramachandran
aeabf806ac Added duration change listener check to prevent mid-video zero second skips.
Sometimes the video gets reset to zero seconds for a few milliseconds, this should not trigger a skip.

Resolves https://github.com/ajayyy/SponsorBlock/issues/183
2020-02-18 15:03:55 -05:00
Ajay Ramachandran
af7ba31c2f Remove logging. 2020-02-18 14:40:40 -05:00
Ajay Ramachandran
5b962b1b9d Merge pull request #281 from ajayyy/experimental
Rename CI artifacts
2020-02-17 15:24:49 -05:00
Ajay Ramachandran
219a7ba8c3 Added preview bar to mobile 2020-02-17 15:10:50 -05:00
Ajay Ramachandran
933babb4e6 Added mobile YouTube site to the whitelist. 2020-02-17 11:32:00 -05:00
Ajay Ramachandran
023ba2e051 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into experimental 2020-02-17 11:24:36 -05:00
Ajay Ramachandran
1c833a8b1d Rename CI artifacts. 2020-02-11 21:04:41 -05:00
Ajay Ramachandran
7143d7532d Increase version number 2020-02-11 21:01:35 -05:00
Ajay Ramachandran
1f10bdf593 Merge pull request #279 from CommanderRoot/patch-1
Retain decimals in seconds value when editing sponsor times
2020-02-11 20:33:04 -05:00
CommanderRoot
3b543916ff Retain decimals in seconds value 2020-02-12 02:24:03 +01:00
Ajay Ramachandran
c4da85340a Merge pull request #277 from ajayyy/experimental
Fixed regex to support Firefox
2020-02-11 14:10:47 -05:00
Ajay Ramachandran
ec59c7e0f9 Increase version number. 2020-02-11 14:10:11 -05:00
Ajay Ramachandran
2454cd9a39 Fixed regex to support Firefox. 2020-02-11 12:29:19 -05:00
Ajay Ramachandran
c19e2bea29 Merge pull request #274 from ajayyy/experimental
Various fixes
2020-02-10 22:35:54 -05:00
Ajay Ramachandran
2f2c1ad49b Increased version number. 2020-02-10 22:32:15 -05:00
Ajay Ramachandran
657aff2167 Removed use of Invidious API.
Resolves https://github.com/ajayyy/SponsorBlock/issues/189.
2020-02-10 22:27:54 -05:00
Ajay Ramachandran
2450457fe5 Fixed close button on dark theme.
Resolves https://github.com/ajayyy/SponsorBlock/issues/196
2020-02-10 21:54:11 -05:00
Ajay Ramachandran
ba9e42e6f0 Forced auto skip if previewing sponsor.
Resolves https://github.com/ajayyy/SponsorBlock/issues/222
2020-02-10 21:49:17 -05:00
Ajay Ramachandran
f05d80523b Made it unpause when previewing a sponsor.
Resolves https://github.com/ajayyy/SponsorBlock/issues/222
2020-02-10 21:39:39 -05:00
Ajay Ramachandran
d2779aba86 Fix editing not adding numbers.
Resolves https://github.com/ajayyy/SponsorBlock/issues/273.
2020-02-10 18:03:09 -05:00
Ajay Ramachandran
852912a42b Fixed inlines sponsor popup.
Fixes https://github.com/ajayyy/SponsorBlock/issues/272
2020-02-10 17:12:52 -05:00
Ajay Ramachandran
45e0f87f9f Reformatted manifest. 2020-02-09 11:14:40 -05:00
7 changed files with 380 additions and 185 deletions

View File

@@ -21,7 +21,7 @@ jobs:
run: npm run build:chrome
- uses: actions/upload-artifact@v1
with:
name: Chrome Extension
name: ChromeExtension
path: dist
# Create Firefox artifacts
@@ -29,6 +29,6 @@ jobs:
run: npm run build:firefox
- uses: actions/upload-artifact@v1
with:
name: Firefox Extension
name: FirefoxExtension
path: dist

View File

@@ -68,7 +68,7 @@ The result is in `dist`.
# Credit
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) is used to grab the time the video was published.
The awesome [Invidious API](https://github.com/omarroth/invidious/wiki/API) used to be used.
Original code from [YTSponsorSkip](https://github.com/OfficialNoob/YTSponsorSkip), but not much of the code is left.

View File

@@ -1,11 +1,10 @@
{
"name": "__MSG_fullName__",
"short_name": "__MSG_Name__",
"version": "1.2.8",
"version": "1.2.14",
"default_locale": "en",
"description": "__MSG_Description__",
"content_scripts": [
{
"content_scripts": [{
"run_at": "document_start",
"matches": [
"https://*.youtube.com/*",
@@ -21,8 +20,7 @@
"./libs/Source+Sans+Pro.css",
"popup.css"
]
}
],
}],
"web_accessible_resources": [
"icons/LogoSponsorBlocker256px.png",
"icons/IconSponsorBlocker256px.png",
@@ -69,4 +67,4 @@
"open_in_tab": true
},
"manifest_version": 2
}
}

View File

@@ -15,11 +15,17 @@ utils.wait(() => Config.config !== null, 5000, 10).then(addCSS);
var sponsorDataFound = false;
var previousVideoID = null;
//the actual sponsorTimes if loaded and UUIDs associated with them
var sponsorTimes = null;
var sponsorTimes: number[][] = null;
var UUIDs = [];
//what video id are these sponsors for
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
var hiddenSponsorTimes = [];
@@ -27,15 +33,18 @@ var hiddenSponsorTimes = [];
var sponsorSkipped = [];
//the video
var v;
var video: HTMLVideoElement;
var onInvidious;
var onMobileYouTube;
//the video id of the last preview bar update
var lastPreviewBarUpdate;
//whether the duration listener listening for the duration changes of the video has been setup yet
var durationListenerSetUp = false;
// Timestamp of the last duration change
var lastDurationChange = 0;
//the channel this video is about
var channelURL;
@@ -47,7 +56,11 @@ var title;
var channelWhitelisted = false;
// 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.
// This is set to a timeout function when that happens that will reset it after 3 seconds.
var previewResetter: NodeJS.Timeout = null;
//the player controls on the YouTube player
var controls = null;
@@ -85,10 +98,11 @@ var skipNoticeContentContainer = () => ({
unskipSponsorTime,
sponsorTimes,
UUIDs,
v,
v: video,
reskipSponsorTime,
hiddenSponsorTimes,
updatePreviewBar
updatePreviewBar,
onMobileYouTube
});
//get messages from the background script and the popup
@@ -132,16 +146,29 @@ function messageListener(request: any, sender: any, sendResponse: (response: any
break;
case "getVideoDuration":
sendResponse({
duration: v.duration
duration: video.duration
});
break;
case "skipToTime":
v.currentTime = request.time;
video.currentTime = request.time;
// Unpause the video if needed
if (video.paused){
video.play();
}
// Start preview resetter
if (previewResetter !== null){
clearTimeout(previewResetter);
}
previewResetter = setTimeout(() => previewResetter = null, 4000);
return
case "getCurrentTime":
sendResponse({
currentTime: v.currentTime
currentTime: video.currentTime
});
break;
@@ -238,7 +265,7 @@ async function videoIDChange(id) {
sponsorVideoID = id;
resetValues();
//id is not valid
if (!id) return;
@@ -261,26 +288,19 @@ async function videoIDChange(id) {
channelIDPromise.then(() => channelIDPromise.isFulfilled = true).catch(() => channelIDPromise.isRejected = true);
//setup the preview bar
if (previewBar == null) {
//create it
utils.wait(getControls).then(result => {
const progressElementSelectors = [
// For YouTube
"ytp-progress-bar-container",
"no-model cue-range-markers",
// For Invidious/VideoJS
"vjs-progress-holder"
];
if (previewBar === null) {
if (onMobileYouTube) {
// Mobile YouTube workaround
const observer = new MutationObserver(handleMobileControlsMutations);
for (const selector of progressElementSelectors) {
const el = document.getElementsByClassName(selector);
if (el && el.length && el[0]) {
previewBar = new PreviewBar(el[0]);
break;
}
}
});
observer.observe(document.getElementById("player-control-container"), {
attributes: true,
childList: true,
subtree: true
});
} else {
utils.wait(getControls).then(createPreviewBar);
}
}
//warn them if they had unsubmitted times
@@ -337,18 +357,123 @@ async function videoIDChange(id) {
}
}
});
});
});
//see if video controls buttons should be added
if (!onInvidious) {
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]);
v = document.querySelector('video') // Youtube video player
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
//there is no video here
if (v == null) {
if (video == null) {
setTimeout(() => sponsorsLookup(id, channelIDPromise), 100);
return;
}
@@ -357,7 +482,17 @@ function sponsorsLookup(id: string, channelIDPromise?) {
durationListenerSetUp = true;
//wait until it is loaded
v.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) {
@@ -410,12 +545,35 @@ function sponsorsLookup(id: string, channelIDPromise?) {
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
sponsorSkipped = [];
//update the preview bar
//leave the type blank for now until categories are added
if (lastPreviewBarUpdate == id || (lastPreviewBarUpdate == null && !isNaN(v.duration))) {
if (lastPreviewBarUpdate == id || (lastPreviewBarUpdate == null && !isNaN(video.duration))) {
//set it now
//otherwise the listener can handle it
updatePreviewBar();
@@ -427,12 +585,19 @@ function sponsorsLookup(id: string, channelIDPromise?) {
//check if this video was uploaded recently
//use the invidious api to get the time published
sendRequestToCustomServer('GET', "https://invidio.us/api/v1/videos/" + id + '?fields=published', function(xmlhttp, error) {
sendRequestToCustomServer('GET', "https://www.youtube.com/get_video_info?video_id=" + id, function(xmlhttp, error) {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
let unixTimePublished = JSON.parse(xmlhttp.responseText).published;
let decodedData = decodeURIComponent(xmlhttp.responseText).match(/player_response=([^&]*)/)[1];
if (decodedData === undefined) {
console.error("[SB] Failed at getting video upload date info from YouTube.");
return;
}
let dateUploaded = JSON.parse(decodedData).microformat.playerMicroformatRenderer.uploadDate;
//if less than 3 days old
if ((Date.now() / 1000) - unixTimePublished < 259200) {
if (Date.now() - new Date(dateUploaded).getTime() < 259200000) {
//TODO lower when server becomes better
setTimeout(() => sponsorsLookup(id, channelIDPromise), 180000);
}
@@ -450,13 +615,6 @@ function sponsorsLookup(id: string, channelIDPromise?) {
sponsorLookupRetries++;
}
});
//add the event to run on the videos "ontimeupdate"
if (!Config.config.disableSkipping) {
v.ontimeupdate = function () {
sponsorCheck();
};
}
}
function getYouTubeVideoID(url: string) {
@@ -475,7 +633,9 @@ function getYouTubeVideoID(url: string) {
// Check if valid hostname
if (Config.config && Config.config.invidiousInstances.includes(urlObject.host)) {
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) {
// Call this later, in case this is an Invidious tab
utils.wait(() => Config.config !== null).then(() => videoIDChange(getYouTubeVideoID(url)));
@@ -548,6 +708,15 @@ function getChannelID() {
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() {
let localSponsorTimes = sponsorTimes;
if (localSponsorTimes == null) localSponsorTimes = [];
@@ -568,7 +737,7 @@ function updatePreviewBar() {
types.push("previewSponsor");
}
utils.wait(() => previewBar !== null).then((result) => previewBar.set(allSponsorTimes, types, v.duration));
utils.wait(() => previewBar !== null).then((result) => previewBar.set(allSponsorTimes, types, video.duration));
//update last video id
lastPreviewBarUpdate = sponsorVideoID;
@@ -584,75 +753,58 @@ function whitelistCheck() {
}
}
//video skipping
function sponsorCheck() {
if (Config.config.disableSkipping) {
// Make sure this isn't called again
v.ontimeupdate = null;
return;
} else if (channelWhitelisted) {
return;
}
/**
* Returns info about the next upcoming sponsor skip
*/
function getNextSkipIndex(currentTime: number): {array: number[][], index: number, openNotice: boolean} {
let sponsorStartTimes = getStartTimes(sponsorTimes);
let sponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimes, currentTime, true);
let skipHappened = false;
let minSponsorTimeIndex = sponsorStartTimes.indexOf(Math.min(...sponsorStartTimesAfterCurrentTime));
if (sponsorTimes != null) {
//see if any sponsor start time was just passed
for (let i = 0; i < sponsorTimes.length; i++) {
//if something was skipped
if (checkSponsorTime(sponsorTimes, i, true)) {
skipHappened = true;
break;
}
}
}
let previewSponsorStartTimes = getStartTimes(sponsorTimesSubmitting);
let previewSponsorStartTimesAfterCurrentTime = getStartTimes(sponsorTimesSubmitting, currentTime, false);
if (!skipHappened) {
//check for the "preview" sponsors (currently edited by this user)
for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
//must be a finished sponsor and be valid
if (sponsorTimesSubmitting[i].length > 1 && sponsorTimesSubmitting[i][1] > sponsorTimesSubmitting[i][0]) {
checkSponsorTime(sponsorTimesSubmitting, i, false);
}
}
}
let minPreviewSponsorTimeIndex = previewSponsorStartTimes.indexOf(Math.min(...previewSponsorStartTimesAfterCurrentTime));
//don't keep track until they are loaded in
if (sponsorTimes !== null || sponsorTimesSubmitting.length > 0) {
lastTime = v.currentTime;
if (minPreviewSponsorTimeIndex == -1 || sponsorStartTimes[minSponsorTimeIndex] < previewSponsorStartTimes[minPreviewSponsorTimeIndex]) {
return {
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
if (Math.abs(v.currentTime - lastTime) > 1 && lastTime != -1) {
//make lastTime as if the video was playing normally
lastTime = v.currentTime - 0.0001;
/**
* Gets just the start times from a sponsor times array.
* Optionally specify a minimum
*
* @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(v.currentTime, sponsorTimes[index][0], sponsorTimes[index][1]) && !hiddenSponsorTimes.includes(index)) {
//skip it
skipToTime(v, index, sponsorTimes, openNotice);
//something was skipped
return true;
}
return false;
return startTimes;
}
function checkIfTimeToSkip(currentVideoTime, startTime, endTime) {
//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
//skip from fhe start time to the end time for a certain index sponsor time
function skipToTime(v, index, sponsorTimes, openNotice) {
if (!Config.config.disableAutoSkip) {
if (!Config.config.disableAutoSkip || previewResetter !== null) {
v.currentTime = sponsorTimes[index][1];
}
@@ -690,27 +842,38 @@ function skipToTime(v, index, sponsorTimes, openNotice) {
function unskipSponsorTime(UUID) {
if (sponsorTimes != null) {
//add a tiny bit of time to make sure it is not skipped again
v.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][0] + 0.001;
video.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][0] + 0.001;
}
}
function reskipSponsorTime(UUID) {
if (sponsorTimes != null) {
//add a tiny bit of time to make sure it is not skipped again
v.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][1];
video.currentTime = sponsorTimes[UUIDs.indexOf(UUID)][1];
}
}
function createButton(baseID, title, callback, imageName, isDraggable=false) {
if (document.getElementById(baseID + "Button") != null) return;
function createButton(baseID, title, callback, imageName, isDraggable=false): boolean {
if (document.getElementById(baseID + "Button") != null) return false;
// Button HTML
let newButton = document.createElement("button");
newButton.draggable = isDraggable;
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.addEventListener("click", callback);
newButton.addEventListener("click", (event: Event) => {
callback();
// Prevents the contols from closing when clicked
if (onMobileYouTube) event.stopPropagation();
});
// Image HTML
let newButtonImage = document.createElement("img");
@@ -724,40 +887,56 @@ function createButton(baseID, title, callback, imageName, isDraggable=false) {
// Add the button to player
controls.prepend(newButton);
return true;
}
function getControls() {
let controls = document.getElementsByClassName("ytp-right-controls");
function getControls(): HTMLElement | boolean {
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) {
// The invidious video element's controls element
controls = document.getElementsByClassName("vjs-control-bar");
return (!controls || controls.length === 0) ? false : controls[controls.length - 1];
} else {
return controls[controls.length - 1];
for (const controlsSelector of controlsSelectors) {
let controls = document.querySelectorAll(controlsSelector);
if (controls && controls.length > 0) {
return <HTMLElement> controls[controls.length - 1];
}
}
return false;
};
//adds all the player controls buttons
async function createButtons() {
async function createButtons(): Promise<boolean> {
let result = await utils.wait(getControls).catch();
//set global controls variable
controls = result;
// Add button if does not already exist in html
createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png");
createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png")
createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png");
createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png");
}
//adds or removes the player controls button to what it should be
async function updateVisibilityOfPlayerControlsButton() {
//not on a proper video yet
if (!sponsorVideoID) return;
let createdButton = false;
// Add button if does not already exist in html
createdButton = createButton("startSponsor", "sponsorStart", startSponsorClicked, "PlayerStartIconSponsorBlocker256px.png") || createdButton;
createdButton = createButton("info", "openPopup", openInfoMenu, "PlayerInfoIconSponsorBlocker256px.png") || createdButton;
createdButton = createButton("delete", "clearTimes", clearSponsorTimes, "PlayerDeleteIconSponsorBlocker256px.png") || createdButton;
createdButton = createButton("submit", "SubmitTimes", submitSponsorTimes, "PlayerUploadIconSponsorBlocker256px.png") || createdButton;
return createdButton;
}
//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) {
document.getElementById("startSponsorButton").style.display = "none";
document.getElementById("submitButton").style.display = "none";
@@ -775,6 +954,8 @@ async function updateVisibilityOfPlayerControlsButton() {
if (Config.config.hideDeleteButtonPlayerControls || onInvidious) {
document.getElementById("deleteButton").style.display = "none";
}
return createdButtons;
}
function startSponsorClicked() {
@@ -786,7 +967,7 @@ function startSponsorClicked() {
//send back current time with message
chrome.runtime.sendMessage({
message: "addSponsorTime",
time: v.currentTime,
time: video.currentTime,
videoID: sponsorVideoID
}, function(response) {
//see if the sponsorTimesSubmitting needs to be updated
@@ -807,22 +988,17 @@ function updateSponsorTimesSubmitting() {
sponsorTimesSubmitting = sponsorTimes;
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) {
if(!sponsorVideoID) return false;
//make sure submit button is loaded
await utils.wait(isSubmitButtonLoaded);
//if it isn't visible, there is no data
let shouldHide = (uploadButtonVisible && !(Config.config.hideDeleteButtonPlayerControls || onInvidious)) ? "unset" : "none"
document.getElementById("deleteButton").style.display = shouldHide;
@@ -875,6 +1051,8 @@ function openInfoMenu() {
closeButton.classList.add("smallLink");
closeButton.setAttribute("align", "center");
closeButton.addEventListener("click", closeInfoMenu);
// Theme based color
closeButton.style.color = "var(--yt-spec-text-primary)";
//add the close button
popup.prepend(closeButton);
@@ -1012,11 +1190,11 @@ function dontShowNoticeAgain() {
}
function sponsorMessageStarted(callback) {
v = document.querySelector('video');
video = document.querySelector('video');
//send back current time
callback({
time: v.currentTime
time: video.currentTime
})
//update button
@@ -1039,8 +1217,8 @@ function submitSponsorTimes() {
if (sponsorTimes != undefined && sponsorTimes.length > 0) {
//check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimes.length; i++) {
if (sponsorTimes[i][1] > v.duration) {
sponsorTimes[i][1] = v.duration;
if (sponsorTimes[i][1] > video.duration) {
sponsorTimes[i][1] = video.duration;
}
}
//update sponsorTimes

View File

@@ -23,18 +23,30 @@ let barTypes = {
class PreviewBar {
container: HTMLUListElement;
parent: any;
onMobileYouTube: boolean;
constructor(parent) {
constructor(parent, onMobileYouTube) {
this.container = document.createElement('ul');
this.container.id = 'previewbar';
this.parent = parent;
this.updatePosition();
this.onMobileYouTube = onMobileYouTube;
this.updatePosition(parent);
}
updatePosition() {
updatePosition(parent) {
//below the seek bar
// 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
this.parent.insertAdjacentElement("afterBegin", this.container);
@@ -70,7 +82,7 @@ class PreviewBar {
bar.setAttribute('data-vs-segment-type', types[i]);
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.left = (timestamps[i][0] / duration * 100) + "%";
bar.style.position = "absolute"

View File

@@ -56,6 +56,10 @@ class SkipNotice {
noticeElement.classList.add("sponsorSkipObject");
noticeElement.classList.add("sponsorSkipNotice");
noticeElement.style.zIndex = String(50 + amountOfPreviousNotices);
if (contentContainer().onMobileYouTube) {
noticeElement.style.bottom = "4em";
noticeElement.style.zoom = "0.8";
}
//add mouse enter and leave listeners
noticeElement.addEventListener("mouseenter", this.pauseCountdown.bind(this));
@@ -173,7 +177,8 @@ class SkipNotice {
noticeElement.appendChild(secondRow);
//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) {
//for embeds
let player = document.getElementById("player");

View File

@@ -38,7 +38,7 @@ class MessageHandler {
//make this a function to allow this to run on the content page
async function runThePopup(messageListener?: MessageListener) {
var messageHandler = new MessageHandler();
var messageHandler = new MessageHandler(messageListener);
utils.localizeHtmlPage();
@@ -656,9 +656,9 @@ async function runThePopup(messageListener?: MessageListener) {
tabs[0].id,
{message: "getCurrentTime"},
function (response) {
let minutes = <HTMLInputElement> <unknown> document.getElementById(idStartName + "Minutes" + index);
let minutes = <HTMLInputElement> <unknown> document.getElementById(idStartName + "Minutes" + index);
let seconds = <HTMLInputElement> <unknown> document.getElementById(idStartName + "Seconds" + index);
minutes.value = String(getTimeInMinutes(response.currentTime));
seconds.value = getTimeInFormattedSeconds(response.currentTime);
});
@@ -667,11 +667,11 @@ async function runThePopup(messageListener?: MessageListener) {
//id start name is whether it is the startTime or endTime
//gives back the time in seconds
function getSponsorTimeEditTimes(idStartName, index) {
function getSponsorTimeEditTimes(idStartName, index): number {
let minutes = <HTMLInputElement> <unknown> document.getElementById(idStartName + "Minutes" + index);
let seconds = <HTMLInputElement> <unknown> document.getElementById(idStartName + "Seconds" + index);
return parseInt(minutes.value) * 60 + seconds.value;
return parseInt(minutes.value) * 60 + parseFloat(seconds.value);
}
function saveSponsorTimeEdit(index, closeEditMode = true) {
@@ -679,16 +679,17 @@ async function runThePopup(messageListener?: MessageListener) {
sponsorTimes[index][1] = getSponsorTimeEditTimes("endTime", index);
//save this
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id,
{message: "sponsorDataChanged"}
);
});
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id,
{message: "sponsorDataChanged"}
);
});
if (closeEditMode) {
displaySponsorTimes();
@@ -718,17 +719,8 @@ async function runThePopup(messageListener?: MessageListener) {
sponsorTimes.splice(index, 1);
//save this
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id,
{message: "sponsorDataChanged"}
);
});
Config.config.sponsorTimes.set(currentVideoID, sponsorTimes);
//update display
displaySponsorTimes();
@@ -749,6 +741,16 @@ async function runThePopup(messageListener?: MessageListener) {
//hide submission section
document.getElementById("submissionSection").style.display = "none";
}
messageHandler.query({
active: true,
currentWindow: true
}, tabs => {
messageHandler.sendMessage(
tabs[0].id,
{message: "sponsorDataChanged"}
);
});
}
function clearTimes() {
@@ -968,7 +970,7 @@ async function runThePopup(messageListener?: MessageListener) {
secondsDisplay = "0" + secondsDisplay;
}
let formatted = minutes+ ":" + secondsDisplay;
let formatted = minutes + ":" + secondsDisplay;
return formatted;
}
@@ -1127,4 +1129,4 @@ if (chrome.tabs != undefined) {
runThePopup();
}
export default runThePopup;
export default runThePopup;