diff --git a/app/sync/models.py b/app/sync/models.py index dbfce5c9..4fa94bee 100644 --- a/app/sync/models.py +++ b/app/sync/models.py @@ -7,6 +7,7 @@ from django.db import models from django.utils.text import slugify from django.utils.translation import gettext_lazy as _ from .youtube import get_media_info as get_youtube_media_info +from .utils import seconds_to_timestr class Source(models.Model): @@ -69,36 +70,27 @@ class Source(models.Model): (FALLBACK_NEXT_HD, _('Get next best HD media or codec instead')), ) + # Fontawesome icons used for the source on the front end ICONS = { SOURCE_TYPE_YOUTUBE_CHANNEL: '', SOURCE_TYPE_YOUTUBE_PLAYLIST: '', } - + # Format to use to display a URL for the source URLS = { SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/c/{key}', SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/playlist?list={key}', } - + # Callback functions to get a list of media from the source INDEXERS = { SOURCE_TYPE_YOUTUBE_CHANNEL: get_youtube_media_info, SOURCE_TYPE_YOUTUBE_PLAYLIST: get_youtube_media_info, } - - KEY_FIELD = { # Field returned by indexing which contains a unique key + # Field names to find the media ID used as the key when storing media + KEY_FIELD = { SOURCE_TYPE_YOUTUBE_CHANNEL: 'id', SOURCE_TYPE_YOUTUBE_PLAYLIST: 'id', } - PUBLISHED_FIELD = { # Field returned by indexing which contains the published date - SOURCE_TYPE_YOUTUBE_CHANNEL: 'upload_date', - SOURCE_TYPE_YOUTUBE_PLAYLIST: 'upload_date', - } - - TITLE_FIELD = { # Field returned by indexing which contains the media title - SOURCE_TYPE_YOUTUBE_CHANNEL: 'title', - SOURCE_TYPE_YOUTUBE_PLAYLIST: 'title', - } - uuid = models.UUIDField( _('uuid'), primary_key=True, @@ -313,10 +305,34 @@ class Media(models.Model): Source. ''' + # Format to use to display a URL for the media URLS = { Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'https://www.youtube.com/watch?v={key}', Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'https://www.youtube.com/watch?v={key}', } + # Maps standardised names to names used in source metdata + METADATA_FIELDS = { + 'upload_date': { + Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'upload_date', + Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'upload_date', + }, + 'title': { + Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'title', + Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'title', + }, + 'description': { + Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'description', + Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'description', + }, + 'duration': { + Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'duration', + Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'duration', + }, + 'formats': { + Source.SOURCE_TYPE_YOUTUBE_CHANNEL: 'formats', + Source.SOURCE_TYPE_YOUTUBE_PLAYLIST: 'formats', + } + } uuid = models.UUIDField( _('uuid'), @@ -435,6 +451,10 @@ class Media(models.Model): verbose_name = _('Media') verbose_name_plural = _('Media') + def get_metadata_field(self, field): + fields = self.METADATA_FIELDS.get(field, {}) + return fields.get(self.source.source_type, '') + @property def loaded_metadata(self): if self.pk in _metadata_cache: @@ -453,8 +473,8 @@ class Media(models.Model): @property def title(self): - k = self.source.TITLE_FIELD.get(self.source.source_type, '') - return self.loaded_metadata.get(k, '').strip() + field = self.get_metadata_field('title') + return self.loaded_metadata.get(field, '').strip() @property def name(self): @@ -463,13 +483,30 @@ class Media(models.Model): @property def upload_date(self): - k = self.source.PUBLISHED_FIELD.get(self.source.source_type, '') - upload_date_str = self.loaded_metadata.get(k, '').strip() + field = self.get_metadata_field('upload_date') + upload_date_str = self.loaded_metadata.get(field, '').strip() try: return datetime.strptime(upload_date_str, '%Y%m%d') except (AttributeError, ValueError) as e: return None + @property + def duration(self): + field = self.get_metadata_field('duration') + return int(self.loaded_metadata.get(field, 0)) + + @property + def duration_formatted(self): + duration = self.duration + if duration > 0: + return seconds_to_timestr(duration) + return '??:??:??' + + @property + def formats(self): + field = self.get_metadata_field('formats') + return self.loaded_metadata.get(field, []) + @property def filename(self): upload_date = self.upload_date diff --git a/app/sync/templates/sync/media-item.html b/app/sync/templates/sync/media-item.html index bbb3d705..5b17f3aa 100644 --- a/app/sync/templates/sync/media-item.html +++ b/app/sync/templates/sync/media-item.html @@ -21,6 +21,10 @@ Title Title
{{ media.title }} + + Duration + Duration
{{ media.duration_formatted }} + Filename Filename
{{ media.filename }} @@ -33,6 +37,16 @@ Downloaded Downloaded
{% if media.downloaded %}{% else %}{% endif %} + + Available formats + Available formats
+ {% for format in media.formats %} + {{ format.format }}
+ {% empty %} + Media has no detected available formats + {% endfor %} + + diff --git a/app/sync/utils.py b/app/sync/utils.py index a5c1cda5..2afeca9a 100644 --- a/app/sync/utils.py +++ b/app/sync/utils.py @@ -107,3 +107,12 @@ def delete_file(filepath): if file_is_editable(filepath): return os.remove(filepath) return False + + +def seconds_to_timestr(seconds): + seconds = seconds % (24 * 3600) + hour = seconds // 3600 + seconds %= 3600 + minutes = seconds // 60 + seconds %= 60 + return '{:02d}:{:02d}:{:02d}'.format(hour, minutes, seconds)