diff --git a/tubesync/sync/management/commands/delete-source.py b/tubesync/sync/management/commands/delete-source.py index 5ab8a325..2f149a67 100644 --- a/tubesync/sync/management/commands/delete-source.py +++ b/tubesync/sync/management/commands/delete-source.py @@ -5,7 +5,6 @@ from django.core.management.base import BaseCommand, CommandError from django.db.models import signals from common.logger import log from sync.models import Source, Media, MediaServer -from sync.signals import media_post_delete from sync.tasks import schedule_media_servers_update diff --git a/tubesync/sync/management/commands/reset-tasks.py b/tubesync/sync/management/commands/reset-tasks.py index d7818007..3d6f515d 100644 --- a/tubesync/sync/management/commands/reset-tasks.py +++ b/tubesync/sync/management/commands/reset-tasks.py @@ -13,21 +13,28 @@ class Command(BaseCommand): help = 'Resets all tasks' - @atomic(durable=True) def handle(self, *args, **options): log.info('Resettings all tasks...') - # Delete all tasks - Task.objects.all().delete() - # Iter all tasks - for source in Source.objects.all(): - # Recreate the initial indexing task - log.info(f'Resetting tasks for source: {source}') - verbose_name = _('Index media from source "{}"') - index_source_task( - str(source.pk), - repeat=source.index_schedule, - verbose_name=verbose_name.format(source.name) - ) - # This also chains down to call each Media objects .save() as well - source.save() + with atomic(durable=True): + # Delete all tasks + Task.objects.all().delete() + # Iter all sources, creating new tasks + for source in Source.objects.all(): + verbose_name = _('Check download directory exists for source "{}"') + check_source_directory_exists( + str(source.pk), + verbose_name=verbose_name.format(source.name), + ) + # Recreate the initial indexing task + log.info(f'Resetting tasks for source: {source}') + verbose_name = _('Index media from source "{}"') + index_source_task( + str(source.pk), + repeat=source.index_schedule, + verbose_name=verbose_name.format(source.name), + ) + with atomic(durable=True): + for source in Source.objects.all(): + # This also chains down to call each Media objects .save() as well + source.save() log.info('Done') diff --git a/tubesync/sync/signals.py b/tubesync/sync/signals.py index 6ee64747..4c332eca 100644 --- a/tubesync/sync/signals.py +++ b/tubesync/sync/signals.py @@ -221,7 +221,7 @@ def media_post_save(sender, instance, created, **kwargs): else: # Downloaded media might need to be renamed # Check settings before any rename tasks are scheduled - rename_sources_setting = settings.RENAME_SOURCES or list() + rename_sources_setting = getattr(settings, 'RENAME_SOURCES') or list() create_rename_task = ( ( media.source.directory and diff --git a/tubesync/sync/tasks.py b/tubesync/sync/tasks.py index 79e283c3..3b02e029 100644 --- a/tubesync/sync/tasks.py +++ b/tubesync/sync/tasks.py @@ -746,7 +746,7 @@ def rename_all_media_for_source(source_id): f'source exists with ID: {source_id}') raise InvalidTaskError(_('no such source')) from e # Check that the settings allow renaming - rename_sources_setting = getattr(settings, 'RENAME_SOURCES', list()) + rename_sources_setting = getattr(settings, 'RENAME_SOURCES') or list() create_rename_tasks = ( ( source.directory and diff --git a/tubesync/sync/templates/sync/dashboard.html b/tubesync/sync/templates/sync/dashboard.html index af342800..23e1cdb2 100644 --- a/tubesync/sync/templates/sync/dashboard.html +++ b/tubesync/sync/templates/sync/dashboard.html @@ -99,6 +99,18 @@ +
+
+

Warnings

+
+ An upcoming release, after 2025-006-01, will introduce automated file renaming.
+ To prevent this change from taking effect, you can set an environment variable before that date.
+ See the GitHub README + for more details or ask questions using + issue #785.
+
+
+

Runtime information

diff --git a/tubesync/sync/views.py b/tubesync/sync/views.py index f489144b..0e3f8dbb 100644 --- a/tubesync/sync/views.py +++ b/tubesync/sync/views.py @@ -931,6 +931,11 @@ class ResetTasks(FormView): Task.objects.all().delete() # Iter all tasks for source in Source.objects.all(): + verbose_name = _('Check download directory exists for source "{}"') + check_source_directory_exists( + str(source.pk), + verbose_name=verbose_name.format(source.name), + ) # Recreate the initial indexing task verbose_name = _('Index media from source "{}"') index_source_task( diff --git a/tubesync/sync/youtube.py b/tubesync/sync/youtube.py index a10ca31d..145e4c5d 100644 --- a/tubesync/sync/youtube.py +++ b/tubesync/sync/youtube.py @@ -14,6 +14,7 @@ from tempfile import TemporaryDirectory from urllib.parse import urlsplit, parse_qs from django.conf import settings +from .choices import Val, FileExtension from .hooks import postprocessor_hook, progress_hook from .utils import mkdir_p import yt_dlp @@ -301,6 +302,15 @@ def download_media( ).options.sponsorblock_mark pp_opts.sponsorblock_remove.update(sponsor_categories or {}) + # Enable audio extraction for audio-only extensions + audio_exts = set(Val( + FileExtension.M4A, + FileExtension.OGG, + )) + if extension in audio_exts: + pp_opts.extractaudio = True + pp_opts.nopostoverwrites = False + ytopts = { 'format': media_format, 'merge_output_format': extension, diff --git a/tubesync/tubesync/settings.py b/tubesync/tubesync/settings.py index c9e9a2f3..6ce95317 100644 --- a/tubesync/tubesync/settings.py +++ b/tubesync/tubesync/settings.py @@ -7,7 +7,7 @@ CONFIG_BASE_DIR = BASE_DIR DOWNLOADS_BASE_DIR = BASE_DIR -VERSION = '0.13.7' +VERSION = '0.14.1' SECRET_KEY = '' DEBUG = False ALLOWED_HOSTS = []