From c7d9a0b58e66a8a36dd9456641104b6d3bcdaf50 Mon Sep 17 00:00:00 2001 From: tcely Date: Thu, 12 Jun 2025 09:52:22 -0400 Subject: [PATCH 1/3] Add `studio` and `tag` to create-tvshow-nfo.py --- .../management/commands/create-tvshow-nfo.py | 53 +++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/tubesync/sync/management/commands/create-tvshow-nfo.py b/tubesync/sync/management/commands/create-tvshow-nfo.py index 04d472ab..b305da21 100644 --- a/tubesync/sync/management/commands/create-tvshow-nfo.py +++ b/tubesync/sync/management/commands/create-tvshow-nfo.py @@ -1,3 +1,5 @@ +import base64 +import binascii from common.logger import log from django.utils.translation import gettext_lazy as _ from sync.models import Source @@ -5,16 +7,50 @@ from sync.utils import write_text_file from django.core.management.base import BaseCommand, CommandError +def validYoutubeID(arg, /): + arg_str = str(arg).strip() + valid_beginning = ( arg_str[0:2] in frozenset(('PL','UC','UU',)) ) + # channels end in one of these: A, Q, g, w, + # playlists are, of course, different. + valid_ending = ( + ( arg_str[0:2] in frozenset(('PL',)) ) or + ( arg_str[-1] in frozenset('AQgw') ) + ) + valid_length = len(arg_str) in {24, 34} + if not ( valid_beginning and valid_ending and valid_length ): + raise ValueError('not a channel or playlist ID') + try: + base64.b64decode(arg_str[2:] + '==', altchars='-_', validate=True) + except binascii.Error as e: + raise ValueError('not a channel or playlist ID') from e + return arg_str + +_filename = 'tvshow.nfo' class Command(BaseCommand): - filename = 'tvshow.nfo' - help = 'Creates a "tvshow.nfo" file for a source during the indexing process' + filename = _filename + help = f'Creates a "{_filename}" file for a source during the indexing process' def add_arguments(self, parser): - parser.add_argument('id', type=str) + parser.add_argument('id') + parser.add_argument('channel_id', nargs='?') + parser.add_argument('--name', default=list(), nargs='*') def handle(self, *args, **options): + channel_id = options['channel_id'] + channel_name = ' '.join(options['name']]).strip() key = options['id'] + try: + key = validYoutubeID(key) + except ValueError as e: + raise CommandError(_(f'not a valid YouTube ID: {key=}')) from e + try: + if channel_id is not None: + channel_id = validYoutubeID(channel_id) + except ValueError as e: + log.exception(f'{e}') + log.info('Continuing without a channel_id') + channel_id = None try: source = Source.objects.get(key=key) except Source.DoesNotExist as e: @@ -36,8 +72,19 @@ class Command(BaseCommand): {source.name} {source.key} + {channel_name} + Youtube + {channel_id or ''} ''' + content = '\n'.join(filter( + lambda s: s.replace( + '', '', + ).replace( + '', '', + ).lstrip(' '), + content.splitlines(), + )) log.debug( f'Writing new content to: {nfo_path}', ) From 6c39e6d3aa59634e0b23e22ecaec28fdcbc410d9 Mon Sep 17 00:00:00 2001 From: tcely Date: Thu, 12 Jun 2025 10:05:56 -0400 Subject: [PATCH 2/3] fixup: end with a line separator --- tubesync/sync/management/commands/create-tvshow-nfo.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tubesync/sync/management/commands/create-tvshow-nfo.py b/tubesync/sync/management/commands/create-tvshow-nfo.py index b305da21..095c03d7 100644 --- a/tubesync/sync/management/commands/create-tvshow-nfo.py +++ b/tubesync/sync/management/commands/create-tvshow-nfo.py @@ -1,5 +1,6 @@ import base64 import binascii +import os from common.logger import log from django.utils.translation import gettext_lazy as _ from sync.models import Source @@ -38,7 +39,7 @@ class Command(BaseCommand): def handle(self, *args, **options): channel_id = options['channel_id'] - channel_name = ' '.join(options['name']]).strip() + channel_name = ' '.join(options['name']).strip() key = options['id'] try: key = validYoutubeID(key) @@ -77,14 +78,14 @@ class Command(BaseCommand): {channel_id or ''} ''' - content = '\n'.join(filter( + content = os.linesep.join(filter( lambda s: s.replace( '', '', ).replace( '', '', ).lstrip(' '), content.splitlines(), - )) + )) + os.linesep log.debug( f'Writing new content to: {nfo_path}', ) From 7a25fd169d7b3d155c19aa27fd72d5ebd39c925a Mon Sep 17 00:00:00 2001 From: tcely Date: Thu, 12 Jun 2025 12:49:26 -0400 Subject: [PATCH 3/3] Special case for `UULV` prefix of channel IDs --- tubesync/sync/management/commands/create-tvshow-nfo.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tubesync/sync/management/commands/create-tvshow-nfo.py b/tubesync/sync/management/commands/create-tvshow-nfo.py index 095c03d7..3691b259 100644 --- a/tubesync/sync/management/commands/create-tvshow-nfo.py +++ b/tubesync/sync/management/commands/create-tvshow-nfo.py @@ -17,11 +17,14 @@ def validYoutubeID(arg, /): ( arg_str[0:2] in frozenset(('PL',)) ) or ( arg_str[-1] in frozenset('AQgw') ) ) - valid_length = len(arg_str) in {24, 34} + valid_length = len(arg_str) in {18, 24, 26, 34} if not ( valid_beginning and valid_ending and valid_length ): raise ValueError('not a channel or playlist ID') try: - base64.b64decode(arg_str[2:] + '==', altchars='-_', validate=True) + value = arg_str[2:] + '==' + if 26 == len(arg_str) and 'UULV' == arg_str[0:4]: + value = value[2:] + base64.b64decode(value, altchars='-_', validate=True) except binascii.Error as e: raise ValueError('not a channel or playlist ID') from e return arg_str