Compare commits

..

30 Commits
5.5.9 ... 5.7

Author SHA1 Message Date
Ajay
e9a77355bb bump version 2024-06-23 00:33:39 +05:30
Ajay
116190f2b3 Warn if server-side ad wasn't detected and submitting a segment 2024-06-23 00:31:11 +05:30
Ajay
4bbd59b988 Support server side rendered ads
Fixes #2035
2024-06-23 00:03:03 +05:30
Ajay
5c279d80df Show submission count from server 2024-06-22 17:42:48 +05:30
Ajay
f177b95a5a Fix submission menu after video ends and unskip button after video ends 2024-06-22 17:06:29 +05:30
Ajay Ramachandran
d86dd37ec0 Merge pull request #2046 from ajayyy/mv3
Support mv3
2024-06-22 16:29:43 +05:30
Ajay
fae7d921a7 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock into mv3 2024-06-22 16:27:18 +05:30
Ajay
60a2eff40a Fix linting issue 2024-06-19 23:16:29 +05:30
Ajay
98a4a076bc Support invidious in mv3 2024-06-19 23:14:27 +05:30
Ajay
a95020dda3 Manifest v3 without invidious working 2024-06-19 22:37:29 +05:30
Ajay Ramachandran
5e179cf9ff Merge pull request #2036 from mini-bomba/refresh-fix
Fix refreshing
2024-06-13 09:07:57 +05:30
mini-bomba
0b946d5ef7 Don't fetch segments when videoID is null
Also log an error to the console if we ever try to do this in the future
2024-06-13 01:18:02 +02:00
mini-bomba
f48c57b1c5 Don't inject into the cookie rotate iframe
There's nothing there, it only breaks the refreshing.
2024-06-13 01:09:27 +02:00
Ajay
98ac2fc618 bump version 2024-06-06 19:53:08 +05:30
Ajay
36e3333e39 Fix submission menu disappearing when video ends 2024-06-06 19:52:57 +05:30
Ajay
15fcc971f6 bump version 2024-05-24 03:26:02 -04:00
Ajay
32adbb9581 update translations 2024-05-24 03:22:36 -04:00
Ajay
4ecd02510b Fix warnings 2024-05-24 03:22:07 -04:00
Ajay
0dbb6474b8 Fix preview bar on mobile
Fixes #2021
2024-05-24 03:20:21 -04:00
Ajay
c974c2a6d6 Merge branch 'master' of https://github.com/ajayyy/SponsorBlock 2024-05-24 03:15:59 -04:00
Ajay
a6695254b6 Fix skipping and preview bar on "add to queue", miniplayer and hover preview
Fixes #1486
2024-05-24 03:15:58 -04:00
Ajay
e8a82eddca Change chapters sorting 2024-05-09 19:09:37 -04:00
Ajay Ramachandran
d3684dbedd Merge pull request #2017 from stdedos/fix/disabled-comment-typo
Fix comment typo
2024-05-08 17:54:10 -04:00
Stavros Ntentos
6c9a403731 Fix comment typo
Signed-off-by: Stavros Ntentos <133706+stdedos@users.noreply.github.com>
2024-05-08 23:44:01 +03:00
Ajay
3be51c89a9 Fix popup sometimes saying "No video found"
Fixes #2006
Fixes #2013
Fixes #1999
2024-04-30 20:54:54 -04:00
Ajay
5b845a56e1 Fix unsubmitted segments sometimes manual skipping if manual skip enabled for category
Fixes #2002
2024-04-28 22:59:02 -04:00
Ajay
7b572c3c0e Fix previewed segment check
Fixes #1996
2024-04-28 21:51:35 -04:00
Ajay
56bb22d03d Allow importing segments with no category
Also fixes case when importing chapters when having no permission to submit chapters
2024-04-26 16:44:20 -04:00
Ajay
e1d656f43f Make notice visibility option not appear when notice disabled 2024-04-04 13:54:47 -04:00
Ajay
e14b3c76f9 Improve submission box padding 2024-03-27 16:14:10 -04:00
24 changed files with 671 additions and 433 deletions

View File

@@ -1,12 +1,156 @@
{ {
"optional_permissions": [ "host_permissions": [
"declarativeContent", "https://*.youtube.com/*",
"webNavigation" "https://sponsor.ajay.app/*"
], ],
"background": { "optional_host_permissions": [
"persistent": false "*://*/*"
],
"web_accessible_resources": [{
"resources": [
"icons/LogoSponsorBlocker256px.png",
"icons/IconSponsorBlocker256px.png",
"icons/PlayerStartIconSponsorBlocker.svg",
"icons/PlayerStopIconSponsorBlocker.svg",
"icons/PlayerUploadIconSponsorBlocker.svg",
"icons/PlayerUploadFailedIconSponsorBlocker.svg",
"icons/PlayerCancelSegmentIconSponsorBlocker.svg",
"icons/clipboard.svg",
"icons/settings.svg",
"icons/pencil.svg",
"icons/check.svg",
"icons/check-smaller.svg",
"icons/upvote.png",
"icons/downvote.png",
"icons/thumbs_down.svg",
"icons/thumbs_down_locked.svg",
"icons/thumbs_up.svg",
"icons/help.svg",
"icons/report.png",
"icons/close.png",
"icons/skipIcon.svg",
"icons/refresh.svg",
"icons/beep.ogg",
"icons/pause.svg",
"icons/stop.svg",
"icons/skip.svg",
"icons/heart.svg",
"icons/visible.svg",
"icons/not_visible.svg",
"icons/sort.svg",
"icons/money.svg",
"icons/segway.png",
"icons/close-smaller.svg",
"icons/right-arrow.svg",
"icons/campaign.svg",
"icons/star.svg",
"icons/lightbulb.svg",
"icons/bolt.svg",
"icons/stopwatch.svg",
"icons/music-note.svg",
"icons/import.svg",
"icons/export.svg",
"icons/PlayerInfoIconSponsorBlocker.svg",
"icons/PlayerDeleteIconSponsorBlocker.svg",
"icons/dearrow.svg",
"popup.html",
"popup.css",
"content.css",
"shared.css",
"js/document.js",
"libs/Source+Sans+Pro.css",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2"
],
"matches": ["<all_urls>"]
}],
"content_scripts": [
{
"world": "MAIN",
"js": [
"./js/document.js"
],
"matches": [
"https://*.youtube.com/*",
"https://www.youtube-nocookie.com/embed/*"
],
"exclude_matches": [
"https://accounts.youtube.com/RotateCookiesPage*"
],
"all_frames": true,
"run_at": "document_start"
}, },
"permissions": [ {
"https://*.youtube.com/*" "world": "ISOLATED",
"js": [
"./js/content.js"
],
"css": [
"content.css",
"shared.css"
],
"matches": [
"https://*.youtube.com/*",
"https://www.youtube-nocookie.com/embed/*"
],
"exclude_matches": [
"https://accounts.youtube.com/RotateCookiesPage*"
],
"all_frames": true,
"run_at": "document_start"
}
],
"action": {
"default_title": "SponsorBlock",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/IconSponsorBlocker64px.png",
"128": "icons/IconSponsorBlocker128px.png"
},
"theme_icons": [
{
"light": "icons/IconSponsorBlocker16px.png",
"dark": "icons/IconSponsorBlocker16px.png",
"size": 16
},
{
"light": "icons/IconSponsorBlocker32px.png",
"dark": "icons/IconSponsorBlocker32px.png",
"size": 32
},
{
"light": "icons/IconSponsorBlocker64px.png",
"dark": "icons/IconSponsorBlocker64px.png",
"size": 64
},
{
"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
}
] ]
},
"background": {
"service_worker": "./js/background.js"
},
"manifest_version": 3
} }

View File

@@ -11,9 +11,6 @@
"background": { "background": {
"persistent": false "persistent": false
}, },
"permissions": [
"scripting"
],
"browser_action": { "browser_action": {
"default_area": "navbar" "default_area": "navbar"
} }

View File

@@ -0,0 +1,136 @@
{
"web_accessible_resources": [
"icons/LogoSponsorBlocker256px.png",
"icons/IconSponsorBlocker256px.png",
"icons/PlayerStartIconSponsorBlocker.svg",
"icons/PlayerStopIconSponsorBlocker.svg",
"icons/PlayerUploadIconSponsorBlocker.svg",
"icons/PlayerUploadFailedIconSponsorBlocker.svg",
"icons/PlayerCancelSegmentIconSponsorBlocker.svg",
"icons/clipboard.svg",
"icons/settings.svg",
"icons/pencil.svg",
"icons/check.svg",
"icons/check-smaller.svg",
"icons/upvote.png",
"icons/downvote.png",
"icons/thumbs_down.svg",
"icons/thumbs_down_locked.svg",
"icons/thumbs_up.svg",
"icons/help.svg",
"icons/report.png",
"icons/close.png",
"icons/skipIcon.svg",
"icons/refresh.svg",
"icons/beep.ogg",
"icons/pause.svg",
"icons/stop.svg",
"icons/skip.svg",
"icons/heart.svg",
"icons/visible.svg",
"icons/not_visible.svg",
"icons/sort.svg",
"icons/money.svg",
"icons/segway.png",
"icons/close-smaller.svg",
"icons/right-arrow.svg",
"icons/campaign.svg",
"icons/star.svg",
"icons/lightbulb.svg",
"icons/bolt.svg",
"icons/stopwatch.svg",
"icons/music-note.svg",
"icons/import.svg",
"icons/export.svg",
"icons/PlayerInfoIconSponsorBlocker.svg",
"icons/PlayerDeleteIconSponsorBlocker.svg",
"icons/dearrow.svg",
"popup.html",
"popup.css",
"content.css",
"shared.css",
"js/document.js",
"libs/Source+Sans+Pro.css",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2"
],
"permissions": [
"https://sponsor.ajay.app/*"
],
"optional_permissions": [
"*://*/*"
],
"browser_action": {
"default_title": "SponsorBlock",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/IconSponsorBlocker64px.png",
"128": "icons/IconSponsorBlocker128px.png"
},
"theme_icons": [
{
"light": "icons/IconSponsorBlocker16px.png",
"dark": "icons/IconSponsorBlocker16px.png",
"size": 16
},
{
"light": "icons/IconSponsorBlocker32px.png",
"dark": "icons/IconSponsorBlocker32px.png",
"size": 32
},
{
"light": "icons/IconSponsorBlocker64px.png",
"dark": "icons/IconSponsorBlocker64px.png",
"size": 64
},
{
"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
}
]
},
"background": {
"scripts":[
"./js/background.js"
]
},
"content_scripts": [{
"run_at": "document_start",
"matches": [
"https://*.youtube.com/*",
"https://www.youtube-nocookie.com/embed/*"
],
"exclude_matches": [
"https://accounts.youtube.com/RotateCookiesPage*"
],
"all_frames": true,
"js": [
"./js/content.js"
],
"css": [
"content.css",
"shared.css"
]
}],
"manifest_version": 2
}

View File

