mirror of
https://github.com/ajayyy/SponsorBlock.git
synced 2025-12-22 15:38:26 +03:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7db6d58c5 | ||
|
|
56a2d76f38 | ||
|
|
4a7d431a17 | ||
|
|
a91ff4e49f | ||
|
|
fcb9f32d4c | ||
|
|
cf4d13a756 | ||
|
|
75d0043e45 | ||
|
|
2391337ee2 | ||
|
|
1074f653b2 | ||
|
|
a12601180e | ||
|
|
3a7716240d | ||
|
|
93f44859b2 | ||
|
|
376ce21eae | ||
|
|
19635d2f06 | ||
|
|
b2a5539324 | ||
|
|
01df1e655e | ||
|
|
467e1cae50 | ||
|
|
822e00a46a | ||
|
|
74433fe751 | ||
|
|
a45690b26e | ||
|
|
f69d6736d4 | ||
|
|
ae7916b7e7 | ||
|
|
3bb4cf4fbc |
12
.github/workflows/tests.yml
vendored
12
.github/workflows/tests.yml
vendored
@@ -18,8 +18,20 @@ jobs:
|
|||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: sudo apt-get install chromium-chromedriver
|
- run: sudo apt-get install chromium-chromedriver
|
||||||
|
|
||||||
|
- uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce
|
||||||
|
with:
|
||||||
|
chrome-version: 135
|
||||||
|
install-dependencies: true
|
||||||
|
install-chromedriver: true
|
||||||
|
|
||||||
- name: Copy configuration
|
- name: Copy configuration
|
||||||
run: cp config.json.example config.json
|
run: cp config.json.example config.json
|
||||||
|
|
||||||
|
- name: Set up WireGuard Connection
|
||||||
|
uses: niklaskeerl/easy-wireguard-action@50341d5f4b8245ff3a90e278aca67b2d283c78d0
|
||||||
|
with:
|
||||||
|
WG_CONFIG_FILE: ${{ secrets.WG_CONFIG_FILE }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: npm run test
|
run: npm run test
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "__MSG_fullName__",
|
"name": "__MSG_fullName__",
|
||||||
"short_name": "SponsorBlock",
|
"short_name": "SponsorBlock",
|
||||||
"version": "5.12",
|
"version": "5.12.4",
|
||||||
"default_locale": "en",
|
"default_locale": "en",
|
||||||
"description": "__MSG_Description__",
|
"description": "__MSG_Description__",
|
||||||
"homepage_url": "https://sponsor.ajay.app",
|
"homepage_url": "https://sponsor.ajay.app",
|
||||||
|
|||||||
Submodule maze-utils updated: 9cef8e27cd...5d5e0b096b
13
package-lock.json
generated
13
package-lock.json
generated
@@ -3313,10 +3313,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/axios": {
|
"node_modules/axios": {
|
||||||
"version": "1.7.7",
|
"version": "1.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@@ -16480,9 +16481,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"axios": {
|
"axios": {
|
||||||
"version": "1.7.7",
|
"version": "1.8.4",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||||
"integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==",
|
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
|
|||||||
Submodule public/_locales updated: 63fe3f4bbc...b6bb85b7f7
@@ -293,7 +293,7 @@
|
|||||||
padding: 10px 15px;
|
padding: 10px 15px;
|
||||||
transition: background-color 0.2s ease-in-out;
|
transition: background-color 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
.sbControlsMenu-item:hover {
|
.sbControlsMenu-item:hover, .sbControlsMenu-item:focus {
|
||||||
background-color: #444;
|
background-color: #444;
|
||||||
}
|
}
|
||||||
.sbControlsMenu-itemIcon {
|
.sbControlsMenu-itemIcon {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
<div id="issueReporterImportExport" class="hidden">
|
<div id="issueReporterImportExport" class="hidden">
|
||||||
<div id="importExportButtons">
|
<div id="importExportButtons">
|
||||||
<button id="importSegmentsButton" title="__MSG_importSegments__">
|
<button id="importSegmentsButton" title="__MSG_importSegments__">
|
||||||
<img src="/icons/import.svg" alt="Refresh icon" id="importSegments" />
|
<img src="/icons/import.svg" alt="Import icon" id="importSegments" />
|
||||||
</button>
|
</button>
|
||||||
<button id="exportSegmentsButton" class="hidden" title="__MSG_exportSegments__">
|
<button id="exportSegmentsButton" class="hidden" title="__MSG_exportSegments__">
|
||||||
<img src="/icons/export.svg" alt="Export icon" id="exportSegments" />
|
<img src="/icons/export.svg" alt="Export icon" id="exportSegments" />
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
|
|
||||||
<!-- Toggle Box -->
|
<!-- Toggle Box -->
|
||||||
<div class="sbControlsMenu">
|
<div class="sbControlsMenu">
|
||||||
<label id="whitelistButton" for="whitelistToggle" class="hidden sbControlsMenu-item">
|
<label id="whitelistButton" for="whitelistToggle" class="hidden sbControlsMenu-item" role="button" tabIndex="0">
|
||||||
<input type="checkbox" style="display: none" id="whitelistToggle">
|
<input type="checkbox" style="display: none" id="whitelistToggle">
|
||||||
<svg viewBox="0 0 24 24" width="23" height="23" class="SBWhitelistIcon sbControlsMenu-itemIcon">
|
<svg viewBox="0 0 24 24" width="23" height="23" class="SBWhitelistIcon sbControlsMenu-itemIcon">
|
||||||
<path d="M24 10H14V0h-4v10H0v4h10v10h4V14h10z" />
|
<path d="M24 10H14V0h-4v10H0v4h10v10h4V14h10z" />
|
||||||
@@ -76,7 +76,7 @@
|
|||||||
<span id="unwhitelistChannel" style="display: none">__MSG_removeFromWhitelist__</span>
|
<span id="unwhitelistChannel" style="display: none">__MSG_removeFromWhitelist__</span>
|
||||||
</label>
|
</label>
|
||||||
<!--github: mbledkowski/toggle-switch-->
|
<!--github: mbledkowski/toggle-switch-->
|
||||||
<label id="disableExtension" for="toggleSwitch" class="toggleSwitchContainer sbControlsMenu-item">
|
<label id="disableExtension" for="toggleSwitch" class="toggleSwitchContainer sbControlsMenu-item" role="button" tabIndex="0">
|
||||||
<span class="toggleSwitchContainer-switch">
|
<span class="toggleSwitchContainer-switch">
|
||||||
<input type="checkbox" style="display: none" id="toggleSwitch" checked>
|
<input type="checkbox" style="display: none" id="toggleSwitch" checked>
|
||||||
<span class="switchBg shadow"></span>
|
<span class="switchBg shadow"></span>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { logDebug, logWarn } from "./utils/logger";
|
|||||||
import { importTimes } from "./utils/exporter";
|
import { importTimes } from "./utils/exporter";
|
||||||
import { ChapterVote } from "./render/ChapterVote";
|
import { ChapterVote } from "./render/ChapterVote";
|
||||||
import { openWarningDialog } from "./utils/warnings";
|
import { openWarningDialog } from "./utils/warnings";
|
||||||
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src";
|
import { extensionUserAgent, isFirefoxOrSafari, waitFor } from "../maze-utils/src";
|
||||||
import { getErrorMessage, getFormattedTime } from "../maze-utils/src/formating";
|
import { getErrorMessage, getFormattedTime } from "../maze-utils/src/formating";
|
||||||
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube, isOnYouTubeMusic, isOnYTTV, getLastNonInlineVideoID, triggerVideoIDChange, triggerVideoElementChange, getIsInline, getCurrentTime, setCurrentTime, getVideoDuration, verifyCurrentTime, waitForVideo } from "../maze-utils/src/video";
|
import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube, isOnYouTubeMusic, isOnYTTV, getLastNonInlineVideoID, triggerVideoIDChange, triggerVideoElementChange, getIsInline, getCurrentTime, setCurrentTime, getVideoDuration, verifyCurrentTime, waitForVideo } from "../maze-utils/src/video";
|
||||||
import { Keybind, StorageChangesObject, isSafari, keybindEquals, keybindToString } from "../maze-utils/src/config";
|
import { Keybind, StorageChangesObject, isSafari, keybindEquals, keybindToString } from "../maze-utils/src/config";
|
||||||
@@ -1926,13 +1926,14 @@ function createButton(baseID: string, title: string, callback: () => void, image
|
|||||||
}
|
}
|
||||||
|
|
||||||
function shouldAutoSkip(segment: SponsorTime): boolean {
|
function shouldAutoSkip(segment: SponsorTime): boolean {
|
||||||
if (segment.category === "music_offtopic" && Config.config.skipNonMusicOnlyOnYoutubeMusic && !isOnYouTubeMusic()) {
|
const canSkipNonMusic = !Config.config.skipNonMusicOnlyOnYoutubeMusic || isOnYouTubeMusic();
|
||||||
|
if (segment.category === "music_offtopic" && !canSkipNonMusic) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (!Config.config.manualSkipOnFullVideo || !sponsorTimes?.some((s) => s.category === segment.category && s.actionType === ActionType.Full))
|
return (!Config.config.manualSkipOnFullVideo || !sponsorTimes?.some((s) => s.category === segment.category && s.actionType === ActionType.Full))
|
||||||
&& (utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
&& (utils.getCategorySelection(segment.category)?.option === CategorySkipOption.AutoSkip ||
|
||||||
(Config.config.autoSkipOnMusicVideos && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
(Config.config.autoSkipOnMusicVideos && canSkipNonMusic && sponsorTimes?.some((s) => s.category === "music_offtopic")
|
||||||
&& segment.actionType === ActionType.Skip)
|
&& segment.actionType === ActionType.Skip)
|
||||||
|| sponsorTimesSubmitting.some((s) => s.segment === segment.segment))
|
|| sponsorTimesSubmitting.some((s) => s.segment === segment.segment))
|
||||||
|| isLoopedChapter(segment);
|
|| isLoopedChapter(segment);
|
||||||
@@ -2469,7 +2470,7 @@ async function sendSubmitMessage(): Promise<boolean> {
|
|||||||
userID: Config.config.userID,
|
userID: Config.config.userID,
|
||||||
segments: sponsorTimesSubmitting,
|
segments: sponsorTimesSubmitting,
|
||||||
videoDuration: getVideoDuration(),
|
videoDuration: getVideoDuration(),
|
||||||
userAgent: `${chrome.runtime.id}/v${chrome.runtime.getManifest().version}`
|
userAgent: extensionUserAgent(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
@@ -2616,23 +2617,13 @@ async function handleKeybindVote(type: number): Promise<void>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
function addHotkeyListener(): void {
|
function addHotkeyListener(): void {
|
||||||
document.addEventListener("keydown", hotkeyListener);
|
document.addEventListener("keydown", hotkeyListener, true);
|
||||||
|
document.addEventListener("keyup", hotkeyPropagationListener, true);
|
||||||
|
|
||||||
const onLoad = () => {
|
addCleanupListener(() => {
|
||||||
// Allow us to stop propagation to YouTube by being deeper
|
document.body.removeEventListener("keydown", hotkeyListener, true);
|
||||||
document.removeEventListener("keydown", hotkeyListener);
|
document.body.removeEventListener("keyup", hotkeyPropagationListener, true);
|
||||||
document.body.addEventListener("keydown", hotkeyListener);
|
});
|
||||||
|
|
||||||
addCleanupListener(() => {
|
|
||||||
document.body.removeEventListener("keydown", hotkeyListener);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
if (document.readyState === "complete") {
|
|
||||||
onLoad();
|
|
||||||
} else {
|
|
||||||
document.addEventListener("DOMContentLoaded", onLoad);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function hotkeyListener(e: KeyboardEvent): void {
|
function hotkeyListener(e: KeyboardEvent): void {
|
||||||
@@ -2662,7 +2653,7 @@ function hotkeyListener(e: KeyboardEvent): void {
|
|||||||
const downvoteKey = Config.config.downvoteKeybind;
|
const downvoteKey = Config.config.downvoteKeybind;
|
||||||
|
|
||||||
if (keybindEquals(key, skipKey)) {
|
if (keybindEquals(key, skipKey)) {
|
||||||
if (activeSkipKeybindElement) {
|
if (activeSkipKeybindElement && !(activeSkipKeybindElement instanceof SkipButtonControlBar)) {
|
||||||
activeSkipKeybindElement.toggleSkip.call(activeSkipKeybindElement);
|
activeSkipKeybindElement.toggleSkip.call(activeSkipKeybindElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2712,6 +2703,32 @@ function hotkeyListener(e: KeyboardEvent): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hotkeyPropagationListener(e: KeyboardEvent): void {
|
||||||
|
if ((["textarea", "input"].includes(document.activeElement?.tagName?.toLowerCase())
|
||||||
|
|| (document.activeElement as HTMLElement)?.isContentEditable
|
||||||
|
|| document.activeElement?.id?.toLowerCase()?.match(/editable|input/))
|
||||||
|
&& document.hasFocus()) return;
|
||||||
|
|
||||||
|
const key: Keybind = {
|
||||||
|
key: e.key,
|
||||||
|
code: e.code,
|
||||||
|
alt: e.altKey,
|
||||||
|
ctrl: e.ctrlKey,
|
||||||
|
shift: e.shiftKey
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextChapterKey = Config.config.nextChapterKeybind;
|
||||||
|
const previousChapterKey = Config.config.previousChapterKeybind;
|
||||||
|
|
||||||
|
if (keybindEquals(key, nextChapterKey)) {
|
||||||
|
if (sponsorTimes.length > 0) e.stopPropagation();
|
||||||
|
return;
|
||||||
|
} else if (keybindEquals(key, previousChapterKey)) {
|
||||||
|
if (sponsorTimes.length > 0) e.stopPropagation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the CSS to the page if needed. Required on optional sites with Chrome.
|
* Adds the CSS to the page if needed. Required on optional sites with Chrome.
|
||||||
*/
|
*/
|
||||||
@@ -2761,7 +2778,7 @@ function showTimeWithoutSkips(skippedDuration: number): void {
|
|||||||
isOnInvidious() ? ".vjs-duration" :
|
isOnInvidious() ? ".vjs-duration" :
|
||||||
isOnYTTV() ? ".ypl-full-controls .ypmcs-control .time-info-bar" :
|
isOnYTTV() ? ".ypl-full-controls .ypmcs-control .time-info-bar" :
|
||||||
isOnMobileYouTube() ? ".ytwPlayerTimeDisplayContent" :
|
isOnMobileYouTube() ? ".ytwPlayerTimeDisplayContent" :
|
||||||
".ytp-time-display.notranslate .ytp-time-wrapper";
|
".ytp-time-display.notranslate .ytp-time-wrapper .ytp-time-contents";
|
||||||
const display = document.querySelector(selector);
|
const display = document.querySelector(selector);
|
||||||
if (!display) return;
|
if (!display) return;
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import Config from "../config";
|
|||||||
|
|
||||||
export function getControls(): HTMLElement {
|
export function getControls(): HTMLElement {
|
||||||
const controlsSelectors = [
|
const controlsSelectors = [
|
||||||
// YouTube
|
|
||||||
".ytp-right-controls",
|
|
||||||
// New YouTube (2025 April)
|
// New YouTube (2025 April)
|
||||||
".ytp-right-controls-right",
|
".ytp-right-controls-right",
|
||||||
|
// YouTube
|
||||||
|
".ytp-right-controls",
|
||||||
// Mobile YouTube
|
// Mobile YouTube
|
||||||
".player-controls-top",
|
".player-controls-top",
|
||||||
// Invidious/videojs video element's controls element
|
// Invidious/videojs video element's controls element
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import * as CompileConfig from "../../config.json";
|
|||||||
import { ActionType, ActionTypes, SponsorSourceType, SponsorTime, VideoID } from "../types";
|
import { ActionType, ActionTypes, SponsorSourceType, SponsorTime, VideoID } from "../types";
|
||||||
import { getHashParams } from "./pageUtils";
|
import { getHashParams } from "./pageUtils";
|
||||||
import { asyncRequestToServer } from "./requests";
|
import { asyncRequestToServer } from "./requests";
|
||||||
|
import { extensionUserAgent } from "../../maze-utils/src";
|
||||||
|
|
||||||
const segmentDataCache = new DataCache<VideoID, SegmentResponse>(() => {
|
const segmentDataCache = new DataCache<VideoID, SegmentResponse>(() => {
|
||||||
return {
|
return {
|
||||||
@@ -57,7 +58,7 @@ async function fetchSegmentsForVideo(videoID: VideoID): Promise<SegmentResponse>
|
|||||||
trimUUIDs: hasDownvotedSegments ? null : 5,
|
trimUUIDs: hasDownvotedSegments ? null : 5,
|
||||||
...extraRequestData
|
...extraRequestData
|
||||||
}, {
|
}, {
|
||||||
"X-CLIENT-NAME": `${chrome.runtime.id}/v${chrome.runtime.getManifest().version}`
|
"X-CLIENT-NAME": extensionUserAgent(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ async function editSegments(driver: WebDriver, index: number, expectedStartTimeB
|
|||||||
await endTimeBox.clear();
|
await endTimeBox.clear();
|
||||||
await endTimeBox.sendKeys(endTime);
|
await endTimeBox.sendKeys(endTime);
|
||||||
|
|
||||||
|
await driver.sleep(1000);
|
||||||
|
|
||||||
editButton = await driver.findElement(By.id("sponsorTimeEditButtonSubmissionNotice" + index));
|
editButton = await driver.findElement(By.id("sponsorTimeEditButtonSubmissionNotice" + index));
|
||||||
await editButton.click();
|
await editButton.click();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user