diff --git a/app/main.py b/app/main.py
index 0678544..5fe4bab 100644
--- a/app/main.py
+++ b/app/main.py
@@ -254,6 +254,7 @@ async def add(request):
subtitle_language = post.get('subtitle_language')
subtitle_mode = post.get('subtitle_mode')
custom_filename = post.get('custom_filename', '')
+ track_numbering = post.get('track_numbering', False)
if custom_name_prefix is None:
custom_name_prefix = ''
@@ -301,6 +302,7 @@ async def add(request):
subtitle_language,
subtitle_mode,
custom_filename=custom_filename,
+ track_numbering=track_numbering,
)
return web.Response(text=serializer.encode(status))
diff --git a/app/ytdl.py b/app/ytdl.py
index 6bc7cd2..8567827 100644
--- a/app/ytdl.py
+++ b/app/ytdl.py
@@ -143,6 +143,7 @@ class DownloadInfo:
subtitle_language="en",
subtitle_mode="prefer_manual",
custom_filename='',
+ track_numbering=False,
):
self.id = id if len(custom_name_prefix) == 0 else f'{custom_name_prefix}.{id}'
self.title = title if len(custom_name_prefix) == 0 else f'{custom_name_prefix}.{title}'
@@ -166,6 +167,7 @@ class DownloadInfo:
self.subtitle_mode = subtitle_mode
self.subtitle_files = []
self.custom_filename = custom_filename
+ self.track_numbering = track_numbering
class Download:
manager = None
@@ -620,6 +622,8 @@ class DownloadQueue:
for property, value in entry.items():
if property.startswith("playlist"):
output = _outtmpl_substitute_field(output, property, value)
+ if getattr(dl, 'track_numbering', False):
+ output = f'%(playlist_index)s - {output}'
if entry is not None and entry.get('channel_index') is not None:
if len(self.config.OUTPUT_TEMPLATE_CHANNEL):
output = self.config.OUTPUT_TEMPLATE_CHANNEL
@@ -658,6 +662,7 @@ class DownloadQueue:
subtitle_mode,
already,
custom_filename='',
+ track_numbering=False,
_add_gen=None,
):
if not entry:
@@ -690,6 +695,7 @@ class DownloadQueue:
subtitle_mode,
already,
custom_filename,
+ track_numbering,
_add_gen,
)
elif etype == 'playlist' or etype == 'channel':
@@ -730,6 +736,7 @@ class DownloadQueue:
subtitle_mode,
already,
custom_filename='',
+ track_numbering=track_numbering,
_add_gen=_add_gen,
)
)
@@ -760,6 +767,7 @@ class DownloadQueue:
subtitle_language,
subtitle_mode,
custom_filename=custom_filename,
+ track_numbering=track_numbering,
)
await self.__add_download(dl, auto_start)
return {'status': 'ok'}
@@ -781,12 +789,13 @@ class DownloadQueue:
subtitle_mode="prefer_manual",
already=None,
custom_filename='',
+ track_numbering=False,
_add_gen=None,
):
log.info(
f'adding {url}: {quality=} {format=} {already=} {folder=} {custom_name_prefix=} '
f'{playlist_item_limit=} {auto_start=} {split_by_chapters=} {chapter_template=} '
- f'{subtitle_format=} {subtitle_language=} {subtitle_mode=} {custom_filename=}'
+ f'{subtitle_format=} {subtitle_language=} {subtitle_mode=} {custom_filename=} {track_numbering=}'
)
if already is None:
_add_gen = self._add_generation
@@ -816,6 +825,7 @@ class DownloadQueue:
subtitle_mode,
already,
custom_filename,
+ track_numbering,
_add_gen,
)
diff --git a/ui/src/app/app.html b/ui/src/app/app.html
index eaa8385..348c0c7 100644
--- a/ui/src/app/app.html
+++ b/ui/src/app/app.html
@@ -219,6 +219,15 @@
[disabled]="addInProgress || downloads.loading">
+
+
+
+
+
+
Items Limit
diff --git a/ui/src/app/app.ts b/ui/src/app/app.ts
index 26fffb0..18e62a0 100644
--- a/ui/src/app/app.ts
+++ b/ui/src/app/app.ts
@@ -46,6 +46,7 @@ export class App implements AfterViewInit, OnInit {
folder!: string;
customNamePrefix!: string;
customFilename = '';
+ trackNumbering = false;
autoStart: boolean;
playlistItemLimit!: number;
splitByChapters: boolean;
@@ -179,6 +180,7 @@ export class App implements AfterViewInit, OnInit {
this.subtitleFormat = this.cookieService.get('metube_subtitle_format') || 'srt';
this.subtitleLanguage = this.cookieService.get('metube_subtitle_language') || 'en';
this.subtitleMode = this.cookieService.get('metube_subtitle_mode') || 'prefer_manual';
+ this.trackNumbering = this.cookieService.get('metube_track_numbering') === 'true';
const allowedSubtitleFormats = new Set(this.subtitleFormats.map(fmt => fmt.id));
const allowedSubtitleModes = new Set(this.subtitleModes.map(mode => mode.id));
if (!allowedSubtitleFormats.has(this.subtitleFormat)) {
@@ -373,6 +375,10 @@ export class App implements AfterViewInit, OnInit {
this.cookieService.set('metube_subtitle_mode', this.subtitleMode, { expires: 3650 });
}
+ trackNumberingChanged() {
+ this.cookieService.set('metube_track_numbering', this.trackNumbering ? 'true' : 'false', { expires: 3650 });
+ }
+
queueSelectionChanged(checked: number) {
this.queueDelSelected().nativeElement.disabled = checked == 0;
this.queueDownloadSelected().nativeElement.disabled = checked == 0;
@@ -428,10 +434,10 @@ export class App implements AfterViewInit, OnInit {
return;
}
- console.debug('Downloading: url=' + url + ' quality=' + quality + ' format=' + format + ' folder=' + folder + ' customNamePrefix=' + customNamePrefix + ' playlistItemLimit=' + playlistItemLimit + ' autoStart=' + autoStart + ' splitByChapters=' + splitByChapters + ' chapterTemplate=' + chapterTemplate + ' subtitleFormat=' + subtitleFormat + ' subtitleLanguage=' + subtitleLanguage + ' subtitleMode=' + subtitleMode + ' customFilename=' + customFilename);
+ console.debug('Downloading: url=' + url + ' quality=' + quality + ' format=' + format + ' folder=' + folder + ' customNamePrefix=' + customNamePrefix + ' playlistItemLimit=' + playlistItemLimit + ' autoStart=' + autoStart + ' splitByChapters=' + splitByChapters + ' chapterTemplate=' + chapterTemplate + ' subtitleFormat=' + subtitleFormat + ' subtitleLanguage=' + subtitleLanguage + ' subtitleMode=' + subtitleMode + ' customFilename=' + customFilename + ' trackNumbering=' + this.trackNumbering);
this.addInProgress = true;
this.cancelRequested = false;
- this.downloads.add(url, quality, format, folder, customNamePrefix, playlistItemLimit, autoStart, splitByChapters, chapterTemplate, subtitleFormat, subtitleLanguage, subtitleMode, customFilename).subscribe((status: Status) => {
+ this.downloads.add(url, quality, format, folder, customNamePrefix, playlistItemLimit, autoStart, splitByChapters, chapterTemplate, subtitleFormat, subtitleLanguage, subtitleMode, customFilename, this.trackNumbering).subscribe((status: Status) => {
if (status.status === 'error' && !this.cancelRequested) {
alert(`Error adding URL: ${status.msg}`);
} else if (status.status !== 'error') {
@@ -618,7 +624,7 @@ export class App implements AfterViewInit, OnInit {
// Now pass the selected quality, format, folder, etc. to the add() method
this.downloads.add(url, this.quality, this.format, this.folder, this.customNamePrefix,
this.playlistItemLimit, this.autoStart, this.splitByChapters, this.chapterTemplate,
- this.subtitleFormat, this.subtitleLanguage, this.subtitleMode, this.customFilename)
+ this.subtitleFormat, this.subtitleLanguage, this.subtitleMode, this.customFilename, this.trackNumbering)
.subscribe({
next: (status: Status) => {
if (status.status === 'error') {
diff --git a/ui/src/app/interfaces/download.ts b/ui/src/app/interfaces/download.ts
index dbcce49..d0fc544 100644
--- a/ui/src/app/interfaces/download.ts
+++ b/ui/src/app/interfaces/download.ts
@@ -14,6 +14,7 @@ export interface Download {
subtitle_language?: string;
subtitle_mode?: string;
custom_filename?: string;
+ track_numbering?: boolean;
status: string;
msg: string;
percent: number;
diff --git a/ui/src/app/services/downloads.service.ts b/ui/src/app/services/downloads.service.ts
index 0bd83d5..2c7689c 100644
--- a/ui/src/app/services/downloads.service.ts
+++ b/ui/src/app/services/downloads.service.ts
@@ -121,6 +121,7 @@ export class DownloadsService {
subtitleLanguage: string,
subtitleMode: string,
customFilename: string = '',
+ trackNumbering: boolean = false,
) {
return this.http.post('add', {
url: url,
@@ -135,7 +136,8 @@ export class DownloadsService {
subtitle_format: subtitleFormat,
subtitle_language: subtitleLanguage,
subtitle_mode: subtitleMode,
- custom_filename: customFilename
+ custom_filename: customFilename,
+ track_numbering: trackNumbering
}).pipe(
catchError(this.handleHTTPError)
);
@@ -186,6 +188,7 @@ export class DownloadsService {
const defaultSubtitleLanguage = 'en';
const defaultSubtitleMode = 'prefer_manual';
const defaultCustomFilename = '';
+ const defaultTrackNumbering = false;
return new Promise((resolve, reject) => {
this.add(
@@ -202,6 +205,7 @@ export class DownloadsService {
defaultSubtitleLanguage,
defaultSubtitleMode,
defaultCustomFilename,
+ defaultTrackNumbering,
)
.subscribe({
next: (response) => resolve(response),