@@ -1,141 +1,10 @@
{ {
"name": "__MSG_fullName__", "name": "__MSG_fullName__",
"short_name": "SponsorBlock", "short_name": "SponsorBlock",
"version": "5.5.9", "version": "5.7",
"default_locale": "en", "default_locale": "en",
"description": "__MSG_Description__", "description": "__MSG_Description__",
"homepage_url": "https://sponsor.ajay.app", "homepage_url": "https://sponsor.ajay.app",
"content_scripts": [{
"run_at": "document_start",
"matches": [
"https://*.youtube.com/*",
"https://www.youtube-nocookie.com/embed/*"
],
"all_frames": true,
"js": [
"./js/content.js"
],
"css": [
"content.css",
"shared.css"
]
}],
"web_accessible_resources": [
"icons/LogoSponsorBlocker256px.png",
"icons/IconSponsorBlocker256px.png",
"icons/PlayerStartIconSponsorBlocker.svg",
"icons/PlayerStopIconSponsorBlocker.svg",
"icons/PlayerUploadIconSponsorBlocker.svg",
"icons/PlayerUploadFailedIconSponsorBlocker.svg",
"icons/PlayerCancelSegmentIconSponsorBlocker.svg",
"icons/clipboard.svg",
"icons/settings.svg",
"icons/pencil.svg",
"icons/check.svg",
"icons/check-smaller.svg",
"icons/upvote.png",
"icons/downvote.png",
"icons/thumbs_down.svg",
"icons/thumbs_down_locked.svg",
"icons/thumbs_up.svg",
"icons/help.svg",
"icons/report.png",
"icons/close.png",
"icons/skipIcon.svg",
"icons/refresh.svg",
"icons/beep.ogg",
"icons/pause.svg",
"icons/stop.svg",
"icons/skip.svg",
"icons/heart.svg",
"icons/visible.svg",
"icons/not_visible.svg",
"icons/sort.svg",
"icons/money.svg",
"icons/segway.png",
"icons/close-smaller.svg",
"icons/right-arrow.svg",
"icons/campaign.svg",
"icons/star.svg",
"icons/lightbulb.svg",
"icons/bolt.svg",
"icons/stopwatch.svg",
"icons/music-note.svg",
"icons/import.svg",
"icons/export.svg",
"icons/PlayerInfoIconSponsorBlocker.svg",
"icons/PlayerDeleteIconSponsorBlocker.svg",
"icons/dearrow.svg",
"popup.html",
"popup.css",
"content.css",
"shared.css",
"js/document.js",
"libs/Source+Sans+Pro.css",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2",
"libs/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2"
],
"permissions": [
"storage",
"https://sponsor.ajay.app/*"
],
"optional_permissions": [
"*://*/*"
],
"browser_action": {
"default_title": "SponsorBlock",
"default_popup": "popup.html",
"default_icon": {
"16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png",
"64": "icons/IconSponsorBlocker64px.png",
"128": "icons/IconSponsorBlocker128px.png"
},
"theme_icons": [
{
"light": "icons/IconSponsorBlocker16px.png",
"dark": "icons/IconSponsorBlocker16px.png",
"size": 16
},
{
"light": "icons/IconSponsorBlocker32px.png",
"dark": "icons/IconSponsorBlocker32px.png",
"size": 32
},
{
"light": "icons/IconSponsorBlocker64px.png",
"dark": "icons/IconSponsorBlocker64px.png",
"size": 64
},
{
"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
}
]
},
"background": {
"scripts":[
"./js/background.js"
]
},
"icons": { "icons": {
"16": "icons/IconSponsorBlocker16px.png", "16": "icons/IconSponsorBlocker16px.png",
"32": "icons/IconSponsorBlocker32px.png", "32": "icons/IconSponsorBlocker32px.png",
@@ -145,9 +14,12 @@
"512": "icons/IconSponsorBlocker512px.png", "512": "icons/IconSponsorBlocker512px.png",
"1024": "icons/IconSponsorBlocker1024px.png" "1024": "icons/IconSponsorBlocker1024px.png"
}, },
"permissions": [
"storage",
"scripting"
],
"options_ui": { "options_ui": {
"page": "options/options.html", "page": "options/options.html",
"open_in_tab": true "open_in_tab": true
}, }
"manifest_version": 2
} }

View File

@@ -2,9 +2,6 @@
"background": { "background": {
"persistent": false "persistent": false
}, },
"permissions": [
"scripting"
],
"optional_permissions": [ "optional_permissions": [
"webNavigation" "webNavigation"
] ]

View File

@@ -26,6 +26,11 @@
transition: transform .1s cubic-bezier(0,0,0.2,1); transition: transform .1s cubic-bezier(0,0,0.2,1);
} }
/* May 2024 hover preview */
.YtPlayerProgressBarProgressBar #previewbar {
transform: none;
}
.ytp-big-mode #previewbar { .ytp-big-mode #previewbar {
transform: scaleY(0.625) translateY(-30%) translateY(1.5px); transform: scaleY(0.625) translateY(-30%) translateY(1.5px);
} }

View File

@@ -219,9 +219,10 @@
__MSG_showSkipNotice__ __MSG_showSkipNotice__
</label> </label>
</div> </div>
</div>
<div data-type="selector" data-sync="noticeVisibilityMode"> <div data-type="selector" data-sync="noticeVisibilityMode" data-dependent-on="dontShowNotice">
<br/>
<label class="optionLabel" for="noticeVisibilityMode">__MSG_noticeVisibilityLabel__:</label> <label class="optionLabel" for="noticeVisibilityMode">__MSG_noticeVisibilityLabel__:</label>
<select id="noticeVisibilityMode" class="selector-element optionsSelector" > <select id="noticeVisibilityMode" class="selector-element optionsSelector" >
@@ -232,6 +233,7 @@
<option value="4">__MSG_noticeVisibilityMode4__</option> <option value="4">__MSG_noticeVisibilityMode4__</option>
</select> </select>
</div> </div>
</div>
<div data-type="toggle" data-sync="showCategoryGuidelines"> <div data-type="toggle" data-sync="showCategoryGuidelines">
<div class="switch-container"> <div class="switch-container">

View File

@@ -7,13 +7,9 @@ import { sendRealRequestToCustomServer, setupBackgroundRequestProxy } from "../m
import { setupTabUpdates } from "../maze-utils/src/tab-updates"; import { setupTabUpdates } from "../maze-utils/src/tab-updates";
import { generateUserID } from "../maze-utils/src/setup"; import { generateUserID } from "../maze-utils/src/setup";
// Make the config public for debugging purposes
window.SB = Config;
import Utils from "./utils"; import Utils from "./utils";
import { getExtensionIdsToImportFrom } from "./utils/crossExtension"; import { getExtensionIdsToImportFrom } from "./utils/crossExtension";
import { isFirefoxOrSafari } from "../maze-utils/src"; import { isFirefoxOrSafari, waitFor } from "../maze-utils/src";
import { injectUpdatedScripts } from "../maze-utils/src/cleanup"; import { injectUpdatedScripts } from "../maze-utils/src/cleanup";
import { logWarn } from "./utils/logger"; import { logWarn } from "./utils/logger";
import { chromeP } from "../maze-utils/src/browserApi"; import { chromeP } from "../maze-utils/src/browserApi";
@@ -142,9 +138,16 @@ chrome.runtime.onInstalled.addListener(function () {
} }
}, 1500); }, 1500);
// Only do this once the old version understands how to clean itself up if (!isFirefoxOrSafari()) {
if (!isFirefoxOrSafari() && chrome.runtime.getManifest().version !== "5.4.13") {
injectUpdatedScripts().catch(logWarn); injectUpdatedScripts().catch(logWarn);
waitFor(() => Config.isReady()).then(() => {
if (Config.config.supportInvidious) {
injectUpdatedScripts([
utils.getExtraSiteRegistration()
])
}
}).catch(logWarn);
} }
}); });

View File

