diff --git a/.gitignore b/.gitignore index eec472f..cb14cfd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/tubesync/sync/migrations/0018_source_subtitles.py b/tubesync/sync/migrations/0018_source_subtitles.py new file mode 100644 index 0000000..c526b99 --- /dev/null +++ b/tubesync/sync/migrations/0018_source_subtitles.py @@ -0,0 +1,27 @@ +# Generated by pac + +from django.db import migrations, models + +class Migration(migrations.Migration): + + dependencies = [ + ('sync', '0017_alter_source_sponsorblock_categories'), + ] + + operations = [ + migrations.AddField( + model_name='source', + name='write_subtitles', + field=models.BooleanField(default=False, help_text='Download video subtitles', verbose_name='write subtitles'), + ), + migrations.AddField( + model_name='source', + name='auto_subtitles', + field=models.BooleanField(default=False, help_text='Accept auto-generated subtitles', verbose_name='accept auto subtitles'), + ), + migrations.AddField( + model_name='source', + name='sub_langs', + field=models.CharField(default='en', help_text='List of subtitles langs to download comma-separated. Example: en,fr',max_length=30), + ), + ] diff --git a/tubesync/sync/models.py b/tubesync/sync/models.py index 35fcda1..874524c 100644 --- a/tubesync/sync/models.py +++ b/tubesync/sync/models.py @@ -8,6 +8,7 @@ from pathlib import Path from django.conf import settings from django.db import models from django.core.files.storage import FileSystemStorage +from django.core.validators import RegexValidator from django.utils.text import slugify from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -349,6 +350,30 @@ class Source(models.Model): help_text=_('Source has failed to index media') ) + write_subtitles = models.BooleanField( + _('write subtitles'), + default=False, + help_text=_('Download video subtitles') + ) + + auto_subtitles = models.BooleanField( + _('accept auto-generated subs'), + default=False, + help_text=_('Accept auto-generated subtitles') + ) + sub_langs = models.CharField( + _('subs langs'), + max_length=30, + default='en', + help_text=_('List of subtitles langs to download, comma-separated. Example: en,fr or all,-fr,-live_chat'), + validators=[ + RegexValidator( + regex=r"^(\-?[\_\.a-zA-Z]+,)*(\-?[\_\.a-zA-Z]+){1}$", + message=_('Subtitle langs must be a comma-separated list of langs. example: en,fr or all,-fr,-live_chat') + ) + ] + ) + def __str__(self): return self.name @@ -1333,7 +1358,8 @@ class Media(models.Model): download_youtube_media(self.url, format_str, self.source.extension, str(self.filepath), self.source.write_json, self.source.sponsorblock_categories, self.source.embed_thumbnail, - self.source.embed_metadata, self.source.enable_sponsorblock) + self.source.embed_metadata, self.source.enable_sponsorblock, + self.source.write_subtitles, self.source.auto_subtitles,self.source.sub_langs ) # Return the download paramaters return format_str, self.source.extension diff --git a/tubesync/sync/templates/sync/source.html b/tubesync/sync/templates/sync/source.html index 1b789ed..65cf242 100644 --- a/tubesync/sync/templates/sync/source.html +++ b/tubesync/sync/templates/sync/source.html @@ -162,6 +162,22 @@ {% endif %} + + + {{ _("Download subtitles?") }}: + {{ _("Download subtitles?") }}: + + + {% if source.write_subtitles %} + + {{ _("Auto-generated subtitles?") }}: + {{ _("Auto-generated subtitles?") }}: + + + {{ _("Subs langs?") }}: + {{ _("Subs langs?") }}:{{source.sub_langs}} + + {% endif %} diff --git a/tubesync/sync/views.py b/tubesync/sync/views.py index b1a2860..6fb36d1 100644 --- a/tubesync/sync/views.py +++ b/tubesync/sync/views.py @@ -299,7 +299,7 @@ class EditSourceMixin: 'days_to_keep', 'source_resolution', 'source_vcodec', 'source_acodec', 'prefer_60fps', 'prefer_hdr', 'fallback', 'copy_thumbnails', 'write_nfo', 'write_json', 'embed_metadata', 'embed_thumbnail', 'enable_sponsorblock', - 'sponsorblock_categories') + 'sponsorblock_categories', 'write_subtitles', 'auto_subtitles', 'sub_langs') errors = { 'invalid_media_format': _('Invalid media format, the media format contains ' 'errors or is empty. Check the table at the end of ' diff --git a/tubesync/sync/youtube.py b/tubesync/sync/youtube.py index 00ae958..4ac6e83 100644 --- a/tubesync/sync/youtube.py +++ b/tubesync/sync/youtube.py @@ -66,13 +66,18 @@ def get_media_info(url): def download_media(url, media_format, extension, output_file, info_json, sponsor_categories="all", - embed_thumbnail=False, embed_metadata=False, skip_sponsors=True): + embed_thumbnail=False, embed_metadata=False, skip_sponsors=True, + write_subtitles=False, auto_subtitles=False, sub_langs='en'): ''' Downloads a YouTube URL to a file on disk. ''' def hook(event): filename = os.path.basename(event['filename']) + + if event.get('downloaded_bytes') is None or event.get('total_bytes') is None: + return None + if event['status'] == 'error': log.error(f'[youtube-dl] error occured downloading: {filename}') elif event['status'] == 'downloading': @@ -110,8 +115,12 @@ def download_media(url, media_format, extension, output_file, info_json, 'quiet': True, 'progress_hooks': [hook], 'writeinfojson': info_json, - 'postprocessors': [] + 'postprocessors': [], + 'writesubtitles': write_subtitles, + 'writeautomaticsub': auto_subtitles, + 'subtitleslangs': sub_langs.split(','), } + sbopt = { 'key': 'SponsorBlock', 'categories': [sponsor_categories]