mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-06 11:37:02 +03:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cd697dc32 | ||
|
|
9946bd1af2 | ||
|
|
3b06d72270 | ||
|
|
4bd0556464 | ||
|
|
7e12a914d5 | ||
|
|
25eaf4fa20 | ||
|
|
b3efa1f787 | ||
|
|
9a18e70e34 | ||
|
|
64ece9cb73 | ||
|
|
66c974b011 | ||
|
|
d8cc93c841 | ||
|
|
de22accfda | ||
|
|
e5b0b60dde | ||
|
|
32d98e6544 | ||
|
|
3dde05eda2 | ||
|
|
6aeefaae64 | ||
|
|
93d695e6c2 | ||
|
|
160924feee | ||
|
|
e3f3ed20e6 | ||
|
|
52149f4c0f | ||
|
|
cbc586f9ac | ||
|
|
fc8e20be0d | ||
|
|
368059eb0d | ||
|
|
ea77375fcc | ||
|
|
16005e417d | ||
|
|
7c5b750264 | ||
|
|
cc6b65c6c4 | ||
|
|
d2c99c2d77 | ||
|
|
84c25e3042 |
@@ -1,15 +1,31 @@
|
||||
If you make any contributions to SponsorBlock after this file was created, you are agreeing that any code you have contributed will be licensed under LGPL-3.0.
|
||||
If you make any contributions to SponsorBlock after this file was created, you are agreeing that any code you have contributed will be licensed under LGPL-3.0 or later.
|
||||
|
||||
# All Platforms
|
||||
Make sure to pull and update all submodules
|
||||
`git submodule update --init --recursive`
|
||||
# Translations
|
||||
https://crowdin.com/project/sponsorblock
|
||||
|
||||
"? property does not exist on type ConfigClass"
|
||||
> Make sure to copy `config.json.example` to `config.json` and remove comments
|
||||
# Building
|
||||
## Building locally
|
||||
0. You must have [Node.js 16 or later](https://nodejs.org/) and npm installed. Works best on Linux
|
||||
1. Clone with submodules
|
||||
```bash
|
||||
git clone --recursive https://github.com/ajayyy/SponsorBlock
|
||||
```
|
||||
Or if you already cloned it, pull submodules with
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
2. Copy the file `config.json.example` to `config.json` and adjust configuration as desired.
|
||||
- Comments are invalid in JSON, make sure they are all removed.
|
||||
- You will need to repeat this step in the future if you get build errors related to `CompileConfig` or `property does not exist on type ConfigClass`. This can happen for example when a new category is added.
|
||||
3. Run `npm ci` in the repository to install dependencies.
|
||||
4. Run `npm run build:dev` (for Chrome) or `npm run build:dev:firefox` (for Firefox) to generate a development version of the extension with source maps.
|
||||
- You can also run `npm run build` (for Chrome) or `npm run build:firefox` (for Firefox) to generate a production build.
|
||||
5. The built extension is now in `dist/`. You can load this folder directly in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/#manifest), or convert it to a zip file to load it as a [temporary extension](https://developer.mozilla.org/docs/Tools/about:debugging#loading_a_temporary_extension) in Firefox.
|
||||
|
||||
## Developing with a clean profile and hot reloading
|
||||
Run `npm run dev` (for Chrome) or `npm run dev:firefox` (for Firefox) to run the extension using a clean browser profile with hot reloading. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
|
||||
|
||||
Known chromium bug: Extension is not loaded properly on first start. Visit `chrome://extensions/` and reload the extension.
|
||||
|
||||
For Firefox for Android, use `npm run dev:firefox-android -- --adb-device <ip-address of the device>`. See the [Firefox documentation](https://extensionworkshop.com/documentation/develop/developing-extensions-for-firefox-for-android/#debug-your-extension) for more information. You may need to edit package.json and add the parameters directly there.
|
||||
|
||||
# Windows
|
||||
"Cannot find module "../maze-utils"
|
||||
- Enable "Developer Mode" in windows for symlinks
|
||||
- `src/maze-utils` will not appear properly and builds will fail since it is is only rendered as a file
|
||||
- Enable symlink support in git `git config --global core.symlinks true`
|
||||
- run `git checkout -- src/maze-utils` in order to create a symlink instead of a text file
|
||||
41
README.md
41
README.md
@@ -38,7 +38,7 @@
|
||||
|
||||
SponsorBlock is an open-source crowdsourced browser extension to skip sponsor segments in YouTube videos. Users submit when a sponsor happens from the extension, and the extension automatically skips sponsors it knows about. It also supports skipping other categories, such as intros, outros and reminders to subscribe.
|
||||
|
||||
It also supports Invidio.us.
|
||||
It also supports Invidious.
|
||||
|
||||
**Translate:** [](https://crowdin.com/project/sponsorblock)
|
||||
|
||||
@@ -56,47 +56,14 @@ The dataset and API are now being used in some [ports](https://github.com/ajayyy
|
||||
|
||||
# API
|
||||
|
||||
You can read the API docs [here](https://wiki.sponsor.ajay.app/index.php/API_Docs).
|
||||
You can read the API docs [here](https://wiki.sponsor.ajay.app/w/API_Docs).
|
||||
|
||||
# Building
|
||||
|
||||
You must have [Node.js 16](https://nodejs.org/) and npm installed.
|
||||
|
||||
1. Clone with submodules
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/ajayyy/SponsorBlock
|
||||
```
|
||||
|
||||
Or if you already cloned it, pull submodules with
|
||||
|
||||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
|
||||
2. Copy the file `config.json.example` to `config.json` and adjust configuration as desired.
|
||||
|
||||
- You will need to repeat this step in the future if you get build errors related to `CompileConfig`. This can happen for example when a new category is added.
|
||||
|
||||
3. Run `npm install` in the repository to install dependencies.
|
||||
|
||||
4. Run `npm run build:dev` (for Chrome) or `npm run build:dev:firefox` (for Firefox) to generate a development version of the extension with source maps.
|
||||
|
||||
- You can also run `npm run build` (for Chrome) or `npm run build:firefox` (for Firefox) to generate a production build.
|
||||
|
||||
5. The built extension is now in `dist/`. You can load this folder directly in Chrome as an [unpacked extension](https://developer.chrome.com/docs/extensions/mv3/getstarted/#manifest), or convert it to a zip file to load it as a [temporary extension](https://developer.mozilla.org/en-US/docs/Tools/about:debugging#loading_a_temporary_extension) in Firefox.
|
||||
|
||||
### Developing with a clean profile and hot reloading
|
||||
|
||||
Run `npm run dev` (for Chrome) or `npm run dev:firefox` (for Firefox) to run the extension using a clean browser profile with hot reloading. This uses [`web-ext run`](https://extensionworkshop.com/documentation/develop/web-ext-command-reference/#commands).
|
||||
|
||||
Known chromium bug: Extension is not loaded properly on first start. Visit `chrome://extensions/` and reload the extension.
|
||||
|
||||
For Firefox for Android, use `npm run dev:firefox-android -- --adb-device <ip-address of the device>`. See the [Firefox documentation](https://extensionworkshop.com/documentation/develop/developing-extensions-for-firefox-for-android/#debug-your-extension) for more information.
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
# Credit
|
||||
|
||||
The awesome [Invidious API](https://docs.invidious.io/API.md) was previously used, and the server is now using [NewLeaf](https://git.sr.ht/~cadence/NewLeaf) as a to get video info from YouTube.
|
||||
The awesome [Invidious API](https://docs.invidious.io/) was previously used, and the server is now using [NewLeaf](https://git.sr.ht/~cadence/NewLeaf) as a to get video info from YouTube.
|
||||
|
||||
Originally forked from [YTSponsorSkip](https://github.com/NDevTK/YTSponsorSkip), but very little code remains.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"optional_permissions": [
|
||||
"declarativeContent"
|
||||
"declarativeContent",
|
||||
"webNavigation"
|
||||
],
|
||||
"background": {
|
||||
"persistent": false
|
||||
|
||||
@@ -3,5 +3,11 @@
|
||||
"gecko": {
|
||||
"id": "sponsorBlocker@ajay.app"
|
||||
}
|
||||
}
|
||||
},
|
||||
"background": {
|
||||
"persistent": false
|
||||
},
|
||||
"permissions": [
|
||||
"scripting"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_fullName__",
|
||||
"short_name": "SponsorBlock",
|
||||
"version": "5.4.13",
|
||||
"version": "5.4.17",
|
||||
"default_locale": "en",
|
||||
"description": "__MSG_Description__",
|
||||
"homepage_url": "https://sponsor.ajay.app",
|
||||
@@ -84,8 +84,7 @@
|
||||
"https://sponsor.ajay.app/*"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"*://*/*",
|
||||
"webNavigation"
|
||||
"*://*/*"
|
||||
],
|
||||
"browser_action": {
|
||||
"default_title": "SponsorBlock",
|
||||
@@ -116,6 +115,21 @@
|
||||
"light": "icons/IconSponsorBlocker128px.png",
|
||||
"dark": "icons/IconSponsorBlocker128px.png",
|
||||
"size": 128
|
||||
},
|
||||
{
|
||||
"light": "icons/IconSponsorBlocker256px.png",
|
||||
"dark": "icons/IconSponsorBlocker256px.png",
|
||||
"size": 256
|
||||
},
|
||||
{
|
||||
"light": "icons/IconSponsorBlocker512px.png",
|
||||
"dark": "icons/IconSponsorBlocker512px.png",
|
||||
"size": 512
|
||||
},
|
||||
{
|
||||
"light": "icons/IconSponsorBlocker1024px.png",
|
||||
"dark": "icons/IconSponsorBlocker1024px.png",
|
||||
"size": 1024
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"background": {
|
||||
"persistent": false
|
||||
}
|
||||
},
|
||||
"permissions": [
|
||||
"scripting"
|
||||
],
|
||||
"optional_permissions": [
|
||||
"webNavigation"
|
||||
]
|
||||
}
|
||||
|
||||
Submodule maze-utils updated: b3572eaeff...79bef97a3b
Submodule public/_locales updated: 9e1f32d7c6...5528978f2f
@@ -3,9 +3,9 @@ import * as CompileConfig from "../config.json";
|
||||
import Config from "./config";
|
||||
import { Registration } from "./types";
|
||||
import "content-scripts-register-polyfill";
|
||||
import { sendRealRequestToCustomServer, setupBackgroundRequestProxy } from "./maze-utils/background-request-proxy";
|
||||
import { setupTabUpdates } from "./maze-utils/tab-updates";
|
||||
import { generateUserID } from "./maze-utils/setup";
|
||||
import { sendRealRequestToCustomServer, setupBackgroundRequestProxy } from "../maze-utils/src/background-request-proxy";
|
||||
import { setupTabUpdates } from "../maze-utils/src/tab-updates";
|
||||
import { generateUserID } from "../maze-utils/src/setup";
|
||||
|
||||
// Make the config public for debugging purposes
|
||||
|
||||
@@ -13,9 +13,10 @@ window.SB = Config;
|
||||
|
||||
import Utils from "./utils";
|
||||
import { getExtensionIdsToImportFrom } from "./utils/crossExtension";
|
||||
import { isFirefoxOrSafari } from "./maze-utils";
|
||||
import { injectUpdatedScripts } from "./maze-utils/cleanup";
|
||||
import { isFirefoxOrSafari } from "../maze-utils/src";
|
||||
import { injectUpdatedScripts } from "../maze-utils/src/cleanup";
|
||||
import { logWarn } from "./utils/logger";
|
||||
import { chromeP } from "../maze-utils/src/browserApi";
|
||||
const utils = new Utils({
|
||||
registerFirefoxContentScript,
|
||||
unregisterFirefoxContentScript
|
||||
@@ -27,7 +28,7 @@ const popupPort: Record<string, chrome.runtime.Port> = {};
|
||||
const contentScriptRegistrations = {};
|
||||
|
||||
// Register content script if needed
|
||||
utils.wait(() => Config.config !== null).then(function() {
|
||||
utils.wait(() => Config.isReady()).then(function() {
|
||||
if (Config.config.supportInvidious) utils.setupExtraSiteContentScripts();
|
||||
});
|
||||
|
||||
@@ -75,7 +76,11 @@ chrome.runtime.onMessage.addListener(function (request, sender, callback) {
|
||||
case "infoUpdated":
|
||||
case "videoChanged":
|
||||
if (sender.tab) {
|
||||
popupPort[sender.tab.id]?.postMessage(request);
|
||||
try {
|
||||
popupPort[sender.tab.id]?.postMessage(request);
|
||||
} catch (e) {
|
||||
// This can happen if the popup is closed
|
||||
}
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
@@ -148,27 +153,60 @@ chrome.runtime.onInstalled.addListener(function () {
|
||||
*
|
||||
* @param {JSON} options
|
||||
*/
|
||||
function registerFirefoxContentScript(options: Registration) {
|
||||
const oldRegistration = contentScriptRegistrations[options.id];
|
||||
if (oldRegistration) oldRegistration.unregister();
|
||||
async function registerFirefoxContentScript(options: Registration) {
|
||||
if ("scripting" in chrome && "getRegisteredContentScripts" in chrome.scripting) {
|
||||
const existingRegistrations = await chromeP.scripting.getRegisteredContentScripts({
|
||||
ids: [options.id]
|
||||
});
|
||||
|
||||
if (existingRegistrations.length > 0
|
||||
&& existingRegistrations[0].matches.every((match) => options.matches.includes(match))) {
|
||||
// No need to register another script, already registered
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await unregisterFirefoxContentScript(options.id);
|
||||
|
||||
if ("scripting" in chrome && "getRegisteredContentScripts" in chrome.scripting) {
|
||||
await chromeP.scripting.registerContentScripts([{
|
||||
id: options.id,
|
||||
runAt: "document_start",
|
||||
matches: options.matches,
|
||||
allFrames: options.allFrames,
|
||||
js: options.js,
|
||||
css: options.css,
|
||||
persistAcrossSessions: true,
|
||||
}]);
|
||||
} else {
|
||||
chrome.contentScripts.register({
|
||||
allFrames: options.allFrames,
|
||||
js: options.js?.map?.(file => ({file})),
|
||||
css: options.css?.map?.(file => ({file})),
|
||||
matches: options.matches
|
||||
}).then((registration) => void (contentScriptRegistrations[options.id] = registration));
|
||||
}
|
||||
|
||||
chrome.contentScripts.register({
|
||||
allFrames: options.allFrames,
|
||||
js: options.js,
|
||||
css: options.css,
|
||||
matches: options.matches
|
||||
}).then((registration) => void (contentScriptRegistrations[options.id] = registration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only works on Firefox.
|
||||
* Firefox requires that this is handled by the background script
|
||||
*
|
||||
*/
|
||||
function unregisterFirefoxContentScript(id: string) {
|
||||
if (contentScriptRegistrations[id]) {
|
||||
contentScriptRegistrations[id].unregister();
|
||||
delete contentScriptRegistrations[id];
|
||||
async function unregisterFirefoxContentScript(id: string) {
|
||||
if ("scripting" in chrome && "getRegisteredContentScripts" in chrome.scripting) {
|
||||
try {
|
||||
await chromeP.scripting.unregisterContentScripts({
|
||||
ids: [id]
|
||||
});
|
||||
} catch (e) {
|
||||
// Already registered
|
||||
}
|
||||
} else {
|
||||
if (contentScriptRegistrations[id]) {
|
||||
contentScriptRegistrations[id].unregister();
|
||||
delete contentScriptRegistrations[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
import { AnimationUtils } from "../utils/animationUtils";
|
||||
import { Tooltip } from "../render/Tooltip";
|
||||
import { getErrorMessage } from "../maze-utils/formating";
|
||||
import { getErrorMessage } from "../../maze-utils/src/formating";
|
||||
|
||||
export interface CategoryPillProps {
|
||||
vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
import { AnimationUtils } from "../utils/animationUtils";
|
||||
import { Tooltip } from "../render/Tooltip";
|
||||
import { getErrorMessage } from "../maze-utils/formating";
|
||||
import { getErrorMessage } from "../../maze-utils/src/formating";
|
||||
|
||||
export interface ChapterVoteProps {
|
||||
vote: (type: number, UUID: SegmentUUID, category?: Category) => Promise<VoteResponse>;
|
||||
|
||||
@@ -12,8 +12,8 @@ import ThumbsUpSvg from "../svg-icons/thumbs_up_svg";
|
||||
import ThumbsDownSvg from "../svg-icons/thumbs_down_svg";
|
||||
import PencilSvg from "../svg-icons/pencil_svg";
|
||||
import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
|
||||
import { generateUserID } from "../maze-utils/setup";
|
||||
import { keybindToString } from "../maze-utils/config";
|
||||
import { generateUserID } from "../../maze-utils/src/setup";
|
||||
import { keybindToString } from "../../maze-utils/src/config";
|
||||
|
||||
enum SkipButtonState {
|
||||
Undo, // Unskip
|
||||
|
||||
@@ -7,7 +7,7 @@ import SubmissionNoticeComponent from "./SubmissionNoticeComponent";
|
||||
import { RectangleTooltip } from "../render/RectangleTooltip";
|
||||
import SelectorComponent, { SelectorOption } from "./SelectorComponent";
|
||||
import { DEFAULT_CATEGORY } from "../utils/categoryUtils";
|
||||
import { getFormattedTime, getFormattedTimeToSeconds } from "../maze-utils/formating";
|
||||
import { getFormattedTime, getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
|
||||
|
||||
const utils = new Utils();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import * as React from "react";
|
||||
import { createRoot, Root } from 'react-dom/client';
|
||||
import Config from "../../config";
|
||||
import KeybindDialogComponent from "./KeybindDialogComponent";
|
||||
import { formatKey, Keybind, keybindEquals, keybindToString } from "../../maze-utils/config";
|
||||
import { formatKey, Keybind, keybindEquals, keybindToString } from "../../../maze-utils/src/config";
|
||||
|
||||
export interface KeybindProps {
|
||||
option: string;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from "react";
|
||||
import { ChangeEvent } from "react";
|
||||
import Config from "../../config";
|
||||
import { Keybind, formatKey, keybindEquals } from "../../maze-utils/config";
|
||||
import { Keybind, formatKey, keybindEquals } from "../../../maze-utils/src/config";
|
||||
|
||||
export interface KeybindDialogProps {
|
||||
option: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as CompileConfig from "../config.json";
|
||||
import * as invidiousList from "../ci/invidiouslist.json";
|
||||
import { Category, CategorySelection, CategorySkipOption, NoticeVisbilityMode, PreviewBarOption, SponsorTime, VideoID, SponsorHideType } from "./types";
|
||||
import { Keybind, ProtoConfig, keybindEquals } from "./maze-utils/config";
|
||||
import { HashedValue } from "./maze-utils/hash";
|
||||
import { Keybind, ProtoConfig, keybindEquals } from "../maze-utils/src/config";
|
||||
import { HashedValue } from "../maze-utils/src/hash";
|
||||
|
||||
export interface Permission {
|
||||
canSubmit: boolean;
|
||||
|
||||
@@ -32,21 +32,21 @@ import { logDebug } from "./utils/logger";
|
||||
import { importTimes } from "./utils/exporter";
|
||||
import { ChapterVote } from "./render/ChapterVote";
|
||||
import { openWarningDialog } from "./utils/warnings";
|
||||
import { isFirefoxOrSafari, waitFor } from "./maze-utils";
|
||||
import { getErrorMessage, getFormattedTime } from "./maze-utils/formating";
|
||||
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube } from "./maze-utils/video";
|
||||
import { Keybind, StorageChangesObject, isSafari, keybindEquals } from "./maze-utils/config";
|
||||
import { findValidElement, waitForElement } from "./maze-utils/dom"
|
||||
import { getHash, HashedValue } from "./maze-utils/hash";
|
||||
import { generateUserID } from "./maze-utils/setup";
|
||||
import { updateAll } from "./maze-utils/thumbnailManagement";
|
||||
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src";
|
||||
import { getErrorMessage, getFormattedTime } from "../maze-utils/src/formating";
|
||||
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube } from "../maze-utils/src/video";
|
||||
import { Keybind, StorageChangesObject, isSafari, keybindEquals } from "../maze-utils/src/config";
|
||||
import { findValidElement, waitForElement } from "../maze-utils/src/dom"
|
||||
import { getHash, HashedValue } from "../maze-utils/src/hash";
|
||||
import { generateUserID } from "../maze-utils/src/setup";
|
||||
import { updateAll } from "../maze-utils/src/thumbnailManagement";
|
||||
import { setupThumbnailListener } from "./utils/thumbnails";
|
||||
import * as documentScript from "../dist/js/document.js";
|
||||
import { Tooltip } from "./render/Tooltip";
|
||||
import { isDeArrowInstalled } from "./utils/crossExtension";
|
||||
import { runCompatibilityChecks } from "./utils/compatibility";
|
||||
import { cleanPage } from "./utils/pageCleaner";
|
||||
import { addCleanupListener } from "./maze-utils/cleanup";
|
||||
import { addCleanupListener } from "../maze-utils/src/cleanup";
|
||||
|
||||
cleanPage();
|
||||
|
||||
@@ -803,11 +803,12 @@ function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boole
|
||||
const currentVideoID = getYouTubeVideoID();
|
||||
const recordedVideoID = videoID || getVideoID();
|
||||
if (currentVideoID !== recordedVideoID || (sponsorTime
|
||||
&& (!sponsorTimes || !sponsorTimes?.some((time) => time.segment === sponsorTime.segment))
|
||||
&& !sponsorTimesSubmitting.some((time) => time.segment === sponsorTime.segment))) {
|
||||
&& (!sponsorTimes || !sponsorTimes?.some((time) => time.segment[0] === sponsorTime.segment[0] && time.segment[1] === sponsorTime.segment[1]))
|
||||
&& !sponsorTimesSubmitting.some((time) => time.segment[0] === sponsorTime.segment[0] && time.segment[1] === sponsorTime.segment[1]))) {
|
||||
// Something has really gone wrong
|
||||
console.error("[SponsorBlock] The videoID recorded when trying to skip is different than what it should be.");
|
||||
console.error("[SponsorBlock] VideoID recorded: " + recordedVideoID + ". Actual VideoID: " + currentVideoID);
|
||||
console.error("[SponsorBlock] SponsorTime", sponsorTime, "sponsorTimes", sponsorTimes, "sponsorTimesSubmitting", sponsorTimesSubmitting);
|
||||
|
||||
// Video ID change occured
|
||||
checkVideoIDChange();
|
||||
@@ -818,6 +819,8 @@ function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boole
|
||||
}
|
||||
}
|
||||
|
||||
let playbackRateCheckInterval: NodeJS.Timeout | null = null;
|
||||
let lastPlaybackSpeed = 1;
|
||||
let setupVideoListenersFirstTime = true;
|
||||
function setupVideoListeners() {
|
||||
//wait until it is loaded
|
||||
@@ -837,6 +840,16 @@ function setupVideoListeners() {
|
||||
let startedWaiting = false;
|
||||
let lastPausedAtZero = true;
|
||||
|
||||
const rateChangeListener = () => {
|
||||
updateVirtualTime();
|
||||
clearWaitingTime();
|
||||
|
||||
startSponsorSchedule();
|
||||
};
|
||||
getVideo().addEventListener('ratechange', rateChangeListener);
|
||||
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
|
||||
getVideo().addEventListener('videoSpeed_ratechange', rateChangeListener);
|
||||
|
||||
const playListener = () => {
|
||||
// If it is not the first event, then the only way to get to 0 is if there is a seek event
|
||||
// This check makes sure that changing the video resolution doesn't cause the extension to think it
|
||||
@@ -867,7 +880,6 @@ function setupVideoListeners() {
|
||||
|
||||
startSponsorSchedule();
|
||||
}
|
||||
|
||||
};
|
||||
getVideo().addEventListener('play', playListener);
|
||||
|
||||
@@ -897,6 +909,27 @@ function setupVideoListeners() {
|
||||
|
||||
startSponsorSchedule();
|
||||
}
|
||||
|
||||
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
||||
lastPlaybackSpeed = getVideo().playbackRate;
|
||||
|
||||
// Video speed controller compatibility
|
||||
// That extension makes rate change events not propagate
|
||||
if (document.body.classList.contains("vsc-initialized")) {
|
||||
playbackRateCheckInterval = setInterval(() => {
|
||||
if ((!getVideoID() || getVideo().paused) && playbackRateCheckInterval) {
|
||||
// Video is gone, stop checking
|
||||
clearInterval(playbackRateCheckInterval);
|
||||
return;
|
||||
}
|
||||
|
||||
if (getVideo().playbackRate !== lastPlaybackSpeed) {
|
||||
lastPlaybackSpeed = getVideo().playbackRate;
|
||||
|
||||
rateChangeListener();
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
};
|
||||
getVideo().addEventListener('playing', playingListener);
|
||||
|
||||
@@ -927,21 +960,13 @@ function setupVideoListeners() {
|
||||
};
|
||||
getVideo().addEventListener('seeking', seekingListener);
|
||||
|
||||
const rateChangeListener = () => {
|
||||
updateVirtualTime();
|
||||
clearWaitingTime();
|
||||
|
||||
startSponsorSchedule();
|
||||
};
|
||||
getVideo().addEventListener('ratechange', () => rateChangeListener);
|
||||
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
|
||||
getVideo().addEventListener('videoSpeed_ratechange', rateChangeListener);
|
||||
|
||||
const stoppedPlayback = () => {
|
||||
// Reset lastCheckVideoTime
|
||||
lastCheckVideoTime = -1;
|
||||
lastCheckTime = 0;
|
||||
|
||||
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
||||
|
||||
lastKnownVideoTime.videoTime = null;
|
||||
lastKnownVideoTime.preciseTime = null;
|
||||
updateWaitingTime();
|
||||
@@ -973,6 +998,8 @@ function setupVideoListeners() {
|
||||
getVideo().removeEventListener('videoSpeed_ratechange', rateChangeListener);
|
||||
getVideo().removeEventListener('pause', pauseListener);
|
||||
getVideo().removeEventListener('waiting', waitingListener);
|
||||
|
||||
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { init } from "./maze-utils/injected/document";
|
||||
import { init } from "../maze-utils/src/injected/document";
|
||||
|
||||
init();
|
||||
@@ -1,8 +1,8 @@
|
||||
import { localizeHtmlPage } from "./maze-utils/setup";
|
||||
import { localizeHtmlPage } from "../maze-utils/src/setup";
|
||||
import Config from "./config";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
|
||||
import { waitFor } from "./maze-utils";
|
||||
import { waitFor } from "../maze-utils/src";
|
||||
|
||||
if (document.readyState === "complete") {
|
||||
init();
|
||||
|
||||
@@ -11,9 +11,9 @@ import { ActionType, Category, SegmentContainer, SponsorHideType, SponsorSourceT
|
||||
import { partition } from "../utils/arrayUtils";
|
||||
import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
|
||||
import { normalizeChapterName } from "../utils/exporter";
|
||||
import { getFormattedTimeToSeconds } from "../maze-utils/formating";
|
||||
import { findValidElement } from "../maze-utils/dom";
|
||||
import { addCleanupListener } from "../maze-utils/cleanup";
|
||||
import { getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
|
||||
import { findValidElement } from "../../maze-utils/src/dom";
|
||||
import { addCleanupListener } from "../../maze-utils/src/cleanup";
|
||||
|
||||
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
|
||||
const MIN_CHAPTER_SIZE = 0.003;
|
||||
@@ -784,11 +784,13 @@ class PreviewBar {
|
||||
if (!Config.config.showSegmentNameInChapterBar
|
||||
|| ((!segments || segments.length <= 0) && submittingSegments?.length <= 0)) {
|
||||
const chaptersContainer = this.getChaptersContainer();
|
||||
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
|
||||
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
|
||||
|
||||
chapterTitle.style.removeProperty("display");
|
||||
chaptersContainer.classList.remove("sponsorblock-chapter-visible");
|
||||
if (chaptersContainer) {
|
||||
chaptersContainer.querySelector(".sponsorChapterText")?.remove();
|
||||
const chapterTitle = chaptersContainer.querySelector(".ytp-chapter-title-content") as HTMLDivElement;
|
||||
|
||||
chapterTitle.style.removeProperty("display");
|
||||
chaptersContainer.classList.remove("sponsorblock-chapter-visible");
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Config from "../config";
|
||||
import { SponsorTime } from "../types";
|
||||
import { getSkippingText } from "../utils/categoryUtils";
|
||||
import { AnimationUtils } from "../utils/animationUtils";
|
||||
import { keybindToString } from "../maze-utils/config";
|
||||
import { keybindToString } from "../../maze-utils/src/config";
|
||||
|
||||
export interface SkipButtonControlBarProps {
|
||||
skip: (segment: SponsorTime) => void;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../maze-utils/src/
|
||||
@@ -13,10 +13,10 @@ import CategoryChooser from "./render/CategoryChooser";
|
||||
import UnsubmittedVideos from "./render/UnsubmittedVideos";
|
||||
import KeybindComponent from "./components/options/KeybindComponent";
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { localizeHtmlPage } from "./maze-utils/setup";
|
||||
import { StorageChangesObject } from "./maze-utils/config";
|
||||
import { getHash } from "./maze-utils/hash";
|
||||
import { isFirefoxOrSafari } from "./maze-utils";
|
||||
import { localizeHtmlPage } from "../maze-utils/src/setup";
|
||||
import { StorageChangesObject } from "../maze-utils/src/config";
|
||||
import { getHash } from "../maze-utils/src/hash";
|
||||
import { isFirefoxOrSafari } from "../maze-utils/src";
|
||||
import { isDeArrowInstalled } from "./utils/crossExtension";
|
||||
const utils = new Utils();
|
||||
let embed = false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Config from "./config";
|
||||
import Utils from "./utils";
|
||||
import { localizeHtmlPage } from "./maze-utils/setup";
|
||||
import { localizeHtmlPage } from "../maze-utils/src/setup";
|
||||
const utils = new Utils();
|
||||
|
||||
// This is needed, if Config is not imported before Utils, things break.
|
||||
|
||||
@@ -21,12 +21,12 @@ import {
|
||||
import { showDonationLink } from "./utils/configUtils";
|
||||
import { AnimationUtils } from "./utils/animationUtils";
|
||||
import { shortCategoryName } from "./utils/categoryUtils";
|
||||
import { localizeHtmlPage } from "./maze-utils/setup";
|
||||
import { localizeHtmlPage } from "../maze-utils/src/setup";
|
||||
import { exportTimes } from "./utils/exporter";
|
||||
import GenericNotice from "./render/GenericNotice";
|
||||
import { getErrorMessage, getFormattedTime } from "./maze-utils/formating";
|
||||
import { StorageChangesObject } from "./maze-utils/config";
|
||||
import { getHash } from "./maze-utils/hash";
|
||||
import { getErrorMessage, getFormattedTime } from "../maze-utils/src/formating";
|
||||
import { StorageChangesObject } from "../maze-utils/src/config";
|
||||
import { getHash } from "../maze-utils/src/hash";
|
||||
|
||||
const utils = new Utils();
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ import Config from "../config";
|
||||
import { VoteResponse } from "../messageTypes";
|
||||
import { Category, SegmentUUID, SponsorTime } from "../types";
|
||||
import { Tooltip } from "./Tooltip";
|
||||
import { waitFor } from "../maze-utils";
|
||||
import { getYouTubeTitleNode } from "../maze-utils/elements";
|
||||
import { addCleanupListener } from "../maze-utils/cleanup";
|
||||
import { waitFor } from "../../maze-utils/src";
|
||||
import { getYouTubeTitleNode } from "../../maze-utils/src/elements";
|
||||
import { addCleanupListener } from "../../maze-utils/src/cleanup";
|
||||
|
||||
const id = "categoryPill";
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ export interface Registration {
|
||||
message: string;
|
||||
id: string;
|
||||
allFrames: boolean;
|
||||
js: browser.extensionTypes.ExtensionFileOrCode[];
|
||||
css: browser.extensionTypes.ExtensionFileOrCode[];
|
||||
js: string[];
|
||||
css: string[];
|
||||
matches: string[];
|
||||
}
|
||||
|
||||
|
||||
33
src/utils.ts
33
src/utils.ts
@@ -1,12 +1,12 @@
|
||||
import Config, { VideoDownvotes } from "./config";
|
||||
import { CategorySelection, SponsorTime, BackgroundScriptContainer, Registration, VideoID, SponsorHideType, CategorySkipOption } from "./types";
|
||||
|
||||
import { getHash, HashedValue } from "./maze-utils/hash";
|
||||
import { getHash, HashedValue } from "../maze-utils/src/hash";
|
||||
import * as CompileConfig from "../config.json";
|
||||
import { isFirefoxOrSafari, waitFor } from "./maze-utils";
|
||||
import { findValidElementFromSelector } from "./maze-utils/dom";
|
||||
import { FetchResponse, sendRequestToCustomServer } from "./maze-utils/background-request-proxy"
|
||||
import { isSafari } from "./maze-utils/config";
|
||||
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src";
|
||||
import { findValidElementFromSelector } from "../maze-utils/src/dom";
|
||||
import { FetchResponse, sendRequestToCustomServer } from "../maze-utils/src/background-request-proxy"
|
||||
import { isSafari } from "../maze-utils/src/config";
|
||||
|
||||
export default class Utils {
|
||||
|
||||
@@ -47,9 +47,13 @@ export default class Utils {
|
||||
* @param {CallableFunction} callback
|
||||
*/
|
||||
setupExtraSitePermissions(callback: (granted: boolean) => void): void {
|
||||
let permissions = ["webNavigation"];
|
||||
if (!isSafari()) permissions.push("declarativeContent");
|
||||
if (isFirefoxOrSafari() && !isSafari()) permissions = [];
|
||||
const permissions = [];
|
||||
if (!isFirefoxOrSafari()) {
|
||||
permissions.push("declarativeContent");
|
||||
}
|
||||
if (!isFirefoxOrSafari() || isSafari()) {
|
||||
permissions.push("webNavigation");
|
||||
}
|
||||
|
||||
chrome.permissions.request({
|
||||
origins: this.getPermissionRegex(),
|
||||
@@ -73,21 +77,12 @@ export default class Utils {
|
||||
* For now, it is just SB.config.invidiousInstances.
|
||||
*/
|
||||
setupExtraSiteContentScripts(): void {
|
||||
const firefoxJS = [];
|
||||
for (const file of this.js) {
|
||||
firefoxJS.push({file});
|
||||
}
|
||||
const firefoxCSS = [];
|
||||
for (const file of this.css) {
|
||||
firefoxCSS.push({file});
|
||||
}
|
||||
|
||||
const registration: Registration = {
|
||||
message: "registerContentScript",
|
||||
id: "invidious",
|
||||
allFrames: true,
|
||||
js: firefoxJS,
|
||||
css: firefoxCSS,
|
||||
js: this.js,
|
||||
css: this.css,
|
||||
matches: this.getPermissionRegex()
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as CompileConfig from "../../config.json";
|
||||
|
||||
import Config from "../config";
|
||||
import { isSafari } from "../maze-utils/config";
|
||||
import { isFirefoxOrSafari } from "../maze-utils";
|
||||
import { isSafari } from "../../maze-utils/src/config";
|
||||
import { isFirefoxOrSafari } from "../../maze-utils/src";
|
||||
|
||||
export function isDeArrowInstalled(): Promise<boolean> {
|
||||
if (Config.config.deArrowInstalled) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { ActionType, Category, SegmentUUID, SponsorSourceType, SponsorTime } from "../types";
|
||||
import { shortCategoryName } from "./categoryUtils";
|
||||
import * as CompileConfig from "../../config.json";
|
||||
import { getFormattedTime, getFormattedTimeToSeconds } from "../maze-utils/formating";
|
||||
import { generateUserID } from "../maze-utils/setup";
|
||||
import { getFormattedTime, getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
|
||||
import { generateUserID } from "../../maze-utils/src/setup";
|
||||
|
||||
const inTest = typeof chrome === "undefined";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ActionType, Category, SponsorSourceType, SponsorTime, VideoID } from "../types";
|
||||
import { getFormattedTimeToSeconds } from "../maze-utils/formating";
|
||||
import { getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
|
||||
|
||||
export function getControls(): HTMLElement {
|
||||
const controlsSelectors = [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isOnInvidious, parseYouTubeVideoIDFromURL } from "../maze-utils/video";
|
||||
import { isOnInvidious, parseYouTubeVideoIDFromURL } from "../../maze-utils/src/video";
|
||||
import Config from "../config";
|
||||
import { getVideoLabel } from "./videoLabels";
|
||||
import { setThumbnailListener } from "../maze-utils/thumbnailManagement";
|
||||
import { setThumbnailListener } from "../../maze-utils/src/thumbnailManagement";
|
||||
|
||||
export async function labelThumbnails(thumbnails: HTMLImageElement[]): Promise<void> {
|
||||
await Promise.all(thumbnails.map((t) => labelThumbnail(t)));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Category, CategorySkipOption, VideoID } from "../types";
|
||||
import { getHash } from "../maze-utils/hash";
|
||||
import { getHash } from "../../maze-utils/src/hash";
|
||||
import Utils from "../utils";
|
||||
import { logWarn } from "./logger";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { objectToURI } from "../maze-utils";
|
||||
import { getHash } from "../maze-utils/hash";
|
||||
import { objectToURI } from "../../maze-utils/src";
|
||||
import { getHash } from "../../maze-utils/src/hash";
|
||||
import Config from "../config";
|
||||
import GenericNotice, { NoticeOptions } from "../render/GenericNotice";
|
||||
import { ContentContainer } from "../types";
|
||||
|
||||
Reference in New Issue
Block a user