From 1c72d045af4d7c5607a872a678eadec17498bd6d Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Thu, 22 Oct 2020 15:38:56 +0200 Subject: [PATCH] Support multiple youtube configs. --- requirements.txt | 2 + .../migrations/0019_auto_20201022_1414.py | 40 +++++++++++++++++++ .../migrations/0020_auto_20201022_1535.py | 20 ++++++++++ src/archive/models.py | 27 ++++++++++++- src/archive/tasks.py | 1 + .../migrations/0015_auto_20201022_1414.py | 25 ++++++++++++ .../0016_populate_youtube_relations.py | 32 +++++++++++++++ .../migrations/0017_auto_20201022_1535.py | 19 +++++++++ src/youtube/models.py | 5 +++ src/youtube/tasks.py | 4 +- src/youtube/views.py | 14 ++++--- 11 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 src/archive/migrations/0019_auto_20201022_1414.py create mode 100644 src/archive/migrations/0020_auto_20201022_1535.py create mode 100644 src/youtube/migrations/0015_auto_20201022_1414.py create mode 100644 src/youtube/migrations/0016_populate_youtube_relations.py create mode 100644 src/youtube/migrations/0017_auto_20201022_1535.py diff --git a/requirements.txt b/requirements.txt index 1c6781e..f910911 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,5 @@ requests-toolbelt==0.9.1 requests-oauthlib==1.3.0 PyYAML==5.3.1 Pillow==7.2.0 +librarian==1.9 +py3-aeneas==1.1.0 diff --git a/src/archive/migrations/0019_auto_20201022_1414.py b/src/archive/migrations/0019_auto_20201022_1414.py new file mode 100644 index 0000000..aa4ebd5 --- /dev/null +++ b/src/archive/migrations/0019_auto_20201022_1414.py @@ -0,0 +1,40 @@ +# Generated by Django 3.1.2 on 2020-10-22 14:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('youtube', '0015_auto_20201022_1414'), + ('archive', '0018_auto_20200703_1718'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='youtube', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='youtube.youtube'), + ), + migrations.AlterField( + model_name='audiobook', + name='mp3_status', + field=models.SmallIntegerField(choices=[(5, 'Queued'), (10, 'Waiting'), (20, 'Encoding'), (30, 'Tagging'), (40, 'Converting audio'), (50, 'Converting video'), (60, 'Assembling audio'), (70, 'Assembling video'), (80, 'Joining audio and video'), (100, 'Sending'), (110, 'Setting thumbnail')], editable=False, null=True), + ), + migrations.AlterField( + model_name='audiobook', + name='ogg_status', + field=models.SmallIntegerField(choices=[(5, 'Queued'), (10, 'Waiting'), (20, 'Encoding'), (30, 'Tagging'), (40, 'Converting audio'), (50, 'Converting video'), (60, 'Assembling audio'), (70, 'Assembling video'), (80, 'Joining audio and video'), (100, 'Sending'), (110, 'Setting thumbnail')], editable=False, null=True), + ), + migrations.AlterField( + model_name='audiobook', + name='slug', + field=models.SlugField(blank=True, help_text='WL catalogue slug of the book.', max_length=120), + ), + migrations.AlterField( + model_name='audiobook', + name='youtube_status', + field=models.SmallIntegerField(choices=[(5, 'Queued'), (10, 'Waiting'), (20, 'Encoding'), (30, 'Tagging'), (40, 'Converting audio'), (50, 'Converting video'), (60, 'Assembling audio'), (70, 'Assembling video'), (80, 'Joining audio and video'), (100, 'Sending'), (110, 'Setting thumbnail')], editable=False, null=True), + ), + ] diff --git a/src/archive/migrations/0020_auto_20201022_1535.py b/src/archive/migrations/0020_auto_20201022_1535.py new file mode 100644 index 0000000..ace0a98 --- /dev/null +++ b/src/archive/migrations/0020_auto_20201022_1535.py @@ -0,0 +1,20 @@ +# Generated by Django 3.1.2 on 2020-10-22 15:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('youtube', '0017_auto_20201022_1535'), + ('archive', '0019_auto_20201022_1414'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='youtube', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='youtube.youtube'), + ), + ] diff --git a/src/archive/models.py b/src/archive/models.py index 3be61d4..b15bec2 100644 --- a/src/archive/models.py +++ b/src/archive/models.py @@ -1,3 +1,4 @@ +import io import json import os.path @@ -27,6 +28,7 @@ class Project(models.Model): name = models.CharField(max_length=128, unique=True, db_index=True, verbose_name="Nazwa") sponsors = models.TextField(blank=True, null=True, verbose_name="Sponsorzy") description = models.TextField(blank=True, verbose_name="Opis") + youtube = models.ForeignKey('youtube.YouTube', models.PROTECT) class Meta: verbose_name = _("project") @@ -81,7 +83,7 @@ class Audiobook(models.Model): encoded_by = models.CharField(max_length=255, verbose_name=_('encoded by')) date = models.CharField(max_length=255, verbose_name=_('date')) project = models.ForeignKey(Project, models.PROTECT, verbose_name=_('project')) - slug = models.SlugField(max_length=120, help_text=_('WL catalogue slug of the book.')) + slug = models.SlugField(max_length=120, blank=True, help_text=_('WL catalogue slug of the book.')) translator = models.CharField(max_length=255, null=True, blank=True, verbose_name=_('translator')) modified = models.DateTimeField(null=True, editable=False) license = models.ForeignKey(License, models.PROTECT, null=True, blank=True, verbose_name=_('license')) @@ -222,5 +224,26 @@ class Audiobook(models.Model): @cached_property def book(self): - apidata = requests.get(f'https://wolnelektury.pl/api/books/{self.slug}/').json() + if self.slug: + apidata = requests.get(f'https://wolnelektury.pl/api/books/{self.slug}/').json() + else: + return {} return apidata + + @property + def document(self): + from librarian.document import WLDocument, parser + from lxml import etree + + xml_url = self.book.get('xml', None) + if xml_url is None: + return None + + return WLDocument( + etree.parse( + io.BytesIO( + requests.get(xml_url).content + ) + ,parser = parser + ) + ) diff --git a/src/archive/tasks.py b/src/archive/tasks.py index e50d9b2..b5c64ce 100644 --- a/src/archive/tasks.py +++ b/src/archive/tasks.py @@ -89,6 +89,7 @@ class AudioFormatTask(Task): def run(self, uid, aid, publish=True): aid = int(aid) audiobook = Audiobook.objects.get(id=aid) + self.audiobook = audiobook self.set_status(aid, status.ENCODING) if uid: diff --git a/src/youtube/migrations/0015_auto_20201022_1414.py b/src/youtube/migrations/0015_auto_20201022_1414.py new file mode 100644 index 0000000..d837410 --- /dev/null +++ b/src/youtube/migrations/0015_auto_20201022_1414.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.2 on 2020-10-22 14:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('youtube', '0014_auto_20200706_1219'), + ] + + operations = [ + migrations.AddField( + model_name='thumbnailtemplate', + name='youtube', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='youtube.youtube'), + ), + migrations.AddField( + model_name='youtube', + name='name', + field=models.CharField(default='Wolne Lektury', max_length=255), + preserve_default=False, + ), + ] diff --git a/src/youtube/migrations/0016_populate_youtube_relations.py b/src/youtube/migrations/0016_populate_youtube_relations.py new file mode 100644 index 0000000..2ea388a --- /dev/null +++ b/src/youtube/migrations/0016_populate_youtube_relations.py @@ -0,0 +1,32 @@ +# Generated by Django 3.1.2 on 2020-10-22 14:15 + +from django.db import migrations + + +def populate_youtube_relations(apps, schema_editor): + YouTube = apps.get_model('youtube', 'YouTube') + ThumbnailTemplate = apps.get_model('youtube', 'ThumbnailTemplate') + Project = apps.get_model('archive', 'Project') + + try: + yt = YouTube.objects.first() + except YouTube.DoesNotExist: + yt = YouTube.objects.create(name='default') + + Project.objects.filter(youtube=None).update(youtube=yt) + ThumbnailTemplate.objects.filter(youtube=None).update(youtube=yt) + + +class Migration(migrations.Migration): + + dependencies = [ + ('youtube', '0015_auto_20201022_1414'), + ('archive', '0019_auto_20201022_1414'), + ] + + operations = [ + migrations.RunPython( + populate_youtube_relations, + migrations.RunPython.noop + ) + ] diff --git a/src/youtube/migrations/0017_auto_20201022_1535.py b/src/youtube/migrations/0017_auto_20201022_1535.py new file mode 100644 index 0000000..63a0e34 --- /dev/null +++ b/src/youtube/migrations/0017_auto_20201022_1535.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.2 on 2020-10-22 15:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('youtube', '0016_populate_youtube_relations'), + ] + + operations = [ + migrations.AlterField( + model_name='thumbnailtemplate', + name='youtube', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='youtube.youtube'), + ), + ] diff --git a/src/youtube/models.py b/src/youtube/models.py index 356e335..df071f1 100644 --- a/src/youtube/models.py +++ b/src/youtube/models.py @@ -24,6 +24,7 @@ YOUTUBE_TITLE_LIMIT = 100 class YouTube(models.Model): + name = models.CharField(max_length=255) title_template = models.CharField(max_length=1024, blank=True) description_template = models.TextField(blank=True) category = models.IntegerField(null=True, blank=True, choices=[ @@ -44,6 +45,9 @@ class YouTube(models.Model): verbose_name = _("YouTube configuration") verbose_name_plural = _("YouTube configurations") + def __str__(self): + return self.name + def get_context(self, audiobook): return Context(dict( audiobook=audiobook, @@ -212,6 +216,7 @@ class Font(models.Model): class ThumbnailTemplate(models.Model): + youtube = models.ForeignKey(YouTube, models.CASCADE) order = models.SmallIntegerField() is_active = models.BooleanField() background = models.FileField(upload_to='youtube/thumbnail') diff --git a/src/youtube/tasks.py b/src/youtube/tasks.py index 63051c9..cad3d11 100644 --- a/src/youtube/tasks.py +++ b/src/youtube/tasks.py @@ -8,7 +8,7 @@ class YouTubeTask(AudioFormatTask): prefix = 'youtube' def encode(self, in_paths, out_path): - YouTube.objects.first().prepare_file(in_paths, out_path) + self.audiobook.project.youtube.prepare_file(in_paths, out_path) def set_tags(self, audiobook, filename): pass @@ -19,7 +19,7 @@ class YouTubeTask(AudioFormatTask): os.unlink(file_name) def put(self, user, audiobook, filename): - YouTube.objects.first().publish(audiobook, filename) + audiobook.project.youtube.publish(audiobook, filename) def get_source_file_paths(self, audiobook): if not audiobook.youtube_volume: diff --git a/src/youtube/views.py b/src/youtube/views.py index 18bd1d7..e0bcab2 100644 --- a/src/youtube/views.py +++ b/src/youtube/views.py @@ -34,7 +34,7 @@ def book_publish(request, slug): def thumbnail(request, aid, thumbnail_id=None): audiobook = get_object_or_404(Audiobook, id=aid) if thumbnail_id is None: - yt = models.YouTube.objects.first() + yt = audiobook.project.youtube buf = yt.prepare_thumbnail(audiobook) else: template = get_object_or_404(models.ThumbnailTemplate, id=thumbnail_id) @@ -49,7 +49,7 @@ class Preview(DetailView): def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) - yt = models.YouTube.objects.first() + yt = ctx['object'].project.youtube ctx['data'] = yt.get_data(ctx['object']) ctx['title'] = yt.get_title(ctx['object']) ctx['description'] = yt.get_description(ctx['object']) @@ -62,8 +62,9 @@ class Update(SingleObjectMixin, View): model = Audiobook def post(self, request, pk): - yt = models.YouTube.objects.first() - yt.update_data(self.get_object()) + obj = self.get_object() + yt = obj.project.youtube + yt.update_data(obj) return redirect(reverse('file', args=[pk])) @@ -72,6 +73,7 @@ class UpdateThumbnail(SingleObjectMixin, View): model = Audiobook def post(self, request, pk): - yt = models.YouTube.objects.first() - yt.update_thumbnail(self.get_object()) + obj = self.get_object() + yt = obj.project.youtube + yt.update_thumbnail(obj) return redirect(reverse('file', args=[pk])) -- 2.20.1