mirror of
https://github.com/alexta69/metube.git
synced 2026-09-21 21:45:04 +00:00
feat: first-class SponsorBlock toggle
A "Remove sponsor segments" switch next to "Split by chapters" queues the download with the same postprocessor pair the CLI's --sponsorblock-remove sponsor builds (SponsorBlock + ModifyChapters). The flag persists as a cookie like the other form options, survives in the queue records, and is carried into retries. The pair is registered above the chapter-splitting block: yt-dlp runs same-stage postprocessors in list order, so ModifyChapters has to rewrite the chapter list before FFmpegSplitChapters cuts the file up, matching what the CLI builds for --sponsorblock-remove sponsor --split-chapters. With both toggles on the other way around the chapter files keep the sponsor segments and the removal desyncs the remaining chapter timings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -399,6 +399,16 @@
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="checkbox-sponsorblock"
|
||||
name="sponsorblock" [(ngModel)]="sponsorblock" (change)="sponsorblockChanged()"
|
||||
[disabled]="addInProgress || subscribeInProgress || downloads.loading">
|
||||
<label class="form-check-label" for="checkbox-sponsorblock"
|
||||
ngbPopover="Cut out sponsor segments using SponsorBlock's crowd-sourced markers (YouTube only)."
|
||||
triggers="hover" container="body">Remove sponsor segments</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="checkbox-split-chapters"
|
||||
|
||||
@@ -86,6 +86,7 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
||||
autoStart: boolean;
|
||||
playlistItemLimit!: number;
|
||||
splitByChapters: boolean;
|
||||
sponsorblock: boolean;
|
||||
chapterTemplate: string;
|
||||
clipStart = '';
|
||||
clipEnd = '';
|
||||
@@ -259,6 +260,7 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
||||
this.quality = this.cookieService.get('metube_quality') || 'best';
|
||||
this.autoStart = this.cookieService.get('metube_auto_start') !== 'false';
|
||||
this.splitByChapters = this.cookieService.get('metube_split_chapters') === 'true';
|
||||
this.sponsorblock = this.cookieService.get('metube_sponsorblock') === 'true';
|
||||
// Will be set from backend configuration, use empty string as placeholder
|
||||
this.chapterTemplate = this.cookieService.get('metube_chapter_template') || '';
|
||||
this.clipStart = this.cookieService.get('metube_clip_start') || '';
|
||||
@@ -855,6 +857,10 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
||||
this.cookieService.set('metube_auto_start', this.autoStart ? 'true' : 'false', { expires: this.settingsCookieExpiryDays });
|
||||
}
|
||||
|
||||
sponsorblockChanged() {
|
||||
this.cookieService.set('metube_sponsorblock', this.sponsorblock ? 'true' : 'false', { expires: this.settingsCookieExpiryDays });
|
||||
}
|
||||
|
||||
splitByChaptersChanged() {
|
||||
this.cookieService.set('metube_split_chapters', this.splitByChapters ? 'true' : 'false', { expires: this.settingsCookieExpiryDays });
|
||||
}
|
||||
@@ -1111,6 +1117,7 @@ export class App implements AfterViewInit, OnInit, OnDestroy {
|
||||
playlistItemLimit: overrides.playlistItemLimit ?? this.playlistItemLimit,
|
||||
autoStart: overrides.autoStart ?? this.autoStart,
|
||||
splitByChapters: overrides.splitByChapters ?? this.splitByChapters,
|
||||
sponsorblock: overrides.sponsorblock ?? this.sponsorblock,
|
||||
chapterTemplate: overrides.chapterTemplate ?? this.chapterTemplate,
|
||||
subtitleLanguage: overrides.subtitleLanguage ?? this.subtitleLanguage,
|
||||
subtitleMode: overrides.subtitleMode ?? this.subtitleMode,
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface Download {
|
||||
custom_name_prefix: string;
|
||||
playlist_item_limit: number;
|
||||
split_by_chapters?: boolean;
|
||||
sponsorblock?: boolean;
|
||||
chapter_template?: string;
|
||||
subtitle_language?: string;
|
||||
subtitle_mode?: string;
|
||||
|
||||
@@ -36,6 +36,7 @@ function basePayload(): AddDownloadPayload {
|
||||
playlistItemLimit: 0,
|
||||
autoStart: true,
|
||||
splitByChapters: false,
|
||||
sponsorblock: false,
|
||||
chapterTemplate: '',
|
||||
subtitleLanguage: 'en',
|
||||
subtitleMode: 'prefer_manual',
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface AddDownloadPayload {
|
||||
playlistItemLimit: number;
|
||||
autoStart: boolean;
|
||||
splitByChapters: boolean;
|
||||
sponsorblock: boolean;
|
||||
chapterTemplate: string;
|
||||
subtitleLanguage: string;
|
||||
subtitleMode: string;
|
||||
@@ -148,6 +149,7 @@ export class DownloadsService {
|
||||
playlist_item_limit: payload.playlistItemLimit,
|
||||
auto_start: payload.autoStart,
|
||||
split_by_chapters: payload.splitByChapters,
|
||||
sponsorblock: payload.sponsorblock,
|
||||
chapter_template: payload.chapterTemplate,
|
||||
subtitle_language: payload.subtitleLanguage,
|
||||
subtitle_mode: payload.subtitleMode,
|
||||
|
||||
Reference in New Issue
Block a user