mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2026-03-17 08:41:53 +03:00
Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into pr/opl-/569
This commit is contained in:
@@ -37,6 +37,9 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
case "openHelp":
|
||||
chrome.tabs.create({url: chrome.runtime.getURL('help/index_en.html')});
|
||||
return;
|
||||
case "openPage":
|
||||
chrome.tabs.create({url: chrome.runtime.getURL(request.url)});
|
||||
return;
|
||||
case "sendRequest":
|
||||
sendRequestToCustomServer(request.type, request.url, request.data).then(async (response) => {
|
||||
callback({
|
||||
|
||||
@@ -127,7 +127,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
|
||||
|
||||
render(): React.ReactElement {
|
||||
const noticeStyle: React.CSSProperties = {
|
||||
zIndex: 50 + this.amountOfPreviousNotices
|
||||
zIndex: 1000 + this.amountOfPreviousNotices
|
||||
}
|
||||
if (this.contentContainer().onMobileYouTube) {
|
||||
noticeStyle.bottom = "4em";
|
||||
|
||||
@@ -37,6 +37,7 @@ interface SBConfig {
|
||||
testingServer: boolean,
|
||||
hashPrefix: boolean,
|
||||
refetchWhenNotFound: boolean,
|
||||
ytInfoPermissionGranted: boolean,
|
||||
|
||||
// What categories should be skipped
|
||||
categorySelections: CategorySelection[],
|
||||
@@ -168,8 +169,9 @@ const Config: SBObject = {
|
||||
audioNotificationOnSkip: false,
|
||||
checkForUnlistedVideos: false,
|
||||
testingServer: false,
|
||||
hashPrefix: false,
|
||||
hashPrefix: true,
|
||||
refetchWhenNotFound: true,
|
||||
ytInfoPermissionGranted: false,
|
||||
|
||||
categorySelections: [{
|
||||
name: "sponsor",
|
||||
|
||||
@@ -258,7 +258,7 @@ async function videoIDChange(id) {
|
||||
try {
|
||||
await utils.wait(() => !!videoInfo, 5000, 1);
|
||||
} catch (err) {
|
||||
alert(chrome.i18n.getMessage("adblockerIssue") + "\n\n" + chrome.i18n.getMessage("adblockerIssueUnlistedVideosInfo"));
|
||||
await videoInfoFetchFailed("adblockerIssueUnlistedVideosInfo");
|
||||
}
|
||||
|
||||
if (isUnlisted()) {
|
||||
@@ -268,7 +268,11 @@ async function videoIDChange(id) {
|
||||
}
|
||||
|
||||
// Update whitelist data when the video data is loaded
|
||||
utils.wait(() => !!videoInfo, 5000, 10).then(whitelistCheck);
|
||||
utils.wait(() => !!videoInfo, 5000, 10).then(whitelistCheck).catch(() => {
|
||||
if (Config.config.forceChannelCheck) {
|
||||
videoInfoFetchFailed("adblockerIssueWhitelist");
|
||||
}
|
||||
});
|
||||
|
||||
//setup the preview bar
|
||||
if (previewBar === null) {
|
||||
@@ -635,12 +639,12 @@ async function sponsorsLookup(id: string) {
|
||||
sponsorLookupRetries = 0;
|
||||
} else if (response?.status === 404) {
|
||||
retryFetch(id);
|
||||
} else if (sponsorLookupRetries < 90 && !recheckStarted) {
|
||||
} else if (sponsorLookupRetries < 15 && !recheckStarted) {
|
||||
recheckStarted = true;
|
||||
|
||||
//TODO lower when server becomes better (back to 1 second)
|
||||
//some error occurred, try again in a second
|
||||
setTimeout(() => sponsorsLookup(id), 5000 + Math.random() * 15000);
|
||||
setTimeout(() => sponsorsLookup(id), 5000 + Math.random() * 15000 + 5000 * sponsorLookupRetries);
|
||||
|
||||
sponsorLookupRetries++;
|
||||
}
|
||||
@@ -715,6 +719,21 @@ async function getVideoInfo(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
async function videoInfoFetchFailed(errorMessage: string): Promise<void> {
|
||||
console.log("failed\t" + errorMessage)
|
||||
if (utils.isFirefox() && !Config.config.ytInfoPermissionGranted) {
|
||||
// Attempt to ask permission for youtube.com domain
|
||||
alert(chrome.i18n.getMessage("youtubePermissionRequest"));
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
message: "openPage",
|
||||
url: "permissions/index.html#youtube.com"
|
||||
});
|
||||
} else {
|
||||
alert(chrome.i18n.getMessage("videoInfoFetchFailed") + "\n\n" + chrome.i18n.getMessage(errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
function getYouTubeVideoID(url: string) {
|
||||
// For YouTube TV support
|
||||
if(url.startsWith("https://www.youtube.com/tv#/")) url = url.replace("#", "");
|
||||
@@ -1276,7 +1295,7 @@ function openInfoMenu() {
|
||||
const settings = <HTMLImageElement> popup.querySelector("#sbPopupIconSettings");
|
||||
const edit = <HTMLImageElement> popup.querySelector("#sbPopupIconEdit");
|
||||
const check = <HTMLImageElement> popup.querySelector("#sbPopupIconCheck");
|
||||
logo.src = chrome.extension.getURL("icons/LogoSponsorBlocker256px.png");
|
||||
logo.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png");
|
||||
settings.src = chrome.extension.getURL("icons/settings.svg");
|
||||
edit.src = chrome.extension.getURL("icons/pencil.svg");
|
||||
check.src = chrome.extension.getURL("icons/check.svg");
|
||||
@@ -1517,9 +1536,11 @@ function getSegmentsMessage(sponsorTimes: SponsorTime[]): string {
|
||||
}
|
||||
|
||||
function addHotkeyListener(): boolean {
|
||||
const videoRoot = document.getElementById("movie_player") as HTMLDivElement;
|
||||
let videoRoot = document.getElementById("movie_player") as HTMLDivElement;
|
||||
if (onInvidious) videoRoot = (document.getElementById("player-container") ?? document.getElementById("player")) as HTMLDivElement;
|
||||
if (video.baseURI.startsWith("https://www.youtube.com/tv#/")) videoRoot = document.querySelector("ytlr-watch-page") as HTMLDivElement;
|
||||
|
||||
if (!videoRootsWithEventListeners.includes(videoRoot)) {
|
||||
if (videoRoot && !videoRootsWithEventListeners.includes(videoRoot)) {
|
||||
videoRoot.addEventListener("keydown", hotkeyListener);
|
||||
videoRootsWithEventListeners.push(videoRoot);
|
||||
return true;
|
||||
@@ -1634,6 +1655,8 @@ function showTimeWithoutSkips(skippedDuration: number): void {
|
||||
|
||||
display.appendChild(duration);
|
||||
}
|
||||
|
||||
const durationAfterSkips = utils.getFormattedTime(video.duration - skippedDuration)
|
||||
|
||||
duration.innerText = skippedDuration <= 0 ? "" : " (" + utils.getFormattedTime(video.duration - skippedDuration) + ")";
|
||||
duration.innerText = (durationAfterSkips == null || skippedDuration <= 0) ? "" : " (" + durationAfterSkips + ")";
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ function invidiousInit(checkbox: HTMLInputElement, option: string) {
|
||||
if (utils.isFirefox()) permissions = [];
|
||||
|
||||
chrome.permissions.contains({
|
||||
origins: utils.getInvidiousInstancesRegex(),
|
||||
origins: utils.getPermissionRegex(),
|
||||
permissions: permissions
|
||||
}, function (result) {
|
||||
if (result != checkbox.checked) {
|
||||
|
||||
35
src/permissions.ts
Normal file
35
src/permissions.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import Config from "./config";
|
||||
import Utils from "./utils";
|
||||
const utils = new Utils();
|
||||
|
||||
// This is needed, if Config is not imported before Utils, things break.
|
||||
// Probably due to cyclic dependencies
|
||||
Config.config;
|
||||
|
||||
window.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
async function init() {
|
||||
utils.localizeHtmlPage();
|
||||
|
||||
const domains = document.location.hash.replace("#", "").split(",");
|
||||
|
||||
const acceptButton = document.getElementById("acceptPermissionButton");
|
||||
acceptButton.addEventListener("click", () => {
|
||||
chrome.permissions.request({
|
||||
origins: utils.getPermissionRegex(domains),
|
||||
permissions: []
|
||||
}, (granted) => {
|
||||
if (granted) {
|
||||
alert(chrome.i18n.getMessage("permissionRequestSuccess"));
|
||||
|
||||
Config.config.ytInfoPermissionGranted = true;
|
||||
|
||||
chrome.tabs.getCurrent((tab) => {
|
||||
chrome.tabs.remove(tab.id);
|
||||
});
|
||||
} else {
|
||||
alert(chrome.i18n.getMessage("permissionRequestFailed"));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
41
src/popup.ts
41
src/popup.ts
@@ -383,7 +383,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
extraInfo = " (" + chrome.i18n.getMessage("hiddenDueToDuration") + ")";
|
||||
}
|
||||
|
||||
sponsorTimeButton.innerText = prefix + getFormattedTime(segmentTimes[i].segment[0]) + " " + chrome.i18n.getMessage("to") + " " + getFormattedTime(segmentTimes[i].segment[1]) + extraInfo;
|
||||
sponsorTimeButton.innerText = prefix + utils.getFormattedTime(segmentTimes[i].segment[0], true) + " " + chrome.i18n.getMessage("to") + " " + utils.getFormattedTime(segmentTimes[i].segment[1], true) + extraInfo;
|
||||
|
||||
const categoryColorCircle = document.createElement("span");
|
||||
categoryColorCircle.id = "sponsorTimesCategoryColorCircle" + UUID;
|
||||
@@ -412,9 +412,18 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
downvoteButton.src = chrome.extension.getURL("icons/thumbs_down.svg");
|
||||
downvoteButton.addEventListener("click", () => vote(0, UUID));
|
||||
|
||||
//add thumbs up and down buttons to the container
|
||||
//uuid button
|
||||
|
||||
const uuidButton = document.createElement("img");
|
||||
uuidButton.id = "sponsorTimesCopyUUIDButtonContainer" + UUID;
|
||||
uuidButton.className = "voteButton";
|
||||
uuidButton.src = chrome.extension.getURL("icons/clipboard.svg");
|
||||
uuidButton.addEventListener("click", () => navigator.clipboard.writeText(UUID));
|
||||
|
||||
//add thumbs up, thumbs down and uuid copy buttons to the container
|
||||
voteButtonsContainer.appendChild(upvoteButton);
|
||||
voteButtonsContainer.appendChild(downvoteButton);
|
||||
voteButtonsContainer.appendChild(uuidButton);
|
||||
|
||||
//add click listener to open up vote panel
|
||||
sponsorTimeButton.addEventListener("click", function() {
|
||||
@@ -542,13 +551,13 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
function vote(type, UUID) {
|
||||
//add loading info
|
||||
addVoteMessage(chrome.i18n.getMessage("Loading"), UUID);
|
||||
|
||||
|
||||
//send the vote message to the tab
|
||||
chrome.runtime.sendMessage({
|
||||
message: "submitVote",
|
||||
type: type,
|
||||
UUID: UUID
|
||||
}, function(response) {
|
||||
}, function (response) {
|
||||
if (response != undefined) {
|
||||
//see if it was a success or failure
|
||||
if (response.successType == 1 || (response.successType == -1 && response.statusCode == 429)) {
|
||||
@@ -561,21 +570,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
});
|
||||
}
|
||||
|
||||
//converts time in seconds to minutes:seconds
|
||||
function getFormattedTime(seconds) {
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
const secondsDisplayNumber = Math.round(seconds - minutes * 60);
|
||||
let secondsDisplay = String(secondsDisplayNumber);
|
||||
if (secondsDisplayNumber < 10) {
|
||||
//add a zero
|
||||
secondsDisplay = "0" + secondsDisplay;
|
||||
}
|
||||
|
||||
const formatted = minutes + ":" + secondsDisplay;
|
||||
|
||||
return formatted;
|
||||
}
|
||||
|
||||
function whitelistChannel() {
|
||||
//get the channel url
|
||||
messageHandler.query({
|
||||
@@ -698,10 +692,11 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
|
||||
* @param {float} seconds
|
||||
* @returns {string}
|
||||
*/
|
||||
function getFormattedHours(minues) {
|
||||
const hours = Math.floor(minues / 60);
|
||||
return (hours > 0 ? hours + "h " : "") + (minues % 60).toFixed(1);
|
||||
}
|
||||
function getFormattedHours(minutes) {
|
||||
minutes = Math.round(minutes * 10) / 10
|
||||
const hours = Math.floor(minutes / 60);
|
||||
return (hours > 0 ? hours + "h " : "") + (minutes % 60).toFixed(1);
|
||||
}
|
||||
|
||||
//end of function
|
||||
}
|
||||
|
||||
46
src/utils.ts
46
src/utils.ts
@@ -3,10 +3,10 @@ import { CategorySelection, SponsorTime, FetchResponse, BackgroundScriptContaine
|
||||
|
||||
import * as CompileConfig from "../config.json";
|
||||
|
||||
class Utils {
|
||||
export default class Utils {
|
||||
|
||||
// Contains functions needed from the background script
|
||||
backgroundScriptContainer: BackgroundScriptContainer | null = null;
|
||||
backgroundScriptContainer: BackgroundScriptContainer | null;
|
||||
|
||||
// Used to add content scripts and CSS required
|
||||
js = [
|
||||
@@ -19,7 +19,7 @@ class Utils {
|
||||
"popup.css"
|
||||
];
|
||||
|
||||
constructor(backgroundScriptContainer?: BackgroundScriptContainer) {
|
||||
constructor(backgroundScriptContainer: BackgroundScriptContainer = null) {
|
||||
this.backgroundScriptContainer = backgroundScriptContainer;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@ class Utils {
|
||||
});
|
||||
}
|
||||
|
||||
containsPermission(permissions: chrome.permissions.Permissions): Promise<boolean> {
|
||||
return new Promise((resolve) => {
|
||||
chrome.permissions.contains(permissions, resolve)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks for the optional permissions required for all extra sites.
|
||||
* It also starts the content script registrations.
|
||||
@@ -57,7 +63,7 @@ class Utils {
|
||||
if (this.isFirefox()) permissions = [];
|
||||
|
||||
chrome.permissions.request({
|
||||
origins: this.getInvidiousInstancesRegex(),
|
||||
origins: this.getPermissionRegex(),
|
||||
permissions: permissions
|
||||
}, async (granted) => {
|
||||
if (granted) {
|
||||
@@ -78,7 +84,6 @@ class Utils {
|
||||
* For now, it is just SB.config.invidiousInstances.
|
||||
*/
|
||||
setupExtraSiteContentScripts(): void {
|
||||
|
||||
if (this.isFirefox()) {
|
||||
const firefoxJS = [];
|
||||
for (const file of this.js) {
|
||||
@@ -95,7 +100,7 @@ class Utils {
|
||||
allFrames: true,
|
||||
js: firefoxJS,
|
||||
css: firefoxCSS,
|
||||
matches: this.getInvidiousInstancesRegex()
|
||||
matches: this.getPermissionRegex()
|
||||
};
|
||||
|
||||
if (this.backgroundScriptContainer) {
|
||||
@@ -106,7 +111,7 @@ class Utils {
|
||||
} else {
|
||||
chrome.declarativeContent.onPageChanged.removeRules(["invidious"], () => {
|
||||
const conditions = [];
|
||||
for (const regex of this.getInvidiousInstancesRegex()) {
|
||||
for (const regex of this.getPermissionRegex()) {
|
||||
conditions.push(new chrome.declarativeContent.PageStateMatcher({
|
||||
pageUrl: { urlMatches: regex }
|
||||
}));
|
||||
@@ -149,7 +154,7 @@ class Utils {
|
||||
}
|
||||
|
||||
chrome.permissions.remove({
|
||||
origins: this.getInvidiousInstancesRegex()
|
||||
origins: this.getPermissionRegex()
|
||||
});
|
||||
}
|
||||
|
||||
@@ -250,16 +255,20 @@ class Utils {
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String[]} Invidious Instances in regex form
|
||||
* @returns {String[]} Domains in regex form
|
||||
*/
|
||||
getInvidiousInstancesRegex(): string[] {
|
||||
const invidiousInstancesRegex: string[] = [];
|
||||
for (const url of Config.config.invidiousInstances) {
|
||||
invidiousInstancesRegex.push("https://*." + url + "/*");
|
||||
invidiousInstancesRegex.push("http://*." + url + "/*");
|
||||
getPermissionRegex(domains: string[] = []): string[] {
|
||||
const permissionRegex: string[] = [];
|
||||
if (domains.length === 0) {
|
||||
domains = [...Config.config.invidiousInstances];
|
||||
}
|
||||
|
||||
return invidiousInstancesRegex;
|
||||
for (const url of domains) {
|
||||
permissionRegex.push("https://*." + url + "/*");
|
||||
permissionRegex.push("http://*." + url + "/*");
|
||||
}
|
||||
|
||||
return permissionRegex;
|
||||
}
|
||||
|
||||
generateUserID(length = 36): string {
|
||||
@@ -290,7 +299,7 @@ class Utils {
|
||||
let errorMessage = "";
|
||||
const postFix = (responseText ? "\n\n" + responseText : "");
|
||||
|
||||
if([400, 429, 409, 502, 0].includes(statusCode)) {
|
||||
if([400, 429, 409, 502, 503, 0].includes(statusCode)) {
|
||||
//treat them the same
|
||||
if (statusCode == 503) statusCode = 502;
|
||||
|
||||
@@ -376,6 +385,9 @@ class Utils {
|
||||
//add a zero
|
||||
minutesDisplay = "0" + minutesDisplay;
|
||||
}
|
||||
if (isNaN(hours) || isNaN(minutes)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const formatted = (hours ? hours + ":" : "") + minutesDisplay + ":" + secondsDisplay;
|
||||
|
||||
@@ -431,5 +443,3 @@ class Utils {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Utils;
|
||||
|
||||
Reference in New Issue
Block a user