From 51fc6fde223448029b228394e58b377a707aabb8 Mon Sep 17 00:00:00 2001 From: Ajay Date: Fri, 16 Sep 2022 00:57:43 -0400 Subject: [PATCH] Improve next chapter and previous chapter keybind --- src/content.ts | 35 +++++++++++++++------- src/js-components/previewBar.ts | 53 +++++++++++++++++---------------- 2 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/content.ts b/src/content.ts index 57b7008d..a84811e8 100644 --- a/src/content.ts +++ b/src/content.ts @@ -71,6 +71,10 @@ let lastKnownVideoTime: { videoTime: number, preciseTime: number } = { }; // It resumes with a slightly later time on chromium let lastTimeFromWaitingEvent = null; +const lastNextChapterKeybind = { + time: 0, + date: 0 +}; // Skips are scheduled to ensure precision. // Skips are rescheduled every seeking event. @@ -2233,30 +2237,39 @@ function updateActiveSegment(currentTime: number): void { } function nextChapter(): void { - const chapters = sponsorTimes.filter((time) => time.actionType === ActionType.Chapter) - .sort((a, b) => a.segment[1] - b.segment[1]); - if (chapters.length <= 0) return; + const chapters = previewBar.chapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType)); + if (!chapters || chapters.length <= 0) return; - const nextChapter = chapters.findIndex((time) => time.actionType === ActionType.Chapter - && time.segment[1] > video.currentTime); + lastNextChapterKeybind.time = video.currentTime; + lastNextChapterKeybind.date = Date.now(); + + const nextChapter = chapters.findIndex((time) => time.segment[0] > video.currentTime); if (nextChapter !== -1) { - reskipSponsorTime(chapters[nextChapter], true); + video.currentTime = chapters[nextChapter].segment[0]; } else { video.currentTime = video.duration; } } function previousChapter(): void { - const chapters = sponsorTimes.filter((time) => time.actionType === ActionType.Chapter); - if (chapters.length <= 0) return; + if (Date.now() - lastNextChapterKeybind.date < 3000) { + video.currentTime = lastNextChapterKeybind.time; + lastNextChapterKeybind.date = 0; + return; + } + + const chapters = previewBar.chapterGroups?.filter((time) => [ActionType.Chapter, null].includes(time.actionType)); + if (!chapters || chapters.length <= 0) { + video.currentTime = 0; + return; + } // subtract 5 seconds to allow skipping back to the previous chapter if close to start of // the current one - const nextChapter = chapters.findIndex((time) => time.actionType === ActionType.Chapter - && time.segment[0] > video.currentTime - Math.min(5, time.segment[1] - time.segment[0])); + const nextChapter = chapters.findIndex((time) => time.segment[0] > video.currentTime - Math.min(5, time.segment[1] - time.segment[0])); const previousChapter = nextChapter !== -1 ? (nextChapter - 1) : (chapters.length - 1); if (previousChapter !== -1) { - unskipSponsorTime(chapters[previousChapter], null, true); + video.currentTime = chapters[previousChapter].segment[0]; } else { video.currentTime = 0; } diff --git a/src/js-components/previewBar.ts b/src/js-components/previewBar.ts index 3f897dd4..651482fd 100644 --- a/src/js-components/previewBar.ts +++ b/src/js-components/previewBar.ts @@ -28,7 +28,8 @@ export interface PreviewBarSegment { } interface ChapterGroup extends SegmentContainer { - originalDuration: number + originalDuration: number; + actionType: ActionType; } class PreviewBar { @@ -54,6 +55,7 @@ class PreviewBar { originalChapterBar: HTMLElement; originalChapterBarBlocks: NodeListOf; chapterMargin: number; + chapterGroups: ChapterGroup[]; constructor(parent: HTMLElement, onMobileYouTube: boolean, onInvidious: boolean, chapterVote: ChapterVote, test=false) { if (test) return; @@ -308,26 +310,21 @@ class PreviewBar { return; } - if (segments.every((segments) => segments.source === SponsorSourceType.YouTube) - || (!Config.config.renderSegmentsAsChapters - && segments.every((segment) => segment.actionType !== ActionType.Chapter - || segment.source === SponsorSourceType.YouTube))) { - if (this.customChaptersBar) this.customChaptersBar.style.display = "none"; - this.originalChapterBar.style.removeProperty("display"); - return; - } - // Merge overlapping chapters const filteredSegments = segments?.filter((segment) => this.chapterFilter(segment)); - const chaptersToRender = this.createChapterRenderGroups(filteredSegments).filter((segment) => this.chapterGroupFilter(segment)); + this.chapterGroups = this.createChapterRenderGroups(filteredSegments).filter((segment) => this.chapterGroupFilter(segment)); // Fix missing sections due to filtered segments - for (let i = 1; i < chaptersToRender.length; i++) { - if (chaptersToRender[i].segment[0] !== chaptersToRender[i - 1].segment[1]) { - chaptersToRender[i - 1].segment[1] = chaptersToRender[i].segment[0] + for (let i = 1; i < this.chapterGroups.length; i++) { + if (this.chapterGroups[i].segment[0] !== this.chapterGroups[i - 1].segment[1]) { + this.chapterGroups[i - 1].segment[1] = this.chapterGroups[i].segment[0] } } - if (chaptersToRender?.length <= 0) { + if (segments.every((segments) => segments.source === SponsorSourceType.YouTube) + || (!Config.config.renderSegmentsAsChapters + && segments.every((segment) => segment.actionType !== ActionType.Chapter + || segment.source === SponsorSourceType.YouTube)) + || this.chapterGroups?.length <= 0) { if (this.customChaptersBar) this.customChaptersBar.style.display = "none"; this.originalChapterBar.style.removeProperty("display"); return; @@ -349,15 +346,15 @@ class PreviewBar { const originalSection = originalSections[0]; // For switching to a video with less chapters - if (originalSections.length > chaptersToRender.length) { - for (let i = originalSections.length - 1; i >= chaptersToRender.length; i--) { + if (originalSections.length > this.chapterGroups.length) { + for (let i = originalSections.length - 1; i >= this.chapterGroups.length; i--) { this.customChaptersBar.removeChild(originalSections[i]); } } // Modify it to have sections for each segment - for (let i = 0; i < chaptersToRender.length; i++) { - const chapter = chaptersToRender[i].segment; + for (let i = 0; i < this.chapterGroups.length; i++) { + const chapter = this.chapterGroups[i].segment; let newSection = originalSections[i] as HTMLElement; if (!newSection) { newSection = originalSection.cloneNode(true) as HTMLElement; @@ -368,7 +365,7 @@ class PreviewBar { this.firstTimeSetupChapterSection(newSection); } - this.setupChapterSection(newSection, chapter[0], chapter[1], i !== chaptersToRender.length - 1); + this.setupChapterSection(newSection, chapter[0], chapter[1], i !== this.chapterGroups.length - 1); } // Hide old bar @@ -414,11 +411,13 @@ class PreviewBar { result.push({ segment: [segment.segment[0], segment.segment[1]], originalDuration: segmentDuration, + actionType: segment.actionType }); if (latestValidChapter?.segment[1] > segment.segment[1]) { result.push({ segment: [segment.segment[1], latestValidChapter.segment[1]], - originalDuration: latestValidChapter.originalDuration + originalDuration: latestValidChapter.originalDuration, + actionType: latestValidChapter.actionType }); } @@ -437,7 +436,8 @@ class PreviewBar { // Start at end of old one otherwise result.push({ segment: [latestChapter.segment[1], segment.segment[1]], - originalDuration: segmentDuration + originalDuration: segmentDuration, + actionType: segment.actionType }); } } else { @@ -446,7 +446,8 @@ class PreviewBar { if (segment.segment[0] > lastTime) { result.push({ segment: [lastTime, segment.segment[0]], - originalDuration: 0 + originalDuration: 0, + actionType: null }); } @@ -454,7 +455,8 @@ class PreviewBar { const endTime = Math.min(segment.segment[1], this.videoDuration); result.push({ segment: [segment.segment[0], endTime], - originalDuration: endTime - segment.segment[0] + originalDuration: endTime - segment.segment[0], + actionType: segment.actionType }); } @@ -466,7 +468,8 @@ class PreviewBar { if (this.intervalToDecimal(lastTime, nextTime) > MIN_CHAPTER_SIZE) { result.push({ segment: [lastTime, nextTime], - originalDuration: 0 + originalDuration: 0, + actionType: null }); } }