@@ -15,6 +15,7 @@ import { downvoteButtonColor, SkipNoticeAction } from "../utils/noticeUtils";
import { generateUserID } from "../../maze-utils/src/setup"; import { generateUserID } from "../../maze-utils/src/setup";
import { keybindToString } from "../../maze-utils/src/config"; import { keybindToString } from "../../maze-utils/src/config";
import { getFormattedTime } from "../../maze-utils/src/formating"; import { getFormattedTime } from "../../maze-utils/src/formating";
import { getCurrentTime, getVideo } from "../../maze-utils/src/video";
enum SkipButtonState { enum SkipButtonState {
Undo, // Unskip Undo, // Unskip
@@ -685,7 +686,7 @@ class SkipNoticeComponent extends React.Component<SkipNoticeProps, SkipNoticeSta
getFullDurationCountdown(index: number): () => number { getFullDurationCountdown(index: number): () => number {
return () => { return () => {
const sponsorTime = this.segments[index]; const sponsorTime = this.segments[index];
const duration = Math.round((sponsorTime.segment[1] - this.contentContainer().v.currentTime) * (1 / this.contentContainer().v.playbackRate)); const duration = Math.round((sponsorTime.segment[1] - getCurrentTime()) * (1 / getVideo().playbackRate));
return Math.max(duration, Config.config.skipNoticeDuration); return Math.max(duration, Config.config.skipNoticeDuration);
}; };

View File

@@ -9,6 +9,7 @@ import { DEFAULT_CATEGORY } from "../utils/categoryUtils";
import { getFormattedTime, getFormattedTimeToSeconds } from "../../maze-utils/src/formating"; import { getFormattedTime, getFormattedTimeToSeconds } from "../../maze-utils/src/formating";
import { asyncRequestToServer } from "../utils/requests"; import { asyncRequestToServer } from "../utils/requests";
import { defaultPreviewTime } from "../utils/constants"; import { defaultPreviewTime } from "../utils/constants";
import { getVideo, getVideoDuration } from "../../maze-utils/src/video";
export interface SponsorTimeEditProps { export interface SponsorTimeEditProps {
index: number; index: number;
@@ -272,10 +273,9 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
</div> </div>
): ""} ): ""}
<br/>
{/* Editing Tools */} {/* Editing Tools */}
<div style={{ marginTop: "3px" }}>
<span id={"sponsorTimeDeleteButton" + this.idSuffix} <span id={"sponsorTimeDeleteButton" + this.idSuffix}
className="sponsorTimeEditButton" className="sponsorTimeEditButton"
onClick={this.deleteTime.bind(this)}> onClick={this.deleteTime.bind(this)}>
@@ -315,6 +315,8 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
</span> </span>
): ""} ): ""}
</div> </div>
</div>
); );
} }
@@ -400,7 +402,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
checkToShowFullVideoWarning(): void { checkToShowFullVideoWarning(): void {
const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index]; const sponsorTime = this.props.contentContainer().sponsorTimesSubmitting[this.props.index];
const segmentDuration = sponsorTime.segment[1] - sponsorTime.segment[0]; const segmentDuration = sponsorTime.segment[1] - sponsorTime.segment[0];
const videoPercentage = segmentDuration / this.props.contentContainer().v.duration; const videoPercentage = segmentDuration / getVideoDuration();
if (videoPercentage > 0.6 && !this.fullVideoWarningShown if (videoPercentage > 0.6 && !this.fullVideoWarningShown
&& (sponsorTime.category === "sponsor" || sponsorTime.category === "selfpromo" || sponsorTime.category === "chooseACategory")) { && (sponsorTime.category === "sponsor" || sponsorTime.category === "selfpromo" || sponsorTime.category === "chooseACategory")) {
@@ -552,7 +554,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
} }
setTimeToEnd(): void { setTimeToEnd(): void {
this.setTimeTo(1, this.props.contentContainer().v.duration); this.setTimeTo(1, getVideoDuration());
} }
/** /**
@@ -639,7 +641,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
sponsorTimesSubmitting[this.props.index].segment[0] = startTime; sponsorTimesSubmitting[this.props.index].segment[0] = startTime;
} }
} else if (this.state.sponsorTimeEdits[1] === null && category === "outro" && !sponsorTimesSubmitting[this.props.index].segment[1]) { } else if (this.state.sponsorTimeEdits[1] === null && category === "outro" && !sponsorTimesSubmitting[this.props.index].segment[1]) {
sponsorTimesSubmitting[this.props.index].segment[1] = this.props.contentContainer().v.duration; sponsorTimesSubmitting[this.props.index].segment[1] = getVideoDuration();
this.props.contentContainer().updateEditButtonsOnPlayer(); this.props.contentContainer().updateEditButtonsOnPlayer();
} }
@@ -682,7 +684,7 @@ class SponsorTimeEditComponent extends React.Component<SponsorTimeEditProps, Spo
const endTime = sponsorTimes[index].segment[1]; const endTime = sponsorTimes[index].segment[1];
// If segment starts at 0:00, start playback at the end of the segment // If segment starts at 0:00, start playback at the end of the segment
const skipTime = (startTime === 0 || skipToEndTime) ? endTime : (startTime - (seekTime * this.props.contentContainer().v.playbackRate)); const skipTime = (startTime === 0 || skipToEndTime) ? endTime : (startTime - (seekTime * getVideo().playbackRate));
this.props.contentContainer().previewTime(skipTime, !skipToEndTime); this.props.contentContainer().previewTime(skipTime, !skipToEndTime);
} }

View File

@@ -9,6 +9,7 @@ import NoticeTextSelectionComponent from "./NoticeTextSectionComponent";
import SponsorTimeEditComponent from "./SponsorTimeEditComponent"; import SponsorTimeEditComponent from "./SponsorTimeEditComponent";
import { getGuidelineInfo } from "../utils/constants"; import { getGuidelineInfo } from "../utils/constants";
import { exportTimes } from "../utils/exporter"; import { exportTimes } from "../utils/exporter";
import { getVideo, isCurrentTimeWrong } from "../../maze-utils/src/video";
export interface SubmissionNoticeProps { export interface SubmissionNoticeProps {
// Contains functions and variables from the content script needed by the skip notice // Contains functions and variables from the content script needed by the skip notice
@@ -66,7 +67,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
this.forceUpdate(); this.forceUpdate();
}); });
this.videoObserver.observe(this.contentContainer().v, { this.videoObserver.observe(getVideo(), {
attributes: true attributes: true
}); });
@@ -131,7 +132,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
{/* Sponsor Time List */} {/* Sponsor Time List */}
<tr id={"sponsorSkipNoticeMiddleRow" + this.state.idSuffix} <tr id={"sponsorSkipNoticeMiddleRow" + this.state.idSuffix}
className="sponsorTimeMessagesRow" className="sponsorTimeMessagesRow"
style={{maxHeight: (this.contentContainer().v.offsetHeight - 200) + "px"}} style={{maxHeight: (getVideo()?.offsetHeight - 200) + "px"}}
onMouseDown={(e) => e.stopPropagation()}> onMouseDown={(e) => e.stopPropagation()}>
<td style={{width: "100%"}}> <td style={{width: "100%"}}>
{this.getSponsorTimeMessages()} {this.getSponsorTimeMessages()}
@@ -215,6 +216,11 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
} }
submit(): void { submit(): void {
if (isCurrentTimeWrong()) {
alert(chrome.i18n.getMessage("submissionFailedServerSideAds"));
return;
}
// save all items // save all items
for (const ref of this.timeEditRefs) { for (const ref of this.timeEditRefs) {
ref.current.saveEditTimes(); ref.current.saveEditTimes();
@@ -283,7 +289,7 @@ class SubmissionNoticeComponent extends React.Component<SubmissionNoticeProps, S
categoryChangeListener(index: number, category: Category): void { categoryChangeListener(index: number, category: Category): void {
const dialogWidth = this.noticeRef?.current?.getElement()?.current?.offsetWidth; const dialogWidth = this.noticeRef?.current?.getElement()?.current?.offsetWidth;
if (category !== "chooseACategory" && Config.config.showCategoryGuidelines if (category !== "chooseACategory" && Config.config.showCategoryGuidelines
&& this.contentContainer().v.offsetWidth > dialogWidth * 2) { && getVideo().offsetWidth > dialogWidth * 2) {
const options = { const options = {
title: chrome.i18n.getMessage(`category_${category}`), title: chrome.i18n.getMessage(`category_${category}`),
textBoxes: getGuidelineInfo(category), textBoxes: getGuidelineInfo(category),

View File

@@ -140,7 +140,7 @@ interface SBStorage {
downvotedSegments: Record<VideoID & HashedValue, VideoDownvotes>; downvotedSegments: Record<VideoID & HashedValue, VideoDownvotes>;
navigationApiAvailable: boolean; navigationApiAvailable: boolean;
// Used when sync storage disbaled // Used when sync storage disabled
alreadyInstalled: boolean; alreadyInstalled: boolean;
/* Contains unsubmitted segments that the user has created. */ /* Contains unsubmitted segments that the user has created. */

View File

@@ -34,7 +34,7 @@ import { ChapterVote } from "./render/ChapterVote";
import { openWarningDialog } from "./utils/warnings"; import { openWarningDialog } from "./utils/warnings";
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src"; import { 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 } from "../maze-utils/src/video"; import { getChannelIDInfo, getVideo, getIsAdPlaying, getIsLivePremiere, setIsAdPlaying, checkVideoIDChange, getVideoID, getYouTubeVideoID, setupVideoModule, checkIfNewVideoID, isOnInvidious, isOnMobileYouTube, getLastNonInlineVideoID, triggerVideoIDChange, triggerVideoElementChange, getIsInline, getCurrentTime, setCurrentTime, getVideoDuration, verifyCurrentTime } 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";
import { findValidElement } from "../maze-utils/src/dom" import { findValidElement } from "../maze-utils/src/dom"
import { getHash, HashedValue } from "../maze-utils/src/hash"; import { getHash, HashedValue } from "../maze-utils/src/hash";
@@ -49,6 +49,7 @@ import { hideDeArrowPromotion, tryShowingDeArrowPromotion } from "./dearrowPromo
import { asyncRequestToServer } from "./utils/requests"; import { asyncRequestToServer } from "./utils/requests";
import { isMobileControlsOpen } from "./utils/mobileUtils"; import { isMobileControlsOpen } from "./utils/mobileUtils";
import { defaultPreviewTime } from "./utils/constants"; import { defaultPreviewTime } from "./utils/constants";
import { onVideoPage } from "../maze-utils/src/pageInfo";
cleanPage(); cleanPage();
@@ -72,6 +73,8 @@ let sponsorDataFound = false;
let sponsorTimes: SponsorTime[] = []; let sponsorTimes: SponsorTime[] = [];
let existingChaptersImported = false; let existingChaptersImported = false;
let importingChaptersWaitingForFocus = false; let importingChaptersWaitingForFocus = false;
let importingChaptersWaiting = false;
let triedImportingChapters = false;
// List of open skip notices // List of open skip notices
const skipNotices: SkipNotice[] = []; const skipNotices: SkipNotice[] = [];
let activeSkipKeybindElement: ToggleSkippable = null; let activeSkipKeybindElement: ToggleSkippable = null;
@@ -124,13 +127,10 @@ setupVideoModule({
updateVisibilityOfPlayerControlsButton(); updateVisibilityOfPlayerControlsButton();
}, },
resetValues, resetValues,
documentScript documentScript: chrome.runtime.getManifest().manifest_version === 2 ? documentScript : undefined
}, () => Config); }, () => Config);
setupThumbnailListener(); setupThumbnailListener();
//the video id of the last preview bar update
let lastPreviewBarUpdate: VideoID;
// Is the video currently being switched // Is the video currently being switched
let switchingVideos = null; let switchingVideos = null;
@@ -168,7 +168,6 @@ let submissionNotice: SubmissionNotice = null;
let lastResponseStatus: number; let lastResponseStatus: number;
let retryCount = 0; let retryCount = 0;
let lookupWaiting = false;
// Contains all of the functions and variables needed by the skip notice // Contains all of the functions and variables needed by the skip notice
const skipNoticeContentContainer: ContentContainer = () => ({ const skipNoticeContentContainer: ContentContainer = () => ({
@@ -178,7 +177,6 @@ const skipNoticeContentContainer: ContentContainer = () => ({
sponsorTimes, sponsorTimes,
sponsorTimesSubmitting, sponsorTimesSubmitting,
skipNotices, skipNotices,
v: getVideo(),
sponsorVideoID: getVideoID(), sponsorVideoID: getVideoID(),
reskipSponsorTime, reskipSponsorTime,
updatePreviewBar, updatePreviewBar,
@@ -219,7 +217,7 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
found: sponsorDataFound, found: sponsorDataFound,
status: lastResponseStatus, status: lastResponseStatus,
sponsorTimes: sponsorTimes, sponsorTimes: sponsorTimes,
time: getVideo().currentTime, time: getCurrentTime() ?? 0,
onMobileYouTube: isOnMobileYouTube() onMobileYouTube: isOnMobileYouTube()
}); });
@@ -265,7 +263,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
// it will assume the page is not a video page and stop the refresh animation // it will assume the page is not a video page and stop the refresh animation
sendResponse({ hasVideo: getVideoID() != null }); sendResponse({ hasVideo: getVideoID() != null });
// fetch segments // fetch segments
if (getVideoID()) {
sponsorsLookup(false); sponsorsLookup(false);
}
break; break;
case "unskip": case "unskip":
@@ -297,13 +297,15 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo
navigator.clipboard.writeText(request.text); navigator.clipboard.writeText(request.text);
break; break;
case "importSegments": { case "importSegments": {
const importedSegments = importTimes(request.data, getVideo().duration); const importedSegments = importTimes(request.data, getVideoDuration());
let addedSegments = false; let addedSegments = false;
for (const segment of importedSegments) { for (const segment of importedSegments) {
if (!sponsorTimesSubmitting.some( if (!sponsorTimesSubmitting.some(
(s) => Math.abs(s.segment[0] - segment.segment[0]) < 1 (s) => Math.abs(s.segment[0] - segment.segment[0]) < 1
&& Math.abs(s.segment[1] - segment.segment[1]) < 1)) { && Math.abs(s.segment[1] - segment.segment[1]) < 1)) {
if (segment.category === "chapter" && !utils.getCategorySelection("chapter")) { const hasChaptersPermission = (Config.config.showCategoryWithoutPermission
|| Config.config.permissions["chapter"]);
if (segment.category === "chapter" && (!utils.getCategorySelection("chapter") || !hasChaptersPermission)) {
segment.category = "chooseACategory" as Category; segment.category = "chooseACategory" as Category;
segment.actionType = ActionType.Skip; segment.actionType = ActionType.Skip;
segment.description = ""; segment.description = "";
@@ -382,6 +384,7 @@ function resetValues() {
sponsorTimes = []; sponsorTimes = [];
existingChaptersImported = false; existingChaptersImported = false;
triedImportingChapters = false;
sponsorSkipped = []; sponsorSkipped = [];
lastResponseStatus = 0; lastResponseStatus = 0;
shownSegmentFailedToFetchWarning = false; shownSegmentFailedToFetchWarning = false;
@@ -398,8 +401,9 @@ function resetValues() {
//reset sponsor data found check //reset sponsor data found check
sponsorDataFound = false; sponsorDataFound = false;
if (switchingVideos === null) {
// When first loading a video, it is not switching videos // When first loading a video, it is not switching videos
// Hover play also doesn't need this check
if (switchingVideos === null || !onVideoPage()) {
switchingVideos = false; switchingVideos = false;
} else { } else {
switchingVideos = true; switchingVideos = true;
@@ -456,6 +460,17 @@ function videoIDChange(): void {
updateSponsorTimesSubmitting(); updateSponsorTimesSubmitting();
tryShowingDeArrowPromotion().catch(logWarn); tryShowingDeArrowPromotion().catch(logWarn);
checkPreviewbarState();
if (getIsInline()) {
// Hover preview progress bar can take some time to appear
// and if the miniplayer is also active then it would
// attach to the wrong one
setTimeout(checkPreviewbarState, 500);
setTimeout(checkPreviewbarState, 1000);
setTimeout(checkPreviewbarState, 3000);
}
} }
function handleMobileControlsMutations(): void { function handleMobileControlsMutations(): void {
@@ -484,12 +499,7 @@ function handleMobileControlsMutations(): void {
createPreviewBar(); createPreviewBar();
} }
/** function getPreviewBarAttachElement(): HTMLElement | null {
* Creates a preview bar on the video
*/
function createPreviewBar(): void {
if (previewBar !== null) return;
const progressElementOptions = [{ const progressElementOptions = [{
// For new mobile YouTube (#1287) // For new mobile YouTube (#1287)
selector: ".progress-bar-line", selector: ".progress-bar-line",
@@ -499,11 +509,22 @@ function createPreviewBar(): void {
selector: ".YtProgressBarProgressBarLine", selector: ".YtProgressBarProgressBarLine",
isVisibleCheck: true isVisibleCheck: true
}, { }, {
// For Desktop YouTube // For newer mobile YouTube (May 2024)
selector: ".YtmProgressBarProgressBarLine",
isVisibleCheck: true
}, {
// For desktop YouTube hover play
// Priority is given to the hover play progress bar over the main progress bar
// for miniplayer + hover preview case
// Second is new hover play selector
selector: "#video-preview .ytp-progress-bar, #video-preview .YtProgressBarLineHost",
isVisibleCheck: true
}, {
// For desktop YouTube
selector: ".ytp-progress-bar", selector: ".ytp-progress-bar",
isVisibleCheck: true isVisibleCheck: true
}, { }, {
// For Desktop YouTube // For desktop YouTube
selector: ".no-model.cue-range-marker", selector: ".no-model.cue-range-marker",
isVisibleCheck: true isVisibleCheck: true
}, { }, {
@@ -525,14 +546,27 @@ function createPreviewBar(): void {
const allElements = document.querySelectorAll(option.selector) as NodeListOf<HTMLElement>; const allElements = document.querySelectorAll(option.selector) as NodeListOf<HTMLElement>;
const el = option.isVisibleCheck ? findValidElement(allElements) : allElements[0]; const el = option.isVisibleCheck ? findValidElement(allElements) : allElements[0];
if (el) {
return el;
}
}
return null;
}
/**
* Creates a preview bar on the video
*/
function createPreviewBar(): void {
if (previewBar !== null) return;
const el = getPreviewBarAttachElement();
if (el) { if (el) {
const chapterVote = new ChapterVote(voteAsync); const chapterVote = new ChapterVote(voteAsync);
previewBar = new PreviewBar(el, isOnMobileYouTube(), isOnInvidious(), chapterVote, () => importExistingChapters(true)); previewBar = new PreviewBar(el, isOnMobileYouTube(), isOnInvidious(), chapterVote, () => importExistingChapters(true));
updatePreviewBar(); updatePreviewBar();
break;
}
} }
} }
@@ -600,7 +634,7 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
updateActiveSegment(currentTime); updateActiveSegment(currentTime);
if (getVideo().paused if (getVideo().paused
|| (getVideo().currentTime >= getVideo().duration - 0.01 && getVideo().duration > 1)) return; || (getCurrentTime() >= getVideoDuration() - 0.01 && getVideoDuration() > 1)) return;
const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments); const skipInfo = getNextSkipIndex(currentTime, includeIntersectingSegments, includeNonIntersectingSegments);
const currentSkip = skipInfo.array[skipInfo.index]; const currentSkip = skipInfo.array[skipInfo.index];
@@ -650,7 +684,7 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
let forcedIncludeNonIntersectingSegments = true; let forcedIncludeNonIntersectingSegments = true;
if (incorrectVideoCheck(videoID, currentSkip)) return; if (incorrectVideoCheck(videoID, currentSkip)) return;
forceVideoTime ||= Math.max(getVideo().currentTime, getVirtualTime()); forceVideoTime ||= Math.max(getCurrentTime(), getVirtualTime());
if ((shouldSkip(currentSkip) || sponsorTimesSubmitting?.some((segment) => segment.segment === currentSkip.segment))) { if ((shouldSkip(currentSkip) || sponsorTimesSubmitting?.some((segment) => segment.segment === currentSkip.segment))) {
if (forceVideoTime >= skipTime[0] - skipBuffer && forceVideoTime < skipTime[1]) { if (forceVideoTime >= skipTime[0] - skipBuffer && forceVideoTime < skipTime[1]) {
@@ -682,7 +716,7 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
forcedIncludeNonIntersectingSegments = false; forcedIncludeNonIntersectingSegments = false;
// Only if not at the end of the video // Only if not at the end of the video
if (Math.abs(skipTime[1] - getVideo().duration) > endTimeSkipBuffer) { if (Math.abs(skipTime[1] - getVideoDuration()) > endTimeSkipBuffer) {
forcedIncludeIntersectingSegments = true; forcedIncludeIntersectingSegments = true;
} }
} }
@@ -713,38 +747,38 @@ async function startSponsorSchedule(includeIntersectingSegments = false, current
// Use interval instead of timeout near the end to combat imprecise video time // Use interval instead of timeout near the end to combat imprecise video time
const startIntervalTime = forceStartIntervalTime || performance.now(); const startIntervalTime = forceStartIntervalTime || performance.now();
const startVideoTime = Math.max(currentTime, getVideo().currentTime); const startVideoTime = Math.max(currentTime, getCurrentTime());
delayTime = (skipTime?.[0] - startVideoTime) * 1000 * (1 / getVideo().playbackRate); delayTime = (skipTime?.[0] - startVideoTime) * 1000 * (1 / getVideo().playbackRate);
let startWaitingForReportedTimeToChange = true; let startWaitingForReportedTimeToChange = true;
const reportedVideoTimeAtStart = getVideo().currentTime; const reportedVideoTimeAtStart = getCurrentTime();
logDebug(`Starting setInterval skipping ${getVideo().currentTime} to skip at ${skipTime[0]}`); logDebug(`Starting setInterval skipping ${getCurrentTime()} to skip at ${skipTime[0]}`);
if (currentSkipInterval !== null) clearInterval(currentSkipInterval); if (currentSkipInterval !== null) clearInterval(currentSkipInterval);
currentSkipInterval = setInterval(() => { currentSkipInterval = setInterval(() => {
// Estimate delay, but only take the current time right after a change // Estimate delay, but only take the current time right after a change
// Current time remains the same for many "frames" on Firefox // Current time remains the same for many "frames" on Firefox
if (isFirefoxOrSafari() && !lastKnownVideoTime.fromPause && startWaitingForReportedTimeToChange if (isFirefoxOrSafari() && !lastKnownVideoTime.fromPause && startWaitingForReportedTimeToChange
&& reportedVideoTimeAtStart !== getVideo().currentTime) { && reportedVideoTimeAtStart !== getCurrentTime()) {
startWaitingForReportedTimeToChange = false; startWaitingForReportedTimeToChange = false;
const delay = getVirtualTime() - getVideo().currentTime; const delay = getVirtualTime() - getCurrentTime();
if (delay > 0) lastKnownVideoTime.approximateDelay = delay; if (delay > 0) lastKnownVideoTime.approximateDelay = delay;
} }
const intervalDuration = performance.now() - startIntervalTime; const intervalDuration = performance.now() - startIntervalTime;
if (intervalDuration + skipBuffer * 1000 >= delayTime || getVideo().currentTime >= skipTime[0]) { if (intervalDuration + skipBuffer * 1000 >= delayTime || getCurrentTime() >= skipTime[0]) {
clearInterval(currentSkipInterval); clearInterval(currentSkipInterval);
if (!isFirefoxOrSafari() && !getVideo().muted && !inMuteSegment(getVideo().currentTime, true)) { if (!isFirefoxOrSafari() && !getVideo().muted && !inMuteSegment(getCurrentTime(), true)) {
// Workaround for more accurate skipping on Chromium // Workaround for more accurate skipping on Chromium
getVideo().muted = true; getVideo().muted = true;
getVideo().muted = false; getVideo().muted = false;
} }
skippingFunction(Math.max(getVideo().currentTime, startVideoTime + getVideo().playbackRate * Math.max(delayTime, intervalDuration) / 1000)); skippingFunction(Math.max(getCurrentTime(), startVideoTime + getVideo().playbackRate * Math.max(delayTime, intervalDuration) / 1000));
} }
}, 0); }, 0);
} else { } else {
logDebug(`Starting timeout to skip ${getVideo().currentTime} to skip at ${skipTime[0]}`); logDebug(`Starting timeout to skip ${getCurrentTime()} to skip at ${skipTime[0]}`);
const offset = (isFirefoxOrSafari() && !isSafari() ? 600 : 150); const offset = (isFirefoxOrSafari() && !isSafari() ? 600 : 150);
// Schedule for right before to be more precise than normal timeout // Schedule for right before to be more precise than normal timeout
@@ -768,10 +802,10 @@ function getVirtualTime(): number {
(performance.now() - lastKnownVideoTime.preciseTime) * getVideo().playbackRate / 1000 + lastKnownVideoTime.videoTime : null); (performance.now() - lastKnownVideoTime.preciseTime) * getVideo().playbackRate / 1000 + lastKnownVideoTime.videoTime : null);
if (Config.config.useVirtualTime && !isSafari() && virtualTime if (Config.config.useVirtualTime && !isSafari() && virtualTime
&& Math.abs(virtualTime - getVideo().currentTime) < 0.2 && getVideo().currentTime !== 0) { && Math.abs(virtualTime - getCurrentTime()) < 0.2 && getCurrentTime() !== 0) {
return Math.max(virtualTime, getVideo().currentTime); return Math.max(virtualTime, getCurrentTime());
} else { } else {
return getVideo().currentTime; return getCurrentTime();
} }
} }
@@ -787,6 +821,8 @@ function inMuteSegment(currentTime: number, includeOverlap: boolean): boolean {
* This makes sure the videoID is still correct and if the sponsorTime is included * This makes sure the videoID is still correct and if the sponsorTime is included
*/ */
function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean { function incorrectVideoCheck(videoID?: string, sponsorTime?: SponsorTime): boolean {
if (!onVideoPage()) return false;
const currentVideoID = getYouTubeVideoID(); const currentVideoID = getYouTubeVideoID();
const recordedVideoID = videoID || getVideoID(); const recordedVideoID = videoID || getVideoID();
if (currentVideoID !== recordedVideoID || (sponsorTime if (currentVideoID !== recordedVideoID || (sponsorTime
@@ -810,14 +846,16 @@ let playbackRateCheckInterval: NodeJS.Timeout | null = null;
let lastPlaybackSpeed = 1; let lastPlaybackSpeed = 1;
let setupVideoListenersFirstTime = true; let setupVideoListenersFirstTime = true;
function setupVideoListeners() { function setupVideoListeners() {
const video = getVideo();
//wait until it is loaded //wait until it is loaded
getVideo().addEventListener('loadstart', videoOnReadyListener) video.addEventListener('loadstart', videoOnReadyListener)
getVideo().addEventListener('durationchange', durationChangeListener); video.addEventListener('durationchange', durationChangeListener);
if (setupVideoListenersFirstTime) { if (setupVideoListenersFirstTime) {
addCleanupListener(() => { addCleanupListener(() => {
getVideo().removeEventListener('loadstart', videoOnReadyListener); video.removeEventListener('loadstart', videoOnReadyListener);
getVideo().removeEventListener('durationchange', durationChangeListener); video.removeEventListener('durationchange', durationChangeListener);
}); });
} }
@@ -833,18 +871,20 @@ function setupVideoListeners() {
startSponsorSchedule(); startSponsorSchedule();
}; };
getVideo().addEventListener('ratechange', rateChangeListener); video.addEventListener('ratechange', rateChangeListener);
// Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740) // Used by videospeed extension (https://github.com/igrigorik/videospeed/pull/740)
getVideo().addEventListener('videoSpeed_ratechange', rateChangeListener); video.addEventListener('videoSpeed_ratechange', rateChangeListener);
const playListener = () => { const playListener = () => {
// If it is not the first event, then the only way to get to 0 is if there is a seek event // 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 // This check makes sure that changing the video resolution doesn't cause the extension to think it
// gone back to the begining // gone back to the begining
if (getVideo().readyState <= HTMLMediaElement.HAVE_CURRENT_DATA if (video.readyState <= HTMLMediaElement.HAVE_CURRENT_DATA
&& getVideo().currentTime === 0) return; && video.currentTime === 0) return;
updateVirtualTime(); updateVirtualTime();
checkForMiniplayerPlaying();
if (switchingVideos || lastPausedAtZero) { if (switchingVideos || lastPausedAtZero) {
switchingVideos = false; switchingVideos = false;
@@ -860,15 +900,15 @@ function setupVideoListeners() {
updateAdFlag(); updateAdFlag();
// Make sure it doesn't get double called with the playing event // Make sure it doesn't get double called with the playing event
if (Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3 if (Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)) { || (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) {
lastCheckTime = Date.now(); lastCheckTime = Date.now();
lastCheckVideoTime = getVideo().currentTime; lastCheckVideoTime = video.currentTime;
startSponsorSchedule(); startSponsorSchedule();
} }
}; };
getVideo().addEventListener('play', playListener); video.addEventListener('play', playListener);
const playingListener = () => { const playingListener = () => {
updateVirtualTime(); updateVirtualTime();
@@ -876,8 +916,8 @@ function setupVideoListeners() {
if (startedWaiting) { if (startedWaiting) {
startedWaiting = false; startedWaiting = false;
logDebug(`[SB] Playing event after buffering: ${Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3 logDebug(`[SB] Playing event after buffering: ${Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)}`); || (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)}`);
} }
if (switchingVideos) { if (switchingVideos) {
@@ -889,63 +929,63 @@ function setupVideoListeners() {
} }
// Make sure it doesn't get double called with the play event // Make sure it doesn't get double called with the play event
if (Math.abs(lastCheckVideoTime - getVideo().currentTime) > 0.3 if (Math.abs(lastCheckVideoTime - video.currentTime) > 0.3
|| (lastCheckVideoTime !== getVideo().currentTime && Date.now() - lastCheckTime > 2000)) { || (lastCheckVideoTime !== video.currentTime && Date.now() - lastCheckTime > 2000)) {
lastCheckTime = Date.now(); lastCheckTime = Date.now();
lastCheckVideoTime = getVideo().currentTime; lastCheckVideoTime = video.currentTime;
startSponsorSchedule(); startSponsorSchedule();
} }
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval); if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
lastPlaybackSpeed = getVideo().playbackRate; lastPlaybackSpeed = video.playbackRate;
// Video speed controller compatibility // Video speed controller compatibility
// That extension makes rate change events not propagate // That extension makes rate change events not propagate
if (document.body.classList.contains("vsc-initialized")) { if (document.body.classList.contains("vsc-initialized")) {
playbackRateCheckInterval = setInterval(() => { playbackRateCheckInterval = setInterval(() => {
if ((!getVideoID() || getVideo().paused) && playbackRateCheckInterval) { if ((!getVideoID() || video.paused) && playbackRateCheckInterval) {
// Video is gone, stop checking // Video is gone, stop checking
clearInterval(playbackRateCheckInterval); clearInterval(playbackRateCheckInterval);
return; return;
} }
if (getVideo().playbackRate !== lastPlaybackSpeed) { if (video.playbackRate !== lastPlaybackSpeed) {
lastPlaybackSpeed = getVideo().playbackRate; lastPlaybackSpeed = video.playbackRate;
rateChangeListener(); rateChangeListener();
} }
}, 2000); }, 2000);
} }
}; };
getVideo().addEventListener('playing', playingListener); video.addEventListener('playing', playingListener);
const seekingListener = () => { const seekingListener = () => {
lastKnownVideoTime.fromPause = false; lastKnownVideoTime.fromPause = false;
if (!getVideo().paused){ if (!video.paused){
// Reset lastCheckVideoTime // Reset lastCheckVideoTime
lastCheckTime = Date.now(); lastCheckTime = Date.now();
lastCheckVideoTime = getVideo().currentTime; lastCheckVideoTime = video.currentTime;
updateVirtualTime(); updateVirtualTime();
clearWaitingTime(); clearWaitingTime();
// Sometimes looped videos loop back to almost zero, but not quite // Sometimes looped videos loop back to almost zero, but not quite
if (getVideo().loop && getVideo().currentTime < 0.2) { if (video.loop && video.currentTime < 0.2 && getCurrentTime() < 0.2) {
startSponsorSchedule(false, 0); startSponsorSchedule(false, 0);
} else { } else {
startSponsorSchedule(); startSponsorSchedule();
} }
} else { } else {
updateActiveSegment(getVideo().currentTime); updateActiveSegment(getCurrentTime());
if (getVideo().currentTime === 0) { if (getCurrentTime() === 0) {
lastPausedAtZero = true; lastPausedAtZero = true;
} }
} }
}; };
getVideo().addEventListener('seeking', seekingListener); video.addEventListener('seeking', seekingListener);
const stoppedPlayback = () => { const stoppedPlayback = () => {
// Reset lastCheckVideoTime // Reset lastCheckVideoTime
@@ -956,7 +996,7 @@ function setupVideoListeners() {
lastKnownVideoTime.videoTime = null; lastKnownVideoTime.videoTime = null;
lastKnownVideoTime.preciseTime = null; lastKnownVideoTime.preciseTime = null;
updateWaitingTime(); updateWaitingTime(video);
cancelSponsorSchedule(); cancelSponsorSchedule();
}; };
@@ -965,26 +1005,26 @@ function setupVideoListeners() {
stoppedPlayback(); stoppedPlayback();
}; };
getVideo().addEventListener('pause', pauseListener); video.addEventListener('pause', pauseListener);
const waitingListener = () => { const waitingListener = () => {
logDebug("[SB] Not skipping due to buffering"); logDebug("[SB] Not skipping due to buffering");
startedWaiting = true; startedWaiting = true;
stoppedPlayback(); stoppedPlayback();
}; };
getVideo().addEventListener('waiting', waitingListener); video.addEventListener('waiting', waitingListener);
startSponsorSchedule(); startSponsorSchedule();
if (setupVideoListenersFirstTime) { if (setupVideoListenersFirstTime) {
addCleanupListener(() => { addCleanupListener(() => {
getVideo().removeEventListener('play', playListener); video.removeEventListener('play', playListener);
getVideo().removeEventListener('playing', playingListener); video.removeEventListener('playing', playingListener);
getVideo().removeEventListener('seeking', seekingListener); video.removeEventListener('seeking', seekingListener);
getVideo().removeEventListener('ratechange', rateChangeListener); video.removeEventListener('ratechange', rateChangeListener);
getVideo().removeEventListener('videoSpeed_ratechange', rateChangeListener); video.removeEventListener('videoSpeed_ratechange', rateChangeListener);
getVideo().removeEventListener('pause', pauseListener); video.removeEventListener('pause', pauseListener);
getVideo().removeEventListener('waiting', waitingListener); video.removeEventListener('waiting', waitingListener);
if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval); if (playbackRateCheckInterval) clearInterval(playbackRateCheckInterval);
}); });
@@ -997,7 +1037,7 @@ function setupVideoListeners() {
function updateVirtualTime() { function updateVirtualTime() {
if (currentVirtualTimeInterval) clearInterval(currentVirtualTimeInterval); if (currentVirtualTimeInterval) clearInterval(currentVirtualTimeInterval);
lastKnownVideoTime.videoTime = getVideo().currentTime; lastKnownVideoTime.videoTime = getCurrentTime();
lastKnownVideoTime.preciseTime = performance.now(); lastKnownVideoTime.preciseTime = performance.now();
// If on Firefox, wait for the second time change (time remains fixed for many "frames" for privacy reasons) // If on Firefox, wait for the second time change (time remains fixed for many "frames" for privacy reasons)
@@ -1009,21 +1049,21 @@ function updateVirtualTime() {
currentVirtualTimeInterval = setInterval(() => { currentVirtualTimeInterval = setInterval(() => {
const frameTime = performance.now() - lastPerformanceTime; const frameTime = performance.now() - lastPerformanceTime;
if (lastTime !== getVideo().currentTime) { if (lastTime !== getCurrentTime()) {
rawCount++; rawCount++;
// If there is lag, give it another shot at finding a good change time // If there is lag, give it another shot at finding a good change time
if (frameTime < 20 || rawCount > 30) { if (frameTime < 20 || rawCount > 30) {
count++; count++;
} }
lastTime = getVideo().currentTime; lastTime = getCurrentTime();
} }
if (count > 1) { if (count > 1) {
const delay = lastKnownVideoTime.fromPause && lastKnownVideoTime.approximateDelay ? const delay = lastKnownVideoTime.fromPause && lastKnownVideoTime.approximateDelay ?
lastKnownVideoTime.approximateDelay : 0; lastKnownVideoTime.approximateDelay : 0;
lastKnownVideoTime.videoTime = getVideo().currentTime + delay; lastKnownVideoTime.videoTime = getCurrentTime() + delay;
lastKnownVideoTime.preciseTime = performance.now(); lastKnownVideoTime.preciseTime = performance.now();
clearInterval(currentVirtualTimeInterval); clearInterval(currentVirtualTimeInterval);
@@ -1035,8 +1075,8 @@ function updateVirtualTime() {
} }
} }
function updateWaitingTime(): void { function updateWaitingTime(video: HTMLVideoElement): void {
lastTimeFromWaitingEvent = getVideo().currentTime; lastTimeFromWaitingEvent = video.currentTime;
} }
function clearWaitingTime(): void { function clearWaitingTime(): void {
@@ -1070,24 +1110,18 @@ function setupCategoryPill() {
} }
async function sponsorsLookup(keepOldSubmissions = true) { async function sponsorsLookup(keepOldSubmissions = true) {
if (lookupWaiting) return;
//there is still no video here
if (!getVideo()) {
lookupWaiting = true;
setTimeout(() => {
lookupWaiting = false;
sponsorsLookup()
}, 100);
return;
}
const categories: string[] = Config.config.categorySelections.map((category) => category.name); const categories: string[] = Config.config.categorySelections.map((category) => category.name);
const extraRequestData: Record<string, unknown> = {}; const extraRequestData: Record<string, unknown> = {};
const hashParams = getHashParams(); const hashParams = getHashParams();
if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment; if (hashParams.requiredSegment) extraRequestData.requiredSegment = hashParams.requiredSegment;
const hashPrefix = (await getHash(getVideoID(), 1)).slice(0, 4) as VideoID & HashedValue; const videoID = getVideoID()
if (!videoID) {
console.error("[SponsorBlock] Attempted to fetch segments with a null/undefined videoID.");
return;
}
const hashPrefix = (await getHash(videoID, 1)).slice(0, 4) as VideoID & HashedValue;
const response = await asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, { const response = await asyncRequestToServer('GET', "/api/skipSegments/" + hashPrefix, {
categories, categories,
actionTypes: getEnabledActionTypes(), actionTypes: getEnabledActionTypes(),
@@ -1157,13 +1191,14 @@ async function sponsorsLookup(keepOldSubmissions = true) {
} }
} }
if (!getVideo()) {
//there is still no video here
await waitFor(() => getVideo(), 5000, 10);
}
startSkipScheduleCheckingForStartSponsors(); startSkipScheduleCheckingForStartSponsors();
//update the preview bar if (!isNaN(getVideoDuration())) {
//leave the type blank for now until categories are added
if (lastPreviewBarUpdate == getVideoID() || (lastPreviewBarUpdate == null && !isNaN(getVideo().duration))) {
//set it now
//otherwise the listener can handle it
updatePreviewBar(); updatePreviewBar();
} }
} else { } else {
@@ -1181,7 +1216,7 @@ async function sponsorsLookup(keepOldSubmissions = true) {
found: sponsorDataFound, found: sponsorDataFound,
status: lastResponseStatus, status: lastResponseStatus,
sponsorTimes: sponsorTimes, sponsorTimes: sponsorTimes,
time: getVideo().currentTime, time: getCurrentTime() ?? 0,
onMobileYouTube: isOnMobileYouTube() onMobileYouTube: isOnMobileYouTube()
}); });
@@ -1191,10 +1226,10 @@ async function sponsorsLookup(keepOldSubmissions = true) {
} }
function importExistingChapters(wait: boolean) { function importExistingChapters(wait: boolean) {
if (!existingChaptersImported) { if (!existingChaptersImported && !importingChaptersWaiting && !triedImportingChapters && onVideoPage() && !isOnMobileYouTube()) {
const waitCondition = () => getVideo()?.duration && getExistingChapters(getVideoID(), getVideo().duration); const waitCondition = () => getVideoDuration() && getExistingChapters(getVideoID(), getVideoDuration());
if (!waitCondition() && wait && !document.hasFocus() && !importingChaptersWaitingForFocus) { if (wait && !document.hasFocus() && !importingChaptersWaitingForFocus && !waitCondition()) {
importingChaptersWaitingForFocus = true; importingChaptersWaitingForFocus = true;
const listener = () => { const listener = () => {
importExistingChapters(wait); importExistingChapters(wait);
@@ -1202,14 +1237,17 @@ function importExistingChapters(wait: boolean) {
}; };
window.addEventListener("focus", listener); window.addEventListener("focus", listener);
} else { } else {
importingChaptersWaiting = true;
waitFor(waitCondition, waitFor(waitCondition,
wait ? 15000 : 0, 400, (c) => c?.length > 0).then((chapters) => { wait ? 15000 : 0, 400, (c) => c?.length > 0).then((chapters) => {
importingChaptersWaiting = false;
if (!existingChaptersImported && chapters?.length > 0) { if (!existingChaptersImported && chapters?.length > 0) {
sponsorTimes = (sponsorTimes ?? []).concat(...chapters).sort((a, b) => a.segment[0] - b.segment[0]); sponsorTimes = (sponsorTimes ?? []).concat(...chapters).sort((a, b) => a.segment[0] - b.segment[0]);
existingChaptersImported = true; existingChaptersImported = true;
updatePreviewBar(); updatePreviewBar();
} }
}).catch(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function }).catch(() => { importingChaptersWaiting = false; triedImportingChapters = true; }); // eslint-disable-line @typescript-eslint/no-empty-function
} }
} }
} }
@@ -1273,7 +1311,7 @@ function startSkipScheduleCheckingForStartSponsors() {
let startingSegmentTime = getStartTimeFromUrl(document.URL) || -1; let startingSegmentTime = getStartTimeFromUrl(document.URL) || -1;
let found = false; let found = false;
for (const time of sponsorTimes) { for (const time of sponsorTimes) {
if (time.segment[0] <= getVideo().currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > getVideo().currentTime if (time.segment[0] <= getCurrentTime() && time.segment[0] > startingSegmentTime && time.segment[1] > getCurrentTime()
&& time.actionType !== ActionType.Poi) { && time.actionType !== ActionType.Poi) {
startingSegmentTime = time.segment[0]; startingSegmentTime = time.segment[0];
found = true; found = true;
@@ -1282,7 +1320,7 @@ function startSkipScheduleCheckingForStartSponsors() {
} }
if (!found) { if (!found) {
for (const time of sponsorTimesSubmitting) { for (const time of sponsorTimesSubmitting) {
if (time.segment[0] <= getVideo().currentTime && time.segment[0] > startingSegmentTime && time.segment[1] > getVideo().currentTime if (time.segment[0] <= getCurrentTime() && time.segment[0] > startingSegmentTime && time.segment[1] > getCurrentTime()
&& time.actionType !== ActionType.Poi) { && time.actionType !== ActionType.Poi) {
startingSegmentTime = time.segment[0]; startingSegmentTime = time.segment[0];
found = true; found = true;
@@ -1293,7 +1331,7 @@ function startSkipScheduleCheckingForStartSponsors() {
// For highlight category // For highlight category
const poiSegments = sponsorTimes const poiSegments = sponsorTimes
.filter((time) => time.segment[1] > getVideo().currentTime .filter((time) => time.segment[1] > getCurrentTime()
&& time.actionType === ActionType.Poi && time.hidden === SponsorHideType.Visible) && time.actionType === ActionType.Poi && time.hidden === SponsorHideType.Visible)
.sort((a, b) => b.segment[0] - a.segment[0]); .sort((a, b) => b.segment[0] - a.segment[0]);
for (const time of poiSegments) { for (const time of poiSegments) {
@@ -1304,7 +1342,7 @@ function startSkipScheduleCheckingForStartSponsors() {
skipTime: time.segment, skipTime: time.segment,
skippingSegments: [time], skippingSegments: [time],
openNotice: true, openNotice: true,
unskipTime: getVideo().currentTime unskipTime: getCurrentTime()
}); });
if (skipOption === CategorySkipOption.AutoSkip) break; if (skipOption === CategorySkipOption.AutoSkip) break;
} }
@@ -1371,8 +1409,8 @@ function updatePreviewBar(): void {
}); });
}); });
previewBar.set(previewBarSegments.filter((segment) => segment.actionType !== ActionType.Full), getVideo()?.duration) previewBar.set(previewBarSegments.filter((segment) => segment.actionType !== ActionType.Full), getVideoDuration())
if (getVideo()) updateActiveSegment(getVideo().currentTime); if (getVideo()) updateActiveSegment(getCurrentTime());
if (Config.config.showTimeWithSkips) { if (Config.config.showTimeWithSkips) {
const skippedDuration = utils.getTimestampsDuration(previewBarSegments const skippedDuration = utils.getTimestampsDuration(previewBarSegments
@@ -1381,9 +1419,6 @@ function updatePreviewBar(): void {
showTimeWithoutSkips(skippedDuration); showTimeWithoutSkips(skippedDuration);
} }
// Update last video id
lastPreviewBarUpdate = getVideoID();
} }
//checks if this channel is whitelisted, should be done only after the channelID has been loaded //checks if this channel is whitelisted, should be done only after the channelID has been loaded
@@ -1408,6 +1443,7 @@ function videoElementChange(newVideo: boolean): void {
setupCategoryPill(); setupCategoryPill();
} }
updatePreviewBar();
checkPreviewbarState(); checkPreviewbarState();
// Incase the page is still transitioning, check again in a few seconds // Incase the page is still transitioning, check again in a few seconds
@@ -1417,8 +1453,19 @@ function videoElementChange(newVideo: boolean): void {
}) })
} }
let checkingPreviewbarAgain = false;
function checkPreviewbarState(): void { function checkPreviewbarState(): void {
if (previewBar && !utils.findReferenceNode()?.contains(previewBar.container)) { if (!getPreviewBarAttachElement() && !checkingPreviewbarAgain && getVideo() && getVideoID()) {
checkingPreviewbarAgain = true;
setTimeout(() => {
checkingPreviewbarAgain = false;
checkPreviewbarState();
}, 500);
return;
}
if (previewBar && !getPreviewBarAttachElement()?.contains(previewBar.container)) {
previewBar.remove(); previewBar.remove();
previewBar = null; previewBar = null;
} }
@@ -1590,7 +1637,7 @@ function getStartTimes(sponsorTimes: SponsorTime[], includeIntersectingSegments:
*/ */
function previewTime(time: number, unpause = true) { function previewTime(time: number, unpause = true) {
previewedSegment = true; previewedSegment = true;
getVideo().currentTime = time; setCurrentTime(time);
// Unpause the video if needed // Unpause the video if needed
if (unpause && getVideo().paused){ if (unpause && getVideo().paused){
@@ -1600,6 +1647,13 @@ function previewTime(time: number, unpause = true) {
//send telemetry and count skip //send telemetry and count skip
function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped: number, fullSkip: boolean) { function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped: number, fullSkip: boolean) {
for (const segment of skippingSegments) {
if (!previewedSegment && sponsorTimesSubmitting.some((s) => s.segment === segment.segment)) {
// Count that as a previewed segment
previewedSegment = true;
}
}
if (!Config.config.trackViewCount || (!Config.config.trackViewCountInPrivate && chrome.extension.inIncognitoContext)) return; if (!Config.config.trackViewCount || (!Config.config.trackViewCountInPrivate && chrome.extension.inIncognitoContext)) return;
let counted = false; let counted = false;
@@ -1616,9 +1670,6 @@ function sendTelemetryAndCount(skippingSegments: SponsorTime[], secondsSkipped:
} }
if (fullSkip) asyncRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID); if (fullSkip) asyncRequestToServer("POST", "/api/viewedVideoSponsorTime?UUID=" + segment.UUID);
} else if (!previewedSegment && sponsorTimesSubmitting.some((s) => s.segment === segment.segment)) {
// Count that as a previewed segment
previewedSegment = true;
} }
} }
} }
@@ -1629,24 +1680,25 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
// There will only be one submission if it is manual skip // There will only be one submission if it is manual skip
const autoSkip: boolean = forceAutoSkip || shouldAutoSkip(skippingSegments[0]); const autoSkip: boolean = forceAutoSkip || shouldAutoSkip(skippingSegments[0]);
const isSubmittingSegment = sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment);
if ((autoSkip || sponsorTimesSubmitting.some((time) => time.segment === skippingSegments[0].segment)) if ((autoSkip || isSubmittingSegment)
&& v.currentTime !== skipTime[1]) { && getCurrentTime() !== skipTime[1]) {
switch(skippingSegments[0].actionType) { switch(skippingSegments[0].actionType) {
case ActionType.Poi: case ActionType.Poi:
case ActionType.Skip: { case ActionType.Skip: {
// Fix for looped videos not working when skipping to the end #426 // Fix for looped videos not working when skipping to the end #426
// for some reason you also can't skip to 1 second before the end // for some reason you also can't skip to 1 second before the end
if (v.loop && v.duration > 1 && skipTime[1] >= v.duration - 1) { if (v.loop && getVideoDuration() > 1 && skipTime[1] >= getVideoDuration() - 1) {
v.currentTime = 0; setCurrentTime(0);
} else if (v.duration > 1 && skipTime[1] >= v.duration } else if (getVideoDuration() > 1 && skipTime[1] >= getVideoDuration()
&& (navigator.vendor === "Apple Computer, Inc." || isPlayingPlaylist())) { && (navigator.vendor === "Apple Computer, Inc." || isPlayingPlaylist())) {
// MacOS will loop otherwise #1027 // MacOS will loop otherwise #1027
// Sometimes playlists loop too #1804 // Sometimes playlists loop too #1804
v.currentTime = v.duration - 0.001; setCurrentTime(getVideoDuration() - 0.001);
} else if (v.duration > 1 && Math.abs(skipTime[1] - v.duration) < endTimeSkipBuffer } else if (getVideoDuration() > 1 && Math.abs(skipTime[1] - getVideoDuration()) < endTimeSkipBuffer
&& isFirefoxOrSafari() && !isSafari()) { && isFirefoxOrSafari() && !isSafari()) {
v.currentTime = v.duration; setCurrentTime(getVideoDuration());
} else { } else {
if (inMuteSegment(skipTime[1], true)) { if (inMuteSegment(skipTime[1], true)) {
// Make sure not to mute if skipping into a mute segment // Make sure not to mute if skipping into a mute segment
@@ -1654,7 +1706,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
videoMuted = true; videoMuted = true;
} }
v.currentTime = skipTime[1]; setCurrentTime(skipTime[1]);
} }
break; break;
@@ -1711,7 +1763,7 @@ function skipToTime({v, skipTime, skippingSegments, openNotice, forceAutoSkip, u
} }
//send telemetry that a this sponsor was skipped //send telemetry that a this sponsor was skipped
if (autoSkip) sendTelemetryAndCount(skippingSegments, skipTime[1] - skipTime[0], true); if (autoSkip || isSubmittingSegment) sendTelemetryAndCount(skippingSegments, skipTime[1] - skipTime[0], true);
} }
function createSkipNotice(skippingSegments: SponsorTime[], autoSkip: boolean, unskipTime: number, startReskip: boolean) { function createSkipNotice(skippingSegments: SponsorTime[], autoSkip: boolean, unskipTime: number, startReskip: boolean) {
@@ -1739,7 +1791,7 @@ function unskipSponsorTime(segment: SponsorTime, unskipTime: number = null, forc
if (forceSeek || segment.actionType === ActionType.Skip) { if (forceSeek || segment.actionType === ActionType.Skip) {
//add a tiny bit of time to make sure it is not skipped again //add a tiny bit of time to make sure it is not skipped again
getVideo().currentTime = unskipTime ?? segment.segment[0] + 0.001; setCurrentTime(unskipTime ?? segment.segment[0] + 0.001);
} }
} }
@@ -1749,11 +1801,11 @@ function reskipSponsorTime(segment: SponsorTime, forceSeek = false) {
getVideo().muted = true; getVideo().muted = true;
videoMuted = true; videoMuted = true;
} else { } else {
const skippedTime = Math.max(segment.segment[1] - getVideo().currentTime, 0); const skippedTime = Math.max(segment.segment[1] - getCurrentTime(), 0);
const segmentDuration = segment.segment[1] - segment.segment[0]; const segmentDuration = segment.segment[1] - segment.segment[0];
const fullSkip = skippedTime / segmentDuration > manualSkipPercentCount; const fullSkip = skippedTime / segmentDuration > manualSkipPercentCount;
getVideo().currentTime = segment.segment[1]; setCurrentTime(segment.segment[1]);
sendTelemetryAndCount([segment], segment.actionType !== ActionType.Chapter ? skippedTime : 0, fullSkip); sendTelemetryAndCount([segment], segment.actionType !== ActionType.Chapter ? skippedTime : 0, fullSkip);
startSponsorSchedule(true, segment.segment[1], false); startSponsorSchedule(true, segment.segment[1], false);
} }
@@ -1801,7 +1853,8 @@ function shouldAutoSkip(segment: SponsorTime): boolean {
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 && sponsorTimes?.some((s) => s.category === "music_offtopic")
&& segment.actionType === ActionType.Skip)); && segment.actionType === ActionType.Skip)
|| sponsorTimesSubmitting.some((s) => s.segment === segment.segment));
} }
function shouldSkip(segment: SponsorTime): boolean { function shouldSkip(segment: SponsorTime): boolean {
@@ -1902,13 +1955,14 @@ function getRealCurrentTime(): number {
if (playButtonSVGData === replaceSVGData) { if (playButtonSVGData === replaceSVGData) {
// At the end of the video // At the end of the video
return getVideo()?.duration; return getVideoDuration();
} else { } else {
return getVideo().currentTime; return getCurrentTime();
} }
} }
function startOrEndTimingNewSegment() { function startOrEndTimingNewSegment() {
verifyCurrentTime();
const roundedTime = Math.round((getRealCurrentTime() + Number.EPSILON) * 1000) / 1000; const roundedTime = Math.round((getRealCurrentTime() + Number.EPSILON) * 1000) / 1000;
if (!isSegmentCreationInProgress()) { if (!isSegmentCreationInProgress()) {
sponsorTimesSubmitting.push({ sponsorTimesSubmitting.push({
@@ -2283,7 +2337,7 @@ async function sendSubmitMessage(): Promise<boolean> {
if (!previewedSegment if (!previewedSegment
&& !sponsorTimesSubmitting.every((segment) => && !sponsorTimesSubmitting.every((segment) =>
[ActionType.Full, ActionType.Chapter, ActionType.Poi].includes(segment.actionType) [ActionType.Full, ActionType.Chapter, ActionType.Poi].includes(segment.actionType)
|| segment.segment[1] >= getVideo()?.duration || segment.segment[1] >= getVideoDuration()
|| segment.segment[0] === 0)) { || segment.segment[0] === 0)) {
alert(`${chrome.i18n.getMessage("previewSegmentRequired")} ${keybindToString(Config.config.previewKeybind)}`); alert(`${chrome.i18n.getMessage("previewSegmentRequired")} ${keybindToString(Config.config.previewKeybind)}`);
return false; return false;
@@ -2295,8 +2349,8 @@ async function sendSubmitMessage(): Promise<boolean> {
//check if a sponsor exceeds the duration of the video //check if a sponsor exceeds the duration of the video
for (let i = 0; i < sponsorTimesSubmitting.length; i++) { for (let i = 0; i < sponsorTimesSubmitting.length; i++) {
if (sponsorTimesSubmitting[i].segment[1] > getVideo().duration) { if (sponsorTimesSubmitting[i].segment[1] > getVideoDuration()) {
sponsorTimesSubmitting[i].segment[1] = getVideo().duration; sponsorTimesSubmitting[i].segment[1] = getVideoDuration();
} }
} }
@@ -2321,7 +2375,7 @@ async function sendSubmitMessage(): Promise<boolean> {
videoID: getVideoID(), videoID: getVideoID(),
userID: Config.config.userID, userID: Config.config.userID,
segments: sponsorTimesSubmitting, segments: sponsorTimesSubmitting,
videoDuration: getVideo()?.duration, videoDuration: getVideoDuration(),
userAgent: `${chrome.runtime.id}/v${chrome.runtime.getManifest().version}` userAgent: `${chrome.runtime.id}/v${chrome.runtime.getManifest().version}`
}); });
@@ -2414,38 +2468,38 @@ function nextChapter(): void {
const chapters = previewBar.unfilteredChapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType)); const chapters = previewBar.unfilteredChapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType));
if (!chapters || chapters.length <= 0) return; if (!chapters || chapters.length <= 0) return;
lastNextChapterKeybind.time = getVideo().currentTime; lastNextChapterKeybind.time = getCurrentTime();
lastNextChapterKeybind.date = Date.now(); lastNextChapterKeybind.date = Date.now();
const nextChapter = chapters.findIndex((time) => time.segment[0] > getVideo().currentTime); const nextChapter = chapters.findIndex((time) => time.segment[0] > getCurrentTime());
if (nextChapter !== -1) { if (nextChapter !== -1) {
getVideo().currentTime = chapters[nextChapter].segment[0]; setCurrentTime(chapters[nextChapter].segment[0]);
} else { } else {
getVideo().currentTime = getVideo().duration; setCurrentTime(getVideoDuration());
} }
} }
function previousChapter(): void { function previousChapter(): void {
if (Date.now() - lastNextChapterKeybind.date < 3000) { if (Date.now() - lastNextChapterKeybind.date < 3000) {
getVideo().currentTime = lastNextChapterKeybind.time; setCurrentTime(lastNextChapterKeybind.time);
lastNextChapterKeybind.date = 0; lastNextChapterKeybind.date = 0;
return; return;
} }
const chapters = previewBar.unfilteredChapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType)); const chapters = previewBar.unfilteredChapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType));
if (!chapters || chapters.length <= 0) { if (!chapters || chapters.length <= 0) {
getVideo().currentTime = 0; setCurrentTime(0);
return; return;
} }
// subtract 5 seconds to allow skipping back to the previous chapter if close to start of // subtract 5 seconds to allow skipping back to the previous chapter if close to start of
// the current one // the current one
const nextChapter = chapters.findIndex((time) => time.segment[0] > getVideo().currentTime - Math.min(5, time.segment[1] - time.segment[0])); const nextChapter = chapters.findIndex((time) => time.segment[0] > getCurrentTime() - Math.min(5, time.segment[1] - time.segment[0]));
const previousChapter = nextChapter !== -1 ? (nextChapter - 1) : (chapters.length - 1); const previousChapter = nextChapter !== -1 ? (nextChapter - 1) : (chapters.length - 1);
if (previousChapter !== -1) { if (previousChapter !== -1) {
getVideo().currentTime = chapters[previousChapter].segment[0]; setCurrentTime(chapters[previousChapter].segment[0]);
} else { } else {
getVideo().currentTime = 0; setCurrentTime(0);
} }
} }
@@ -2606,7 +2660,7 @@ function showTimeWithoutSkips(skippedDuration: number): void {
display.appendChild(duration); display.appendChild(duration);
} }
const durationAfterSkips = getFormattedTime(getVideo()?.duration - skippedDuration); const durationAfterSkips = getFormattedTime(getVideoDuration() - skippedDuration);
duration.innerText = (durationAfterSkips == null || skippedDuration <= 0) ? "" : " (" + durationAfterSkips + ")"; duration.innerText = (durationAfterSkips == null || skippedDuration <= 0) ? "" : " (" + durationAfterSkips + ")";
} }
@@ -2668,3 +2722,22 @@ function setCategoryColorCSSVariables() {
styleContainer.innerText = css; styleContainer.innerText = css;
} }
/**
* If mini player starts playing, then videoID change might have to be called
*/
function checkForMiniplayerPlaying() {
const miniPlayerUI = document.querySelector(".miniplayer") as HTMLElement;
if (!onVideoPage() && isVisible(miniPlayerUI)) {
const videoID = getLastNonInlineVideoID();
if (videoID) {
triggerVideoIDChange(videoID);
// treat as if video element has changed
const video = miniPlayerUI.querySelector("video") as HTMLVideoElement;
if (video && getVideo() !== video) {
triggerVideoElementChange(video);
}
}
}
}

15
src/globals.d.ts vendored
View File

@@ -1,19 +1,4 @@
import { SBObject } from "./config"; import { SBObject } from "./config";
declare global { declare global {
interface Window { SB: SBObject } interface Window { SB: SBObject }
// Remove this once the API becomes stable and types are shipped in @types/chrome
namespace chrome {
namespace declarativeContent {
export interface RequestContentScriptOptions {
allFrames?: boolean;
css?: string[];
instanceType?: "declarativeContent.RequestContentScript";
js?: string[];
matchAboutBlanck?: boolean;
}
export class RequestContentScript {
constructor(options: RequestContentScriptOptions);
}
}
}
} }

View File

@@ -13,6 +13,7 @@ import { DEFAULT_CATEGORY, shortCategoryName } from "../utils/categoryUtils";
import { normalizeChapterName } from "../utils/exporter"; import { normalizeChapterName } from "../utils/exporter";
import { findValidElement } from "../../maze-utils/src/dom"; import { findValidElement } from "../../maze-utils/src/dom";
import { addCleanupListener } from "../../maze-utils/src/cleanup"; import { addCleanupListener } from "../../maze-utils/src/cleanup";
import { isVisible } from "../utils/pageUtils";
const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible'; const TOOLTIP_VISIBLE_CLASS = 'sponsorCategoryTooltipVisible';
const MIN_CHAPTER_SIZE = 0.003; const MIN_CHAPTER_SIZE = 0.003;
@@ -225,10 +226,12 @@ class PreviewBar {
this.segments = segments ?? []; this.segments = segments ?? [];
this.videoDuration = videoDuration ?? 0; this.videoDuration = videoDuration ?? 0;
this.updatePageElements(); this.updatePageElements();
// Sometimes video duration is inaccurate, pull from accessibility info // Sometimes video duration is inaccurate, pull from accessibility info
const ariaDuration = parseInt(this.progressBar?.getAttribute('aria-valuemax')) ?? 0; const ariaDuration = parseInt(this.progressBar?.getAttribute('aria-valuemax')) ?? 0;
if (ariaDuration && Math.abs(ariaDuration - this.videoDuration) > 3) { const multipleActiveVideos = [...document.querySelectorAll("video")].filter((v) => isVisible(v)).length > 1;
if (!multipleActiveVideos && ariaDuration && Math.abs(ariaDuration - this.videoDuration) > 3) {
this.videoDuration = ariaDuration; this.videoDuration = ariaDuration;
} }
@@ -236,7 +239,7 @@ class PreviewBar {
} }
private updatePageElements(): void { private updatePageElements(): void {
const allProgressBars = document.querySelectorAll('.ytp-progress-bar') as NodeListOf<HTMLElement>; const allProgressBars = document.querySelectorAll(".ytp-progress-bar") as NodeListOf<HTMLElement>;
this.progressBar = findValidElement(allProgressBars) ?? allProgressBars?.[0]; this.progressBar = findValidElement(allProgressBars) ?? allProgressBars?.[0];
if (this.progressBar) { if (this.progressBar) {

View File

@@ -303,7 +303,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
PageElements.showNoticeAgain.style.display = "unset"; PageElements.showNoticeAgain.style.display = "unset";
} }
const values = ["userName", "viewCount", "minutesSaved", "vip", "permissions"]; const values = ["userName", "viewCount", "minutesSaved", "vip", "permissions", "segmentCount"];
asyncRequestToServer("GET", "/api/userInfo", { asyncRequestToServer("GET", "/api/userInfo", {
publicUserID: await getHash(Config.config.userID), publicUserID: await getHash(Config.config.userID),
@@ -336,16 +336,18 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
PageElements.sponsorTimesOthersTimeSavedDisplay.innerText = getFormattedHours(minutesSaved); PageElements.sponsorTimesOthersTimeSavedDisplay.innerText = getFormattedHours(minutesSaved);
} }
//get the amount of times this user has contributed and display it to thank them
PageElements.sponsorTimesContributionsDisplay.innerText = Math.max(Config.config.sponsorTimesContributed ?? 0, userInfo.segmentCount).toLocaleString();
PageElements.sponsorTimesContributionsContainer.classList.remove("hidden");
PageElements.sponsorTimesOthersTimeSavedEndWord.innerText = chrome.i18n.getMessage("minsLower");
Config.config.isVip = userInfo.vip; Config.config.isVip = userInfo.vip;
Config.config.permissions = userInfo.permissions; Config.config.permissions = userInfo.permissions;
} }
}); });
//get the amount of times this user has contributed and display it to thank them
if (Config.config.sponsorTimesContributed != undefined) {
PageElements.sponsorTimesContributionsDisplay.innerText = Config.config.sponsorTimesContributed.toLocaleString();
PageElements.sponsorTimesContributionsContainer.classList.remove("hidden");
}
//get the amount of times this user has skipped a sponsor //get the amount of times this user has skipped a sponsor
if (Config.config.skipCount != undefined) { if (Config.config.skipCount != undefined) {
@@ -561,7 +563,7 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> {
return true; return true;
} }
}) })
.sort((a, b) => a.segment[1] - b.segment[1]) .sort((a, b) => b.segment[1] - a.segment[1])
.sort((a, b) => a.segment[0] - b.segment[0]); .sort((a, b) => a.segment[0] - b.segment[0]);
//add them as buttons to the issue reporting container //add them as buttons to the issue reporting container

View File

@@ -8,6 +8,7 @@ const utils = new Utils();
import { ContentContainer } from "../types"; import { ContentContainer } from "../types";
import NoticeTextSelectionComponent from "../components/NoticeTextSectionComponent"; import NoticeTextSelectionComponent from "../components/NoticeTextSectionComponent";
import { ButtonListener } from "../../maze-utils/src/components/component-types"; import { ButtonListener } from "../../maze-utils/src/components/component-types";
import { getVideo } from "../../maze-utils/src/video";
export interface TextBox { export interface TextBox {
icon: string; icon: string;
@@ -75,7 +76,7 @@ export default class GenericNotice {
{options.textBoxes?.length > 0 ? {options.textBoxes?.length > 0 ?
<tr id={"sponsorSkipNoticeMiddleRow" + this.idSuffix} <tr id={"sponsorSkipNoticeMiddleRow" + this.idSuffix}
className="sponsorTimeMessagesRow" className="sponsorTimeMessagesRow"
style={{maxHeight: this.contentContainer ? (this.contentContainer().v.offsetHeight - 200) + "px" : null}}> style={{maxHeight: getVideo() ? (getVideo().offsetHeight - 200) + "px" : null}}>
<td style={{width: "100%"}}> <td style={{width: "100%"}}>
{this.getMessageBoxes(this.idSuffix, options.textBoxes)} {this.getMessageBoxes(this.idSuffix, options.textBoxes)}
</td> </td>

View File

@@ -10,7 +10,6 @@ export interface ContentContainer {
sponsorTimes: SponsorTime[]; sponsorTimes: SponsorTime[];
sponsorTimesSubmitting: SponsorTime[]; sponsorTimesSubmitting: SponsorTime[];
skipNotices: SkipNotice[]; skipNotices: SkipNotice[];
v: HTMLVideoElement;
sponsorVideoID; sponsorVideoID;
reskipSponsorTime: (segment: SponsorTime, forceSeek?: boolean) => void; reskipSponsorTime: (segment: SponsorTime, forceSeek?: boolean) => void;
updatePreviewBar: () => void; updatePreviewBar: () => void;

View File

@@ -2,7 +2,7 @@ import Config, { VideoDownvotes } from "./config";
import { CategorySelection, SponsorTime, BackgroundScriptContainer, Registration, VideoID, SponsorHideType, CategorySkipOption } from "./types"; import { CategorySelection, SponsorTime, BackgroundScriptContainer, Registration, VideoID, SponsorHideType, CategorySkipOption } from "./types";
import { getHash, HashedValue } from "../maze-utils/src/hash"; import { getHash, HashedValue } from "../maze-utils/src/hash";
import { isFirefoxOrSafari, waitFor } from "../maze-utils/src"; import { waitFor } from "../maze-utils/src";
import { findValidElementFromSelector } from "../maze-utils/src/dom"; import { findValidElementFromSelector } from "../maze-utils/src/dom";
import { isSafari } from "../maze-utils/src/config"; import { isSafari } from "../maze-utils/src/config";
@@ -46,10 +46,7 @@ export default class Utils {
*/ */
setupExtraSitePermissions(callback: (granted: boolean) => void): void { setupExtraSitePermissions(callback: (granted: boolean) => void): void {
const permissions = []; const permissions = [];
if (!isFirefoxOrSafari()) { if (isSafari()) {
permissions.push("declarativeContent");
}
if (!isFirefoxOrSafari() || isSafari()) {
permissions.push("webNavigation"); permissions.push("webNavigation");
} }
@@ -67,6 +64,17 @@ export default class Utils {
}); });
} }
getExtraSiteRegistration(): Registration {
return {
message: "registerContentScript",
id: "invidious",
allFrames: true,
js: this.js,
css: this.css,
matches: this.getPermissionRegex()
};
}
/** /**
* Registers the content scripts for the extra sites. * Registers the content scripts for the extra sites.
* Will use a different method depending on the browser. * Will use a different method depending on the browser.
@@ -75,14 +83,7 @@ export default class Utils {
* For now, it is just SB.config.invidiousInstances. * For now, it is just SB.config.invidiousInstances.
*/ */
setupExtraSiteContentScripts(): void { setupExtraSiteContentScripts(): void {
const registration: Registration = { const registration = this.getExtraSiteRegistration();
message: "registerContentScript",
id: "invidious",
allFrames: true,
js: this.js,
css: this.css,
matches: this.getPermissionRegex()
};
if (this.backgroundScriptContainer) { if (this.backgroundScriptContainer) {
this.backgroundScriptContainer.registerFirefoxContentScript(registration); this.backgroundScriptContainer.registerFirefoxContentScript(registration);
@@ -106,11 +107,6 @@ export default class Utils {
}); });
} }
if (!isFirefoxOrSafari() && chrome.declarativeContent) {
// Only if we have permission
chrome.declarativeContent.onPageChanged.removeRules(["invidious"]);
}
chrome.permissions.remove({ chrome.permissions.remove({
origins: this.getPermissionRegex() origins: this.getPermissionRegex()
}); });
@@ -135,8 +131,10 @@ export default class Utils {
containsInvidiousPermission(): Promise<boolean> { containsInvidiousPermission(): Promise<boolean> {
return new Promise((resolve) => { return new Promise((resolve) => {
let permissions = ["declarativeContent"]; const permissions = [];
if (isFirefoxOrSafari()) permissions = []; if (isSafari()) {
permissions.push("webNavigation");
}
chrome.permissions.contains({ chrome.permissions.contains({
origins: this.getPermissionRegex(), origins: this.getPermissionRegex(),

View File

@@ -53,14 +53,14 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[]
titleRight = removeIf(split2[split2.length - 1], specialCharMatchers) titleRight = removeIf(split2[split2.length - 1], specialCharMatchers)
const title = titleLeft?.length > titleRight?.length ? titleLeft : titleRight; const title = titleLeft?.length > titleRight?.length ? titleLeft : titleRight;
if (title) {
const determinedCategory = chapterNames.find(c => c.names.includes(title))?.code as Category; const determinedCategory = chapterNames.find(c => c.names.includes(title))?.code as Category;
const category = title ? (determinedCategory ?? ("chapter" as Category)) : "chooseACategory" as Category;
const segment: SponsorTime = { const segment: SponsorTime = {
segment: [startTime, getFormattedTimeToSeconds(match[1])], segment: [startTime, getFormattedTimeToSeconds(match[1])],
category: determinedCategory ?? ("chapter" as Category), category,
actionType: determinedCategory ? ActionType.Skip : ActionType.Chapter, actionType: category === "chapter" ? ActionType.Chapter : ActionType.Skip,
description: title, description: category === "chapter" ? title : null,
source: SponsorSourceType.Local, source: SponsorSourceType.Local,
UUID: generateUserID() as SegmentUUID UUID: generateUserID() as SegmentUUID
}; };
@@ -73,7 +73,6 @@ export function importTimes(data: string, videoDuration: number): SponsorTime[]
} }
} }
} }
}
if (result.length > 0 && result[result.length - 1].segment[1] === null) { if (result.length > 0 && result[result.length - 1].segment[1] === null) {
result[result.length - 1].segment[1] = videoDuration; result[result.length - 1].segment[1] = videoDuration;

View File

@@ -1,12 +1,22 @@
window["SBLogs"] = { if (typeof (window) !== "undefined") {
window["SBLogs"] = {
debug: [], debug: [],
warn: [] warn: []
}; };
}
export function logDebug(message: string) { export function logDebug(message: string) {
if (typeof (window) !== "undefined") {
window["SBLogs"].debug.push(`[${new Date().toISOString()}] ${message}`); window["SBLogs"].debug.push(`[${new Date().toISOString()}] ${message}`);
} else {
console.log(`[${new Date().toISOString()}] ${message}`)
}
} }
export function logWarn(message: string) { export function logWarn(message: string) {
if (typeof (window) !== "undefined") {
window["SBLogs"].warn.push(`[${new Date().toISOString()}] ${message}`); window["SBLogs"].warn.push(`[${new Date().toISOString()}] ${message}`);
} else {
console.warn(`[${new Date().toISOString()}] ${message}`)
}
} }

View File

@@ -11,6 +11,7 @@ const chromeManifestExtra = require("../manifest/chrome-manifest-extra.json");
const safariManifestExtra = require("../manifest/safari-manifest-extra.json"); const safariManifestExtra = require("../manifest/safari-manifest-extra.json");
const betaManifestExtra = require("../manifest/beta-manifest-extra.json"); const betaManifestExtra = require("../manifest/beta-manifest-extra.json");
const firefoxBetaManifestExtra = require("../manifest/firefox-beta-manifest-extra.json"); const firefoxBetaManifestExtra = require("../manifest/firefox-beta-manifest-extra.json");
const manifestV2ManifestExtra = require("../manifest/manifest-v2-extra.json");
// schema for options object // schema for options object
const schema = { const schema = {
@@ -41,12 +42,14 @@ class BuildManifest {
// Add missing manifest elements // Add missing manifest elements
if (this.options.browser.toLowerCase() === "firefox") { if (this.options.browser.toLowerCase() === "firefox") {
mergeObjects(manifest, manifestV2ManifestExtra);
mergeObjects(manifest, firefoxManifestExtra); mergeObjects(manifest, firefoxManifestExtra);
} else if (this.options.browser.toLowerCase() === "chrome" } else if (this.options.browser.toLowerCase() === "chrome"
|| this.options.browser.toLowerCase() === "chromium" || this.options.browser.toLowerCase() === "chromium"
|| this.options.browser.toLowerCase() === "edge") { || this.options.browser.toLowerCase() === "edge") {
mergeObjects(manifest, chromeManifestExtra); mergeObjects(manifest, chromeManifestExtra);
} else if (this.options.browser.toLowerCase() === "safari") { } else if (this.options.browser.toLowerCase() === "safari") {
mergeObjects(manifest, manifestV2ManifestExtra);
mergeObjects(manifest, safariManifestExtra); mergeObjects(manifest, safariManifestExtra);
} }