Off by one error. master
authorRadek Czajka <rczajka@rczajka.pl>
Mon, 26 Jun 2023 09:38:35 +0000 (11:38 +0200)
committerRadek Czajka <rczajka@rczajka.pl>
Mon, 26 Jun 2023 09:47:22 +0000 (11:47 +0200)
30 files changed:
requirements.txt
src/apiclient/urls.py
src/archive/admin.py
src/archive/forms.py
src/archive/locale/pl/LC_MESSAGES/django.mo
src/archive/locale/pl/LC_MESSAGES/django.po
src/archive/migrations/0023_project_info_flac.py [new file with mode: 0644]
src/archive/migrations/0024_auto_20211222_1604.py [new file with mode: 0644]
src/archive/migrations/0025_create_config.py [new file with mode: 0644]
src/archive/migrations/0026_auto_20211222_1605.py [new file with mode: 0644]
src/archive/migrations/0027_auto_20221025_1336.py [new file with mode: 0644]
src/archive/migrations/0028_auto_20221025_1341.py [new file with mode: 0644]
src/archive/migrations/0029_auto_20221025_1357.py [new file with mode: 0644]
src/archive/models.py
src/archive/tasks.py
src/archive/templates/archive/book.html
src/archive/templates/archive/file_managed.html
src/archive/templates/archive/list_publishing.html
src/archive/templatetags/tags.py
src/archive/urls.py
src/archive/views.py
src/audiobooks/settings.py
src/youtube/locale/pl/LC_MESSAGES/django.mo
src/youtube/locale/pl/LC_MESSAGES/django.po
src/youtube/management/commands/youtube.py
src/youtube/migrations/0012_move_thumbnail_definitions.py
src/youtube/tasks.py
src/youtube/thumbnail.py
src/youtube/urls.py
src/youtube/utils.py

index 20e30d7..5c31d8c 100644 (file)
@@ -1,19 +1,20 @@
--i https://py.mdrn.pl:8443/simple
+-i https://py.mdrn.pl/simple
 
 
-Django==3.1.8
-django-cas-ng==4.1.1
-django-bootstrap4==2.2.0
+Django==3.2.16
+django-cas-ng==4.3.0
+django-bootstrap4==22.2
 django-pglocks==1.0.4
 django-pglocks==1.0.4
-fnp-django-pagination==2.2.4
+fnp-django-pagination==2.2.5
 
 
+# ?
 celery[redis]==4.4.2
 
 celery[redis]==4.4.2
 
-psycopg2-binary==2.8.5
-mutagen==1.45.1
-requests==2.24.0
-requests-toolbelt==0.9.1
-requests-oauthlib==1.3.0
-PyYAML==5.4.1
-Pillow==8.2.0
-librarian==1.9
+psycopg2-binary==2.9.5
+mutagen==1.46.0
+requests==2.28.1
+requests-toolbelt==0.10.1
+requests-oauthlib==1.3.1
+PyYAML==6.0
+Pillow==9.2.0
+librarian==2.4.8
 py3-aeneas==1.1.0
 py3-aeneas==1.1.0
index ad3f166..58dec53 100755 (executable)
@@ -1,10 +1,10 @@
-from django.conf.urls import url
+from django.urls import path
 from . import views
 
 
 urlpatterns = [
 from . import views
 
 
 urlpatterns = [
-    url(r'^oauth/$', views.oauth, name='apiclient_oauth'),
-    url(r'^oauth_callback/$', views.oauth_callback, name='apiclient_oauth_callback'),
-    url(r'^oauth2/$', views.oauth2, name='apiclient_oauth2'),
-    url(r'^oauth2_redirect/$', views.oauth2_redirect, name='apiclient_oauth2_redirect'),
+    path('oauth/', views.oauth, name='apiclient_oauth'),
+    path('auth_callback/', views.oauth_callback, name='apiclient_oauth_callback'),
+    path('oauth2/', views.oauth2, name='apiclient_oauth2'),
+    path('oauth2_redirect/', views.oauth2_redirect, name='apiclient_oauth2_redirect'),
 ]
 ]
index 10f1a33..f9249af 100644 (file)
@@ -1,4 +1,4 @@
-from archive.models import Project, Audiobook, License
+from archive.models import Project, Audiobook, License, Config
 from django.contrib import admin
 
 admin.site.register(Project)
 from django.contrib import admin
 
 admin.site.register(Project)
@@ -6,7 +6,12 @@ admin.site.register(Project)
 
 class AudiobookAdmin(admin.ModelAdmin):
     list_display = ["title", "slug", "index", "part_name", "duration", "license", "youtube_volume"]
 
 class AudiobookAdmin(admin.ModelAdmin):
     list_display = ["title", "slug", "index", "part_name", "duration", "license", "youtube_volume"]
-    list_filter = ["license"]
+    list_filter = [
+        "license",
+        "project",
+        ("mp3_published", admin.EmptyFieldListFilter),
+        ("youtube_published", admin.EmptyFieldListFilter),
+    ]
     search_fields = ["title", "slug", "part_name", "youtube_volume"]
     list_editable = ["youtube_volume"]
     readonly_fields = ['duration']
     search_fields = ["title", "slug", "part_name", "youtube_volume"]
     list_editable = ["youtube_volume"]
     readonly_fields = ['duration']
@@ -14,3 +19,4 @@ class AudiobookAdmin(admin.ModelAdmin):
 
 admin.site.register(Audiobook, AudiobookAdmin)
 admin.site.register(License)
 
 admin.site.register(Audiobook, AudiobookAdmin)
 admin.site.register(License)
+admin.site.register(Config)
index 3b68c28..eca8f1a 100644 (file)
@@ -15,7 +15,9 @@ from archive.utils import ExistingFile, sha1_file
 class AudiobookForm(forms.ModelForm):
     class Meta:
         model = Audiobook
 class AudiobookForm(forms.ModelForm):
     class Meta:
         model = Audiobook
-        exclude = []
+        exclude = [
+            'youtube_id', 'youtube_queued'
+        ]
 
     def save(self, commit=True, path=None):
         """ Performs normal save, with given file as an source audiobook.
 
     def save(self, commit=True, path=None):
         """ Performs normal save, with given file as an source audiobook.
index 666b791..dca91ae 100644 (file)
Binary files a/src/archive/locale/pl/LC_MESSAGES/django.mo and b/src/archive/locale/pl/LC_MESSAGES/django.mo differ
index 6fb331d..526f50d 100644 (file)
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-06-06 00:25+0200\n"
-"PO-Revision-Date: 2020-06-06 00:30+0200\n"
+"POT-Creation-Date: 2022-10-25 13:56+0200\n"
+"PO-Revision-Date: 2022-10-25 13:57+0200\n"
 "Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
 "Language-Team: \n"
 "Language: pl\n"
 "Last-Translator: Radek Czajka <radoslaw.czajka@nowoczesnapolska.org.pl>\n"
 "Language-Team: \n"
 "Language: pl\n"
@@ -17,89 +17,97 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 2.2.4\n"
+"X-Generator: Poedit 3.0.1\n"
 
 
-#: constants.py:18
-msgid "Waiting"
-msgstr "Czeka"
-
-#: constants.py:19
+#: archive/constants.py:18
 msgid "Queued"
 msgstr "W kolejce"
 
 msgid "Queued"
 msgstr "W kolejce"
 
-#: constants.py:20
+#: archive/constants.py:19
+msgid "Waiting"
+msgstr "Czeka"
+
+#: archive/constants.py:20
 msgid "Encoding"
 msgstr "Konwersja"
 
 msgid "Encoding"
 msgstr "Konwersja"
 
-#: constants.py:21
+#: archive/constants.py:21
 msgid "Tagging"
 msgstr "Opisywanie"
 
 msgid "Tagging"
 msgstr "Opisywanie"
 
-#: constants.py:22
+#: archive/constants.py:22
 msgid "Converting audio"
 msgstr "Konwersja audio"
 
 msgid "Converting audio"
 msgstr "Konwersja audio"
 
-#: constants.py:23
+#: archive/constants.py:23
 msgid "Converting video"
 msgstr "Konwersja wideo"
 
 msgid "Converting video"
 msgstr "Konwersja wideo"
 
-#: constants.py:24
+#: archive/constants.py:24
 msgid "Assembling audio"
 msgstr "Kompletowanie audio"
 
 msgid "Assembling audio"
 msgstr "Kompletowanie audio"
 
-#: constants.py:25
+#: archive/constants.py:25
 msgid "Assembling video"
 msgstr "Kompletowanie wideo"
 
 msgid "Assembling video"
 msgstr "Kompletowanie wideo"
 
-#: constants.py:26
+#: archive/constants.py:26
 msgid "Joining audio and video"
 msgstr "Łączenie audio i wideo"
 
 msgid "Joining audio and video"
 msgstr "Łączenie audio i wideo"
 
-#: constants.py:27
+#: archive/constants.py:27
 msgid "Sending"
 msgstr "Wysyłanie"
 
 msgid "Sending"
 msgstr "Wysyłanie"
 
-#: constants.py:28
+#: archive/constants.py:28
 msgid "Setting thumbnail"
 msgstr "Wysyłanie miniatury"
 
 msgid "Setting thumbnail"
 msgstr "Wysyłanie miniatury"
 
-#: models.py:31 models.py:82
+#: archive/models.py:44 archive/models.py:122
 msgid "project"
 msgstr "projekt"
 
 msgid "project"
 msgstr "projekt"
 
-#: models.py:32
+#: archive/models.py:45
 msgid "projects"
 msgstr "projekty"
 
 msgid "projects"
 msgstr "projekty"
 
-#: models.py:63
+#: archive/models.py:76
+msgid "Configuration"
+msgstr "Konfiguracja"
+
+#: archive/models.py:77
+msgid "Configurations"
+msgstr "Konfiguracje"
+
+#: archive/models.py:102
 msgid "source file"
 msgstr "plik źródłowy"
 
 msgid "source file"
 msgstr "plik źródłowy"
 
-#: models.py:66
+#: archive/models.py:106
 msgid "title"
 msgstr "tytuł"
 
 msgid "title"
 msgstr "tytuł"
 
-#: models.py:67
+#: archive/models.py:107
 msgid "part name"
 msgstr "nazwa części"
 
 msgid "part name"
 msgstr "nazwa części"
 
-#: models.py:67
+#: archive/models.py:107
 msgid "eg. chapter in a novel"
 msgstr "np. rozdział w powieści"
 
 msgid "eg. chapter in a novel"
 msgstr "np. rozdział w powieści"
 
-#: models.py:69
+#: archive/models.py:109
 msgid "index"
 msgstr "numer"
 
 msgid "index"
 msgstr "numer"
 
-#: models.py:69
+#: archive/models.py:109
 msgid "Ordering of parts of a book."
 msgstr "Kolejność części w książce"
 
 msgid "Ordering of parts of a book."
 msgstr "Kolejność części w książce"
 
-#: models.py:71
+#: archive/models.py:111
 msgid "Volume name for YouTube"
 msgstr "Nazwa woluminu na YouTube"
 
 msgid "Volume name for YouTube"
 msgstr "Nazwa woluminu na YouTube"
 
-#: models.py:75
+#: archive/models.py:115
 msgid ""
 "If set, audiobooks with the save value will be published as single YouTube "
 "video."
 msgid ""
 "If set, audiobooks with the save value will be published as single YouTube "
 "video."
@@ -107,241 +115,247 @@ msgstr ""
 "Jeśli ustawione, audiobooki z tą samą wartością będą opublikowane jako jeden "
 "film na YouTube."
 
 "Jeśli ustawione, audiobooki z tą samą wartością będą opublikowane jako jeden "
 "film na YouTube."
 
-#: models.py:78
+#: archive/models.py:118
 msgid "artist"
 msgstr "lektor"
 
 msgid "artist"
 msgstr "lektor"
 
-#: models.py:79
+#: archive/models.py:119
 msgid "conductor"
 msgstr "reżyser"
 
 msgid "conductor"
 msgstr "reżyser"
 
-#: models.py:80
+#: archive/models.py:120
 msgid "encoded by"
 msgstr "przyg. techn."
 
 msgid "encoded by"
 msgstr "przyg. techn."
 
-#: models.py:81
+#: archive/models.py:121
 msgid "date"
 msgstr "data"
 
 msgid "date"
 msgstr "data"
 
-#: models.py:83
+#: archive/models.py:123
 msgid "WL catalogue slug of the book."
 msgstr "Slug książki z katalogu WL."
 
 msgid "WL catalogue slug of the book."
 msgstr "Slug książki z katalogu WL."
 
-#: models.py:84
+#: archive/models.py:124
 msgid "translator"
 msgstr "tłumacz"
 
 msgid "translator"
 msgstr "tłumacz"
 
-#: models.py:86
+#: archive/models.py:126
 msgid "license"
 msgstr "licencja"
 
 msgid "license"
 msgstr "licencja"
 
-#: models.py:112
+#: archive/models.py:127
+msgid "secondary license"
+msgstr "druga licencja"
+
+#: archive/models.py:144
 msgid "audiobook"
 msgstr "audiobook"
 
 msgid "audiobook"
 msgstr "audiobook"
 
-#: models.py:113
+#: archive/models.py:145
 msgid "audiobooks"
 msgstr "audiobooki"
 
 msgid "audiobooks"
 msgstr "audiobooki"
 
-#: templates/archive/audiobook_list.html:10 templates/archive/base.html:6
+#: archive/templates/archive/audiobook_list.html:11
+#: archive/templates/archive/base.html:6
 msgid "Audiobooks"
 msgstr "Audiobooki"
 
 msgid "Audiobooks"
 msgstr "Audiobooki"
 
-#: templates/archive/audiobook_list.html:28 templates/archive/book.html:19
+#: archive/templates/archive/audiobook_list.html:37
+#: archive/templates/archive/book.html:19
 msgid "Title"
 msgstr "tytuł"
 
 msgid "Title"
 msgstr "tytuł"
 
-#: templates/archive/audiobook_list.html:29
+#: archive/templates/archive/audiobook_list.html:38
 msgid "YouTube volume"
 msgstr "wolumin YouTube"
 
 msgid "YouTube volume"
 msgstr "wolumin YouTube"
 
-#: templates/archive/base.html:7 templates/archive/file_managed.html:19
+#: archive/templates/archive/base.html:7
 msgid "Publishing"
 msgstr "Publikacja"
 
 msgid "Publishing"
 msgstr "Publikacja"
 
-#: templates/archive/base.html:8
+#: archive/templates/archive/base.html:8
 msgid "New"
 msgstr "Nowe"
 
 msgid "New"
 msgstr "Nowe"
 
-#: templates/archive/base.html:9
+#: archive/templates/archive/base.html:9
 msgid "Archive"
 msgstr "Archiwum"
 
 msgid "Archive"
 msgstr "Archiwum"
 
-#: templates/archive/base.html:14
+#: archive/templates/archive/base.html:14
 msgid "Projects"
 msgstr "Projekty"
 
 msgid "Projects"
 msgstr "Projekty"
 
-#: templates/archive/base.html:17
+#: archive/templates/archive/base.html:17
 msgid "Logout"
 msgstr "Wyloguj"
 
 msgid "Logout"
 msgstr "Wyloguj"
 
-#: templates/archive/base.html:19 templates/registration/login.html:9
+#: archive/templates/archive/base.html:19
+#: archive/templates/registration/login.html:9
 msgid "Login"
 msgstr "Zaloguj"
 
 msgid "Login"
 msgstr "Zaloguj"
 
-#: templates/archive/base.html:22
+#: archive/templates/archive/base.html:22
 msgid "Administration"
 msgstr "Administracja"
 
 msgid "Administration"
 msgstr "Administracja"
 
-#: templates/archive/book.html:18
+#: archive/templates/archive/book.html:18
 msgid "Index"
 msgstr "numer"
 
 msgid "Index"
 msgstr "numer"
 
-#: templates/archive/file_managed.html:23
+#: archive/templates/archive/file_managed.html:29
+#: archive/templates/archive/file_new.html:29
+msgid "Commit"
+msgstr "Zatwierdź"
+
+#: archive/templates/archive/file_managed.html:57
 msgid "Publishing pending"
 msgstr "Czeka na publikację"
 
 msgid "Publishing pending"
 msgstr "Czeka na publikację"
 
-#: templates/archive/file_managed.html:26
+#: archive/templates/archive/file_managed.html:60
 msgid "Cancel publishing"
 msgstr "Anuluj publikację"
 
 msgid "Cancel publishing"
 msgstr "Anuluj publikację"
 
-#: templates/archive/file_managed.html:65
-msgid "Publish"
-msgstr "Opublikuj"
-
-#: templates/archive/file_managed.html:74
-msgid "Convert without publishing"
-msgstr "Konwertuj bez publikacji"
-
-#: templates/archive/file_managed.html:82
-msgid "Preview YouTube metadata"
-msgstr "Podgląd metadanych dla YouTube"
-
-#: templates/archive/file_managed.html:87
-msgid "Publish on YouTube"
-msgstr "Opublikuj na YouTube"
-
-#: templates/archive/file_managed.html:94
-msgid "Update YouTube metadata"
-msgstr "Aktualizuj metadane na YouTube"
-
-#: templates/archive/file_managed.html:111
-msgid "MP3 file"
-msgstr "Plik MP3"
-
-#: templates/archive/file_managed.html:115
+#: archive/templates/archive/file_managed.html:81
 msgid "Download MP3 file."
 msgstr "Pobierz plik MP3."
 
 msgid "Download MP3 file."
 msgstr "Pobierz plik MP3."
 
-#: templates/archive/file_managed.html:117
-#: templates/archive/file_managed.html:140
-#: templates/archive/file_managed.html:167
+#: archive/templates/archive/file_managed.html:83
+#: archive/templates/archive/file_managed.html:94
+#: archive/templates/archive/file_managed.html:192
 msgid "Published:"
 msgstr "Opublikowano:"
 
 msgid "Published:"
 msgstr "Opublikowano:"
 
-#: templates/archive/file_managed.html:122
-#: templates/archive/file_managed.html:145
-#: templates/archive/file_managed.html:172
+#: archive/templates/archive/file_managed.html:85
+#: archive/templates/archive/file_managed.html:96
 msgid "Not published yet."
 msgstr "Nie opublikowane."
 
 msgid "Not published yet."
 msgstr "Nie opublikowane."
 
-#: templates/archive/file_managed.html:125
+#: archive/templates/archive/file_managed.html:88
 msgid "MP3 file hasn't been generated yet."
 msgstr "Plik MP3 nie został jeszcze wygenerowany."
 
 msgid "MP3 file hasn't been generated yet."
 msgstr "Plik MP3 nie został jeszcze wygenerowany."
 
-#: templates/archive/file_managed.html:134
-msgid "Ogg Vorbis file"
-msgstr "Plik Ogg Vorbis"
-
-#: templates/archive/file_managed.html:138
+#: archive/templates/archive/file_managed.html:92
 msgid "Download Ogg Vorbis file."
 msgstr "Pobierz plik Ogg Vorbis."
 
 msgid "Download Ogg Vorbis file."
 msgstr "Pobierz plik Ogg Vorbis."
 
-#: templates/archive/file_managed.html:148
+#: archive/templates/archive/file_managed.html:99
 msgid "Ogg Vorbis file hasn't been generated yet."
 msgstr "Plik Ogg Vorbis nie został jeszcze wygenerowany."
 
 msgid "Ogg Vorbis file hasn't been generated yet."
 msgstr "Plik Ogg Vorbis nie został jeszcze wygenerowany."
 
-#: templates/archive/file_managed.html:157
-msgid "YouTube"
-msgstr "YouTube"
+#: archive/templates/archive/file_managed.html:105
+msgid "Publish"
+msgstr "Opublikuj"
+
+#: archive/templates/archive/file_managed.html:114
+msgid "Convert without publishing"
+msgstr "Konwertuj bez publikacji"
+
+#: archive/templates/archive/file_managed.html:160
+msgid "Preview YouTube metadata"
+msgstr "Podgląd metadanych dla YouTube"
+
+#: archive/templates/archive/file_managed.html:169
+msgid "Update YouTube thumbnail"
+msgstr "Aktualizuj metadane na YouTube"
+
+#: archive/templates/archive/file_managed.html:175
+msgid "Update YouTube metadata"
+msgstr "Aktualizuj metadane na YouTube"
 
 
-#: templates/archive/file_managed.html:163
+#: archive/templates/archive/file_managed.html:180
+msgid "Publish on YouTube"
+msgstr "Opublikuj na YouTube"
+
+#: archive/templates/archive/file_managed.html:187
 msgid "See on YouTube"
 msgstr "Zobacz na YouTube"
 
 msgid "See on YouTube"
 msgstr "Zobacz na YouTube"
 
-#: templates/archive/file_managed.html:175
-msgid "YouTube file hasn't been generated yet."
-msgstr "Plik dla YouTube nie został jeszcze wygenerowany."
-
-#: templates/archive/file_managed.html:194
+#: archive/templates/archive/file_managed.html:226
 msgid "Are you sure you want to move this audiobook to archive?"
 msgstr "Czy na pewno chcesz przenieść ten plik to archiwum?"
 
 msgid "Are you sure you want to move this audiobook to archive?"
 msgstr "Czy na pewno chcesz przenieść ten plik to archiwum?"
 
-#: templates/archive/file_managed.html:196
+#: archive/templates/archive/file_managed.html:234
 msgid "Remove to archive"
 msgstr "Usuń do archiwum"
 
 msgid "Remove to archive"
 msgstr "Usuń do archiwum"
 
-#: templates/archive/file_managed.html:206
-msgid "Update tags"
-msgstr "Uaktualnij tagi"
-
-#: templates/archive/file_managed.html:213 templates/archive/file_new.html:29
-msgid "Commit"
-msgstr "Zatwierdź"
-
-#: templates/archive/file_new.html:17
+#: archive/templates/archive/file_new.html:17
 msgid "Move to archive"
 msgstr "Przenieś do archiwum"
 
 msgid "Move to archive"
 msgstr "Przenieś do archiwum"
 
-#: templates/archive/file_unmanaged.html:11
+#: archive/templates/archive/file_unmanaged.html:11
 msgid "File with same name already exists!"
 msgstr "Plik o tej nazwie już istnieje!"
 
 msgid "File with same name already exists!"
 msgstr "Plik o tej nazwie już istnieje!"
 
-#: templates/archive/file_unmanaged.html:27
+#: archive/templates/archive/file_unmanaged.html:27
 msgid "Move to new files"
 msgstr "Przenieś do nowych plików"
 
 msgid "Move to new files"
 msgstr "Przenieś do nowych plików"
 
-#: templates/archive/list_new.html:10
+#: archive/templates/archive/list_new.html:10
 msgid "New audiobooks"
 msgstr "Nowe audiobooki"
 
 msgid "New audiobooks"
 msgstr "Nowe audiobooki"
 
-#: templates/archive/list_new.html:15
+#: archive/templates/archive/list_new.html:15
 msgid "Put source audiobooks in:"
 msgstr "Umieść nowe audiobooki w:"
 
 msgid "Put source audiobooks in:"
 msgstr "Umieść nowe audiobooki w:"
 
-#: templates/archive/list_publishing.html:9
+#: archive/templates/archive/list_publishing.html:9
 msgid "Audiobooks being published"
 msgstr "Aktualnie publikowane audiobooki"
 
 msgid "Audiobooks being published"
 msgstr "Aktualnie publikowane audiobooki"
 
-#: templates/archive/list_unmanaged.html:9
+#: archive/templates/archive/list_unmanaged.html:9
 msgid "Unmanaged archive"
 msgstr "Audiobooki archiwalne"
 
 msgid "Unmanaged archive"
 msgstr "Audiobooki archiwalne"
 
-#: templates/archive/status.html:7
+#: archive/templates/archive/status.html:7
 msgid "Published at"
 msgstr "Opublikowane"
 
 msgid "Published at"
 msgstr "Opublikowane"
 
-#: templates/archive/status.html:8
+#: archive/templates/archive/status.html:8
 msgid "OK"
 msgstr "OK"
 
 msgid "OK"
 msgstr "OK"
 
-#: templates/base.html:12
+#: archive/templates/base.html:12
 msgid "Audiobook repository"
 msgstr "Repozytorium audiobooków"
 
 msgid "Audiobook repository"
 msgstr "Repozytorium audiobooków"
 
-#: templates/pagination/pagination.html:3
+#: archive/templates/pagination/pagination.html:3
 msgid "Pagination"
 msgstr "Paginacja"
 
 msgid "Pagination"
 msgstr "Paginacja"
 
-#: templates/pagination/pagination.html:8
-#: templates/pagination/pagination.html:14
+#: archive/templates/pagination/pagination.html:8
+#: archive/templates/pagination/pagination.html:14
 msgid "previous"
 msgstr "poprzednia"
 
 msgid "previous"
 msgstr "poprzednia"
 
-#: templates/pagination/pagination.html:40
-#: templates/pagination/pagination.html:46
+#: archive/templates/pagination/pagination.html:40
+#: archive/templates/pagination/pagination.html:46
 msgid "next"
 msgstr "następna"
 
 msgid "next"
 msgstr "następna"
 
-#: views.py:264
+#: archive/views.py:258
 msgid "There is more than one part, but index is not set."
 msgstr "Utwór ma więcej niż jedną część, ale indeks części nie jest ustawiony."
 
 msgid "There is more than one part, but index is not set."
 msgstr "Utwór ma więcej niż jedną część, ale indeks części nie jest ustawiony."
 
-#: views.py:266
+#: archive/views.py:260
 #, python-format
 msgid "Part indexes are not 1..%(parts_count)d."
 msgstr "Indeksy części utworu nie tworzą zakresu 1..%(parts_count)d."
 
 #, python-format
 msgid "Part indexes are not 1..%(parts_count)d."
 msgstr "Indeksy części utworu nie tworzą zakresu 1..%(parts_count)d."
 
+#~ msgid "MP3 file"
+#~ msgstr "Plik MP3"
+
+#~ msgid "Ogg Vorbis file"
+#~ msgstr "Plik Ogg Vorbis"
+
+#~ msgid "YouTube"
+#~ msgstr "YouTube"
+
+#~ msgid "YouTube file hasn't been generated yet."
+#~ msgstr "Plik dla YouTube nie został jeszcze wygenerowany."
+
+#~ msgid "Update tags"
+#~ msgstr "Uaktualnij tagi"
+
 #~ msgid "parts count"
 #~ msgstr "liczba części"
 
 #~ msgid "parts count"
 #~ msgstr "liczba części"
 
diff --git a/src/archive/migrations/0023_project_info_flac.py b/src/archive/migrations/0023_project_info_flac.py
new file mode 100644 (file)
index 0000000..99897c4
--- /dev/null
@@ -0,0 +1,18 @@
+# Generated by Django 3.1.2 on 2021-06-25 16:19
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0022_auto_20210316_1406'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='project',
+            name='info_flac',
+            field=models.FileField(blank=True, upload_to='archive/info_flac'),
+        ),
+    ]
diff --git a/src/archive/migrations/0024_auto_20211222_1604.py b/src/archive/migrations/0024_auto_20211222_1604.py
new file mode 100644 (file)
index 0000000..f4c724c
--- /dev/null
@@ -0,0 +1,34 @@
+# Generated by Django 3.1.14 on 2021-12-22 16:04
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0023_project_info_flac'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Config',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=255)),
+                ('intro_flac', models.FileField(blank=True, upload_to='config/intro_flac')),
+                ('intro_min_seconds', models.IntegerField()),
+                ('outro_flac', models.FileField(blank=True, upload_to='config/outro_flac')),
+                ('outro_min_seconds', models.IntegerField()),
+            ],
+            options={
+                'verbose_name': 'Configuration',
+                'verbose_name_plural': 'Configurations',
+            },
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='config',
+            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='archive.config'),
+        ),
+    ]
diff --git a/src/archive/migrations/0025_create_config.py b/src/archive/migrations/0025_create_config.py
new file mode 100644 (file)
index 0000000..f297676
--- /dev/null
@@ -0,0 +1,25 @@
+# Generated by Django 3.1.14 on 2021-12-22 16:00
+
+from django.db import migrations
+
+
+def create_config(apps, schema_editor):
+    Config = apps.get_model('archive', 'Config')
+    Project = apps.get_model('archive', 'Project')
+    c = Config.objects.create(name='Wolne Lektury', intro_min_seconds=0, outro_min_seconds=0)
+    Project.objects.all().update(config=c)
+    
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0024_auto_20211222_1604'),
+    ]
+
+    operations = [
+        migrations.RunPython(
+            create_config,
+            migrations.RunPython.noop
+        )
+    ]
diff --git a/src/archive/migrations/0026_auto_20211222_1605.py b/src/archive/migrations/0026_auto_20211222_1605.py
new file mode 100644 (file)
index 0000000..5b09693
--- /dev/null
@@ -0,0 +1,19 @@
+# Generated by Django 3.1.14 on 2021-12-22 16:05
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0025_create_config'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='project',
+            name='config',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='archive.config'),
+        ),
+    ]
diff --git a/src/archive/migrations/0027_auto_20221025_1336.py b/src/archive/migrations/0027_auto_20221025_1336.py
new file mode 100644 (file)
index 0000000..6e6e8a8
--- /dev/null
@@ -0,0 +1,55 @@
+# Generated by Django 3.1.14 on 2022-10-25 13:36
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0026_auto_20211222_1605'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='mp3_published_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='mp3_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='mp3_task',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='ogg_published_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='ogg_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='ogg_task',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='youtube_published_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='youtube_tags',
+        ),
+        migrations.RemoveField(
+            model_name='audiobook',
+            name='youtube_task',
+        ),
+        migrations.AddField(
+            model_name='audiobook',
+            name='license_secondary',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='secondary', to='archive.license', verbose_name='license'),
+        ),
+    ]
diff --git a/src/archive/migrations/0028_auto_20221025_1341.py b/src/archive/migrations/0028_auto_20221025_1341.py
new file mode 100644 (file)
index 0000000..bff3f8c
--- /dev/null
@@ -0,0 +1,29 @@
+# Generated by Django 3.1.14 on 2022-10-25 13:41
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0027_auto_20221025_1336'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='project',
+            name='can_sell',
+            field=models.BooleanField(default=True, verbose_name='Do sprzedaży'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='private_notes',
+            field=models.TextField(blank=True, verbose_name='Prywatne notatki'),
+        ),
+        migrations.AddField(
+            model_name='project',
+            name='required_license',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='archive.license', verbose_name='Wymagana licencja'),
+        ),
+    ]
diff --git a/src/archive/migrations/0029_auto_20221025_1357.py b/src/archive/migrations/0029_auto_20221025_1357.py
new file mode 100644 (file)
index 0000000..3aaae8f
--- /dev/null
@@ -0,0 +1,19 @@
+# Generated by Django 3.1.14 on 2022-10-25 13:57
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('archive', '0028_auto_20221025_1341'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='audiobook',
+            name='license_secondary',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='secondary', to='archive.license', verbose_name='secondary license'),
+        ),
+    ]
index 1fc033b..1dbb701 100644 (file)
@@ -1,5 +1,6 @@
 import io
 import json
 import io
 import json
+from os import unlink
 import os.path
 from urllib.parse import urljoin
 
 import os.path
 from urllib.parse import urljoin
 
@@ -14,6 +15,7 @@ import requests
 from archive.constants import status
 from archive.settings import FILES_SAVE_PATH, ADVERT, ORGANIZATION, PROJECT
 from archive.utils import OverwriteStorage, sha1_file
 from archive.constants import status
 from archive.settings import FILES_SAVE_PATH, ADVERT, ORGANIZATION, PROJECT
 from archive.utils import OverwriteStorage, sha1_file
+from youtube.utils import concat_audio, standardize_audio
 
 
 class License(models.Model):
 
 
 class License(models.Model):
@@ -30,8 +32,13 @@ 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")
     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")
+    private_notes = models.TextField(blank=True, verbose_name="Prywatne notatki")
+    config = models.ForeignKey('Config', models.PROTECT)
+    can_sell = models.BooleanField(default=True, verbose_name="Do sprzedaży")
+    required_license = models.ForeignKey('License', models.PROTECT, blank=True, null=True, verbose_name='Wymagana licencja')
     youtube = models.ForeignKey('youtube.YouTube', models.PROTECT)
     icon = models.FileField(upload_to='archive/project', blank=True, null=True)
     youtube = models.ForeignKey('youtube.YouTube', models.PROTECT)
     icon = models.FileField(upload_to='archive/project', blank=True, null=True)
+    info_flac = models.FileField(upload_to='archive/info_flac', blank=True)
 
     class Meta:
         verbose_name = _("project")
 
     class Meta:
         verbose_name = _("project")
@@ -58,6 +65,34 @@ class Project(models.Model):
         )
 
 
         )
 
 
+class Config(models.Model):
+    name = models.CharField(max_length=255)
+    intro_flac = models.FileField(upload_to='config/intro_flac', blank=True)
+    intro_min_seconds = models.IntegerField()
+    outro_flac = models.FileField(upload_to='config/outro_flac', blank=True)
+    outro_min_seconds = models.IntegerField()
+
+    class Meta:
+        verbose_name = _("Configuration")
+        verbose_name_plural = _("Configurations")
+
+    def __str__(self):
+        return self.name
+
+    def prepare_audio(self, audiobook):
+        total_duration = audiobook.total_duration
+        files = []
+        if self.intro_flac and total_duration > self.intro_min_seconds and audiobook.is_first:
+            files.append(standardize_audio(self.intro_flac.path))
+        files.append(standardize_audio(audiobook.source_file.path))
+        if self.outro_flac and total_duration > self.outro_min_seconds and audiobook.is_last:
+            files.append(standardize_audio(self.outro_flac.path))
+        output = concat_audio(files)
+        for d in files:
+            unlink(d)
+        return output
+
+
 def source_upload_to(intance, filename):
     return os.path.join(FILES_SAVE_PATH, filename) # FIXME: what about really long file names?
 
 def source_upload_to(intance, filename):
     return os.path.join(FILES_SAVE_PATH, filename) # FIXME: what about really long file names?
 
@@ -89,26 +124,18 @@ class Audiobook(models.Model):
     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'))
     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'))
+    license_secondary = models.ForeignKey(License, models.PROTECT, null=True, blank=True, verbose_name=_('secondary license'), related_name='secondary')
 
     # publishing process
     mp3_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
 
     # publishing process
     mp3_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
-    mp3_task = models.CharField(max_length=64, null=True, editable=False)
-    mp3_tags = models.TextField(null=True, editable=False)
     mp3_file = models.FileField(null=True, upload_to='archive/final', storage=OverwriteStorage(), editable=False)
     mp3_file = models.FileField(null=True, upload_to='archive/final', storage=OverwriteStorage(), editable=False)
-    mp3_published_tags = models.TextField(null=True, editable=False)
     mp3_published = models.DateTimeField(null=True, editable=False)
 
     ogg_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
     mp3_published = models.DateTimeField(null=True, editable=False)
 
     ogg_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
-    ogg_task = models.CharField(max_length=64, null=True, editable=False)
-    ogg_tags = models.TextField(null=True, editable=False)
     ogg_file = models.FileField(null=True, upload_to='archive/final', storage=OverwriteStorage(), editable=False)
     ogg_file = models.FileField(null=True, upload_to='archive/final', storage=OverwriteStorage(), editable=False)
-    ogg_published_tags = models.TextField(null=True, editable=False)
     ogg_published = models.DateTimeField(null=True, editable=False)
 
     youtube_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
     ogg_published = models.DateTimeField(null=True, editable=False)
 
     youtube_status = models.SmallIntegerField(null=True, editable=False, choices=status.choices)
-    youtube_task = models.CharField(max_length=64, null=True, editable=False)
-    youtube_tags = models.TextField(null=True, editable=False)
-    youtube_published_tags = models.TextField(null=True, editable=False)
     youtube_published = models.DateTimeField(null=True, editable=False)
     youtube_id = models.CharField(max_length=255, blank=True, default='')
     youtube_queued = models.DateTimeField(null=True, blank=True)
     youtube_published = models.DateTimeField(null=True, editable=False)
     youtube_id = models.CharField(max_length=255, blank=True, default='')
     youtube_queued = models.DateTimeField(null=True, blank=True)
@@ -129,6 +156,18 @@ class Audiobook(models.Model):
     def parts_count(self):
         return type(self).objects.filter(slug=self.slug).count()
 
     def parts_count(self):
         return type(self).objects.filter(slug=self.slug).count()
 
+    @property
+    def total_duration(self):
+        return type(self).objects.filter(slug=self.slug).aggregate(s=models.Sum('duration'))['s']
+
+    @property
+    def is_first(self):
+        return not type(self).objects.filter(slug=self.slug, index__lte=self.index).exclude(pk=self.pk).exists()
+
+    @property
+    def is_last(self):
+        return not type(self).objects.filter(slug=self.slug, index__gte=self.index).exclude(pk=self.pk).exists()
+    
     @property
     def youtube_volume_count(self):
         total = 0
     @property
     def youtube_volume_count(self):
         total = 0
@@ -154,7 +193,7 @@ class Audiobook(models.Model):
         return (
             not self.youtube_volume
             or not type(self)
         return (
             not self.youtube_volume
             or not type(self)
-            .objects.filter(youtube_volume=self.youtube_volume, index__lt=self.index)
+            .objects.filter(slug=self.slug, youtube_volume=self.youtube_volume, index__lt=self.index)
             .exists()
         )
 
             .exists()
         )
 
@@ -165,16 +204,16 @@ class Audiobook(models.Model):
         self.youtube_queued = now()
         self.save(update_fields=['youtube_status', 'youtube_queued'])
 
         self.youtube_queued = now()
         self.save(update_fields=['youtube_status', 'youtube_queued'])
 
-    def get_mp3_tags(self): return json.loads(self.mp3_tags) if self.mp3_tags else None
-    def get_ogg_tags(self): return json.loads(self.ogg_tags) if self.ogg_tags else None
-    def get_mp3_published_tags(self): return json.loads(self.mp3_published_tags) if self.mp3_published_tags else None
-    def get_ogg_published_tags_tags(self): return json.loads(self.ogg_published_tags) if self.ogg_published_tags else None
-    def set_mp3_tags(self, tags): self.mp3_tags = json.dumps(tags)
-    def set_ogg_tags(self, tags): self.ogg_tags = json.dumps(tags)
-
     def published(self):
         return self.mp3_published and self.ogg_published
 
     def published(self):
         return self.mp3_published and self.ogg_published
 
+    def publish(self, user, publish=True):
+        from . import tasks
+        self.mp3_status = self.ogg_status = status.WAITING
+        self.save(update_fields=['mp3_status', 'ogg_status'])
+        tasks.Mp3Task.delay(user.id, self.pk, publish=publish).task_id
+        tasks.OggTask.delay(user.id, self.pk, publish=publish).task_id
+
     def get_source_sha1(self):
         assert self.pk or self.source_sha1
         if not self.source_sha1:
     def get_source_sha1(self):
         assert self.pk or self.source_sha1
         if not self.source_sha1:
@@ -220,10 +259,13 @@ class Audiobook(models.Model):
         if self.project.sponsors:
             tags['funded_by'] = self.project.sponsors
 
         if self.project.sponsors:
             tags['funded_by'] = self.project.sponsors
 
-        if self.source_sha1:
-            tags['flac_sha1'] = self.source_sha1
+        tags['flac_sha1'] = self.get_source_sha1()
+
         return tags
 
         return tags
 
+    def prepare_audio(self):
+        return self.project.config.prepare_audio(self)
+    
     @cached_property
     def book(self):
         if self.slug:
     @cached_property
     def book(self):
         if self.slug:
@@ -241,11 +283,9 @@ class Audiobook(models.Model):
         if xml_url is None:
             return None
 
         if xml_url is None:
             return None
 
-        return WLDocument(
-                etree.parse(
-                    io.BytesIO(
-                        requests.get(xml_url).content
-                    )
-                    ,parser = parser
-                )
-            )
+        return WLDocument(url=xml_url)
+
+    @property
+    def cover(self):
+        from librarian.cover import LogoWLCover
+        return LogoWLCover(self.document.meta).output_file.get_bytes()
index 3538a73..d95baac 100644 (file)
@@ -39,10 +39,7 @@ class AudioFormatTask(Task):
         raise NotImplemented
 
     @classmethod
         raise NotImplemented
 
     @classmethod
-    def set_tags(cls, audiobook, file_name):
-        tags = getattr(audiobook, "get_%s_tags" % cls.prefix)()['tags']
-        if not tags.get('flac_sha1'):
-            tags['flac_sha1'] = audiobook.get_source_sha1()
+    def set_tags(cls, tags, file_name):
         audio = File(file_name)
         for k, v in tags.items():
             audio[k] = v
         audio = File(file_name)
         for k, v in tags.items():
             audio[k] = v
@@ -61,10 +58,8 @@ class AudioFormatTask(Task):
             **{field: getattr(audiobook, field)})
 
     @classmethod
             **{field: getattr(audiobook, field)})
 
     @classmethod
-    def published(cls, aid):
+    def published(cls, aid, tags):
         kwargs = {
         kwargs = {
-            "%s_published_tags" % cls.prefix: F("%s_tags" % cls.prefix),
-            "%s_tags" % cls.prefix: None,
             "%s_published" % cls.prefix: datetime.now(),
             '%s_status' % cls.prefix: None,
         }
             "%s_published" % cls.prefix: datetime.now(),
             '%s_status' % cls.prefix: None,
         }
@@ -72,11 +67,10 @@ class AudioFormatTask(Task):
 
     @classmethod
     def put(cls, user, audiobook, path):
 
     @classmethod
     def put(cls, user, audiobook, path):
-        tags = getattr(audiobook, "get_%s_tags" % cls.prefix)()
         data = {
         data = {
-            'book': tags['url'],
+            'book': audiobook.url,
             'type': cls.ext,
             'type': cls.ext,
-            'name': tags['name'],
+            'name': audiobook.title,                ##### IS IT USED?
             'part_name': audiobook.part_name,
             'part_index': audiobook.index,
             'parts_count': audiobook.parts_count,
             'part_name': audiobook.part_name,
             'part_index': audiobook.index,
             'parts_count': audiobook.parts_count,
@@ -108,19 +102,21 @@ class AudioFormatTask(Task):
         out_file.close()
         self.encode(self.get_source_file_paths(audiobook), out_file.name)
         self.set_status(aid, status.TAGGING)
         out_file.close()
         self.encode(self.get_source_file_paths(audiobook), out_file.name)
         self.set_status(aid, status.TAGGING)
-        self.set_tags(audiobook, out_file.name)
+
+        tags = audiobook.new_publish_tags()
+        self.set_tags(tags, out_file.name)
         self.set_status(aid, status.SENDING)
 
         if publish:
             self.put(user, audiobook, out_file.name)
         self.set_status(aid, status.SENDING)
 
         if publish:
             self.put(user, audiobook, out_file.name)
-            self.published(aid)
+            self.published(aid, tags)
         else:
             self.set_status(aid, None)
 
         self.save(audiobook, out_file.name)
 
     def get_source_file_paths(self, audiobook):
         else:
             self.set_status(aid, None)
 
         self.save(audiobook, out_file.name)
 
     def get_source_file_paths(self, audiobook):
-        return [audiobook.source_file.path]
+        return [audiobook.prepare_audio()]
 
     def on_failure(self, exc, task_id, args, kwargs, einfo):
         aid = (args[0], kwargs.get('aid'))[0]
 
     def on_failure(self, exc, task_id, args, kwargs, einfo):
         aid = (args[0], kwargs.get('aid'))[0]
@@ -175,12 +171,9 @@ class Mp3Task(AudioFormatTask):
             ])
 
     @classmethod
             ])
 
     @classmethod
-    def set_tags(cls, audiobook, file_name):
-        mp3_tags = audiobook.get_mp3_tags()['tags']
-        if not mp3_tags.get('flac_sha1'):
-            mp3_tags['flac_sha1'] = audiobook.get_source_sha1()
+    def set_tags(cls, tags, file_name):
         audio = id3.ID3(file_name)
         audio = id3.ID3(file_name)
-        for k, v in mp3_tags.items():
+        for k, v in tags.items():
             factory_tuple = cls.TAG_MAP[k]
             factory, tagtype = factory_tuple[:2]
             audio.add(factory(tagtype, v, *factory_tuple[2:]))
             factory_tuple = cls.TAG_MAP[k]
             factory, tagtype = factory_tuple[:2]
             audio.add(factory(tagtype, v, *factory_tuple[2:]))
index 6f7bf1c..9cb1c80 100644 (file)
@@ -19,7 +19,7 @@
             <th>{% trans "Title" %}</th>
             <th>MP3</th>
             <th>Ogg</th>
             <th>{% trans "Title" %}</th>
             <th>MP3</th>
             <th>Ogg</th>
-            <th colspan="3">YouTube</th>
+            <th colspan="5">YouTube</th>
           </tr>
         </thead>
         <tbody>
           </tr>
         </thead>
         <tbody>
@@ -35,7 +35,7 @@
                       <em class="text-warning" title="ddd">
                         ({{ audiobook }})
                       </em>
                       <em class="text-warning" title="ddd">
                         ({{ audiobook }})
                       </em>
-                      {% endif %}
+                    {% endif %}
                   </a>
                 </td>
                 <td>{% status audiobook "mp3" %}</td>
                   </a>
                 </td>
                 <td>{% status audiobook "mp3" %}</td>
                     {{ audiobook.youtube_volume_index }}/{{ volumes }}
                   </td>
                   <td>
                     {{ audiobook.youtube_volume_index }}/{{ volumes }}
                   </td>
                   <td>
-                    {{ audiobook.youtube_volume }}
+                    <form method="POST" action="{% url 'book_youtube_volume' audiobook.id %}">
+                      {% csrf_token %}
+                      <input name='volume' value="{{ audiobook.youtube_volume }}" class="form-control">
+                    </form>
+                  </td>
+                  <td>
+                    {% if audiobook.youtube_volume %}
+                      {{ audiobook.total|duration }}
+                    {% else %}
+                      <small class="text-secondary">{{ audiobook.subtotal|duration }}</small>
+                    {% endif %}
+                  </td>
+                  <td>
+                    {{ audiobook.duration|duration }}
                   </td>
                   <td>
                     {% status audiobook "youtube" %}
                   </td>
                   <td>
                     {% status audiobook "youtube" %}
                   </td>
                   <td>
                     <span class="text-secondary">
                   </td>
                   <td>
                     <span class="text-secondary">
-                      {{ audiobook.youtube_volume }}
+                      <form method="POST" action="{% url 'book_youtube_volume' audiobook.id %}">
+                        {% csrf_token %}
+                        <input name='volume' value="{{ audiobook.youtube_volume }}" class="form-control">
+                      </form>
                     </span>
                   </td>
                     </span>
                   </td>
+                  <td>
+                    <small class="text-secondary">{{ audiobook.subtotal|duration }}</small>
+                  </td>
+                  <td class="text-secondary">
+                    {{ audiobook.duration|duration }}
+                  </td>
                   <td>
                   </td>
                 {% endifchanged %}
                   <td>
                   </td>
                 {% endifchanged %}
index 60d6b6c..c4e2a57 100644 (file)
@@ -17,7 +17,7 @@
 
 
 <div class="row mt-4">
 
 
 <div class="row mt-4">
-  <div class="col-xl-7">
+  <div class="col-xl-12">
     <div class="card mt-4">
       <div class="card-header">
         <h2>{% if audiobook.slug %}<a href="{% url 'book' audiobook.slug %}" %}">{% endif %}{{ audiobook.title }}{% if audiobook.slug %}</a>{% endif %}</h2>
     <div class="card mt-4">
       <div class="card-header">
         <h2>{% if audiobook.slug %}<a href="{% url 'book' audiobook.slug %}" %}">{% endif %}{{ audiobook.title }}{% if audiobook.slug %}</a>{% endif %}</h2>
       <div class="card-body">
         <form method='post' action='.'>
           {% csrf_token %}
       <div class="card-body">
         <form method='post' action='.'>
           {% csrf_token %}
-         {% bootstrap_form form %}
+         {% bootstrap_form form layout="horizontal" %}
           <input class="btn btn-primary" type="submit" value='{% trans "Commit" %}' />
         </form>
           <input class="btn btn-primary" type="submit" value='{% trans "Commit" %}' />
         </form>
-
       </div>
     </div>
   </div>
 
       </div>
     </div>
   </div>
 
-  <div class="col-xl-5">
-    {% if audiobook.mp3_status or audiobook.ogg_status or audiobook.youtube_status %}
-      <h2>{% trans "Publishing pending" %}</h2>
-      <form method="post" action="{% url 'cancel_publishing' audiobook.id %}">
-        {% csrf_token %}
-        <input class='btn btn-danger' type="submit" value="{% trans "Cancel publishing" %}" />
-      </form>
-    {% endif %}
+
+</div>
+
+
+
+
+
+
+
+
+<div class="row">
+
+
+  <div class="col-xl-8">
 
 
     <div class="card mt-4">
 
 
     <div class="card mt-4">
         <h3>MP3, Ogg</h3>
       </div>
       <div class="card-body">
         <h3>MP3, Ogg</h3>
       </div>
       <div class="card-body">
+        {% if audiobook.mp3_status or audiobook.ogg_status or audiobook.youtube_status %}
+          <h2>{% trans "Publishing pending" %}</h2>
+          <form method="post" action="{% url 'cancel_publishing' audiobook.id %}">
+            {% csrf_token %}
+            <input class='btn btn-danger' type="submit" value="{% trans "Cancel publishing" %}" />
+          </form>
+        {% endif %}
+
+
         {% if audiobook.mp3_status %}
           <hr/>
           <h2>MP3</h2>
 
         {% if audiobook.mp3_status %}
           <hr/>
           <h2>MP3</h2>
 
-          {% tags_table audiobook.get_mp3_tags.tags %}
-
           <p>Status: <b>{{ audiobook.get_mp3_status_display }}</b></p>
         {% endif %}
 
           <p>Status: <b>{{ audiobook.get_mp3_status_display }}</b></p>
         {% endif %}
 
@@ -61,8 +73,6 @@
           <hr/>
           <h2>Ogg Vorbis</h2>
 
           <hr/>
           <h2>Ogg Vorbis</h2>
 
-          {% tags_table audiobook.get_ogg_tags.tags %}
-
           <p>Status: <b>{{ audiobook.get_ogg_status_display }}</b></p>
         {% endif %}
 
           <p>Status: <b>{{ audiobook.get_ogg_status_display }}</b></p>
         {% endif %}
 
@@ -71,9 +81,6 @@
           <p><a href="{% url 'download' audiobook.id 'mp3' %}">{% trans "Download MP3 file." %}</a></p>
           {% if audiobook.mp3_published %}
             <p>{% trans "Published:" %} {{ audiobook.mp3_published }}</a></p>
           <p><a href="{% url 'download' audiobook.id 'mp3' %}">{% trans "Download MP3 file." %}</a></p>
           {% if audiobook.mp3_published %}
             <p>{% trans "Published:" %} {{ audiobook.mp3_published }}</a></p>
-            {% if audiobook.get_mp3_published_tags.tags %}
-              {% tags_table audiobook.get_mp3_published_tags.tags %}
-            {% endif %}
           {% else %}
             <p>{% trans "Not published yet." %}</p>
           {% endif %}
           {% else %}
             <p>{% trans "Not published yet." %}</p>
           {% endif %}
@@ -85,9 +92,6 @@
           <p><a href="{% url 'download' audiobook.id 'ogg' %}">{% trans "Download Ogg Vorbis file." %}</a></p>
           {% if audiobook.ogg_published %}
             <p>{% trans "Published:" %} {{ audiobook.ogg_published }}</a></p>
           <p><a href="{% url 'download' audiobook.id 'ogg' %}">{% trans "Download Ogg Vorbis file." %}</a></p>
           {% if audiobook.ogg_published %}
             <p>{% trans "Published:" %} {{ audiobook.ogg_published }}</a></p>
-            {% if audiobook.get_ogg_published_tags.tags %}
-              {% tags_table audiobook.get_ogg_published_tags.tags %}
-            {% endif %}
           {% else %}
             <p>{% trans "Not published yet." %}</p>
           {% endif %}
           {% else %}
             <p>{% trans "Not published yet." %}</p>
           {% endif %}
       </div>
     </div>
 
       </div>
     </div>
 
+
+
     <div class="card mt-4">
       <div class="card-header">
     <div class="card mt-4">
       <div class="card-header">
-        <h3>YouTube</h3>
+        <h3>Metadane dla MP3, Ogg</h3>
       </div>
       <div class="card-body">
       </div>
       <div class="card-body">
-        {% if audiobook.youtube_status %}
-          <hr/>
-          <h2>YouTube</h2>
+        <table class='table'>
+          tagi, które zostałyby zapisane do pliku, gdyby go teraz opublikować
+          {% tags_table audiobook.new_publish_tags 0 %}
+        </table>
+      </div>
+    </div>
 
 
-          <p>Status: <b>{{ audiobook.get_youtube_status_display }}</b></p>
-        {% endif %}
+  </div>
 
 
-        {% if audiobook.youtube_id %}
-          {% if audiobook.youtube_id %}
-            <p>
-              <a href="https://youtu.be/{{ audiobook.youtube_id }}" target="_blank" title="{% trans "See on YouTube" %}">
-                <img src="https://i.ytimg.com/vi/{{ audiobook.youtube_id }}/hq720.jpg" style="width: 100%">
 
 
-              </a>
-            </p>
-          {% endif %}
-          {% if audiobook.youtube_published %}
-            <p>{% trans "Published:" %} {{ audiobook.youtube_published }}</a></p>
-            {% if audiobook.get_youtube_published_tags.tags %}
-              {% tags_table audiobook.get_youtube_published_tags.tags %}
-            {% endif %}
-          {% else %}
-            <p>{% trans "Not published yet." %}</p>
+  <div class="col-xl-4">
+    <div class="card mt-4">
+      <div class="card-header">
+        <h3>
+          YouTube
+          {% if audiobook.youtube_status %}
+            <span class="badge badge-pill badge-primary">{{ audiobook.get_youtube_status_display }}</span>
           {% endif %}
           {% endif %}
-        {% else %}
-          <p>{% trans "YouTube file hasn't been generated yet." %}</p>
+        </h3>
+      </div>
+      <div class="card-body">
+        <img src="{% url 'youtube_thumbnail' audiobook.id %}" style="width:100%">
+        <strong>{{ youtube_title }}</strong><br><br>
+        {{ youtube_description|linebreaksbr }}
+
+
+
+        {% if audiobook.is_youtube_publishable %}
+          <br>
+          <p>
+           <a href="{% url 'youtube_preview' audiobook.id %}">
+              {% trans "Preview YouTube metadata" %}
+            </a>
+          </p>
+
         {% endif %}
 
         {% if audiobook.youtube_id %}
         {% endif %}
 
         {% if audiobook.youtube_id %}
             <input class="btn btn-secondary" type="submit" value="{% trans "Update YouTube metadata" %}">
           </form>
         {% endif %}
             <input class="btn btn-secondary" type="submit" value="{% trans "Update YouTube metadata" %}">
           </form>
         {% endif %}
+        <form method="post" action="{% url 'youtube_publish' audiobook.id %}">
+          {% csrf_token %}
+          <input class="btn btn-primary" type="submit" value="{% trans "Publish on YouTube" %}" />
+        </form>
 
 
-        {% if audiobook.is_youtube_publishable %}
-          <br>
+      </div>
+      <div class="card-footer">
+        {% if audiobook.youtube_id %}
           <p>
           <p>
-           <a href="{% url 'youtube_preview' audiobook.id %}">
-              {% trans "Preview YouTube metadata" %}
+            <a href="https://youtu.be/{{ audiobook.youtube_id }}" target="_blank" title="{% trans "See on YouTube" %}">
+              <img src="https://i.ytimg.com/vi/{{ audiobook.youtube_id }}/hq720.jpg" style="width: 100%">
             </a>
           </p>
             </a>
           </p>
-          <form method="post" action="{% url 'youtube_publish' audiobook.id %}">
-            {% csrf_token %}
-            <input class="btn btn-primary" type="submit" value="{% trans "Publish on YouTube" %}" />
-          </form>
         {% endif %}
         {% endif %}
+        <p>{% trans "Published:" %} {{ audiobook.youtube_published }}</a></p>
 
       </div>
     </div>
   </div>
 
 
       </div>
     </div>
   </div>
 
+
 </div>
 
 
 
 </div>
 
 
 
-<div class="row">
-  <div class="col-xl-6">
-
-    <div class="card mt-4">
-      <div class="card-header">
-        <h3>Metadane dla MP3, Ogg</h3>
-      </div>
-      <div class="card-body">
-        <table class='table'>
-          {% tags_table audiobook.new_publish_tags 0 %}
-        </table>
-      </div>
-    </div>
-
-  </div>
-  <div class="col-xl-6">
-    <div class="card mt-4">
-      <div class="card-header">
-        <h3>Metadane dla YouTube</h3>
-      </div>
-      <div class="card-body">
-        <img src="{% url 'youtube_thumbnail' audiobook.id %}" style="width:100%">
-        <strong>{{ youtube_title }}</strong><br><br>
-        {{ youtube_description|linebreaksbr }}
-      </div>
-    </div>
-  </div>
-
-</div>
 
 
 <div class="card mt-4 mb-4">
   <div class="card-header">
     <h2>Plik źródłowy</h2>
 
 
 <div class="card mt-4 mb-4">
   <div class="card-header">
     <h2>Plik źródłowy</h2>
+    (informacje fizycznie ze źródłowego pliku)
   </div>
   <div class="card-body">
   </div>
   <div class="card-body">
-    <p>Last modified: {{ audiobook.modified }}</p>
-    <p>Plik źródłowy: <a href='{{ audiobook.source_file.url }}'>{{ path }}</a>
-      (sha1: <tt>{{ audiobook.source_sha1 }}</tt>).
-    </p>
-    {% multiple_tags_table tags %}
-
-    <form method="post" action="{% url 'remove_to_archive' audiobook.id %}"
-          onsubmit='return confirm("{% trans "Are you sure you want to move this audiobook to archive?" %}")'>
-      {% csrf_token %}
-      <input class="btn btn-danger" type="submit" value="{% trans "Remove to archive" %}" />
-    </form>
 
 
+    <div class="row">
+      <div class="col-lg-8">
+
+        <p>Last modified: {{ audiobook.modified }}</p>
+        <p>Plik źródłowy: <a href='{{ audiobook.source_file.url }}'>{{ path }}</a>
+          (sha1: <tt>{{ audiobook.source_sha1 }}</tt>).
+        </p>
+        {% multiple_tags_table tags %}
+      </div>
+
+      <div class="col-xl-4">
+        <div class="card">
+          <div class="card-body">
+            <form method="post" action="{% url 'remove_to_archive' audiobook.id %}"
+                  onsubmit='return confirm("{% trans "Are you sure you want to move this audiobook to archive?" %}")'>
+              {% csrf_token %}
+
+              <p>
+                Jeśli ten plik nie jest potrzebny, możesz usunąć informacje o nim z systemu,
+                zachowując go tylko w postaci samego źródłowego pliku.
+              </p>
+
+              <input class="btn btn-danger" type="submit" value="{% trans "Remove to archive" %}" />
+            </form>
+          </div>
+        </div>
+      </div>
+    </div>
   </div>
 </div>
 
   </div>
 </div>
 
+
 {% endblock %}
 {% endblock %}
index ad13504..2a8512d 100644 (file)
     <table class="table">
       {% for file in objects %}
         <tr>
     <table class="table">
       {% for file in objects %}
         <tr>
-          <td><a href='{% url "file" file.id %}'>{{ file }}</a></td>
+          <td>
+            <a href='{% url "file" file.id %}'>
+              {{ file }}
+              {% if file.youtube_status == k.0 and file.youtube_volume %}
+                <br>
+                <small>
+                  ({{ file.youtube_volume_index }}/{{ file.youtube_volume_count }})
+                  {{ file.youtube_volume }}
+                </small>
+              {% endif %}
+            </a>
+          </td>
           <td class="text-warning">
             {% if file.mp3_status == k.0 %}MP3{% endif %}
           </td>
           <td class="text-warning">
             {% if file.mp3_status == k.0 %}MP3{% endif %}
           </td>
index c3dfa23..0fa23ac 100755 (executable)
@@ -34,3 +34,16 @@ def status(audiobook, format):
         "format": format,
         "link": link,
     }
         "format": format,
         "link": link,
     }
+
+
+
+@register.filter
+def duration(s):
+    try:
+        h = int(s / 3600)
+    except:
+        return s
+    s %= 3600
+    m = int(s / 60)
+    s %= 60
+    return f'{h}:{m:02d}:{s:02.1f}'
index 4743227..b057df4 100644 (file)
@@ -1,23 +1,23 @@
-from django.conf.urls import url
 from django.urls import path
 from django.views.generic import RedirectView
 from . import views
 
 urlpatterns = [
     path("", views.AudiobookList.as_view(), name="list_managed"),
 from django.urls import path
 from django.views.generic import RedirectView
 from . import views
 
 urlpatterns = [
     path("", views.AudiobookList.as_view(), name="list_managed"),
-    url(r'^new/$', views.list_new, name="list_new"),
-    url(r'^new/(.+)/$', views.file_new, name="file_new"),
-    url(r'^move_to_archive/(.+)/$', views.move_to_archive, name="move_to_archive"),
-    url(r'^publishing/$', views.list_publishing, name="list_publishing"),
+    path('new/', views.list_new, name="list_new"),
+    path('new/<path:filename>/', views.file_new, name="file_new"),
+    path('move_to_archive/<path:filename>/', views.move_to_archive, name="move_to_archive"),
+    path('publishing/', views.list_publishing, name="list_publishing"),
     path('book/<slug:slug>/', views.BookView.as_view(), name="book"),
     path('book/<slug:slug>/', views.BookView.as_view(), name="book"),
-    url(r'^file/(\d+)/$', views.file_managed, name="file"),
-    url(r'^publish/(\d+)/$', views.publish, name="publish"),
-    url(r'^convert/(\d+)/$', views.publish, {'publish': False}, name="convert"),
-    url(r'^download/(\d+)/$', views.download, name="download"),
-    url(r'^download/(\d+)\.(mp3|ogg|mkv)$', views.download, name="download"),
-    url(r'^cancel/(\d+)/$', views.cancel_publishing, name="cancel_publishing"),
-    url(r'^remove_to_archive/(\d+)/$', views.remove_to_archive, name="remove_to_archive"),
-    url(r'^unmanaged/$', views.list_unmanaged, name="list_unmanaged"),
-    url(r'^unmanaged/(.+)/$', views.file_unmanaged, name="file_unmanaged"),
-    url(r'^move_to_new/(.+)/$', views.move_to_new, name="move_to_new"),
+    path('book-youtube-volume/<int:aid>/', views.book_youtube_volume, name="book_youtube_volume"),
+    path('file/<int:id>/', views.file_managed, name="file"),
+    path('publish/<int:aid>/', views.publish, name="publish"),
+    path('convert/<int:aid>/', views.publish, {'publish': False}, name="convert"),
+    path('download/<int:aid>/', views.download, name="download"),
+    path('download/<int:aid>.<slug:which>', views.download, name="download"),
+    path('cancel/<int:aid>/', views.cancel_publishing, name="cancel_publishing"),
+    path('remove_to_archive/<int:aid>/', views.remove_to_archive, name="remove_to_archive"),
+    path('unmanaged/', views.list_unmanaged, name="list_unmanaged"),
+    path('unmanaged/<path:filename>/', views.file_unmanaged, name="file_unmanaged"),
+    path('move_to_new/<path:filename>/', views.move_to_new, name="move_to_new"),
 ]
 ]
index fab7a1c..6ae2927 100644 (file)
@@ -70,9 +70,8 @@ def file_new(request, filename):
 def move_to_archive(request, filename):
     """ move a new file to the unmanaged files dir """
 
 def move_to_archive(request, filename):
     """ move a new file to the unmanaged files dir """
 
-    filename_str = filename.encode('utf-8')
-    old_path = os.path.join(settings.NEW_PATH, filename_str)
-    new_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
+    old_path = os.path.join(settings.NEW_PATH, filename)
+    new_path = os.path.join(settings.UNMANAGED_PATH, filename)
     new_dir = os.path.split(new_path)[0]
     if not os.path.isdir(new_dir):
         os.makedirs(new_dir)
     new_dir = os.path.split(new_path)[0]
     if not os.path.isdir(new_dir):
         os.makedirs(new_dir)
@@ -131,9 +130,8 @@ def remove_to_archive(request, aid):
 def move_to_new(request, filename):
     """ move a unmanaged file to new files dir """
 
 def move_to_new(request, filename):
     """ move a unmanaged file to new files dir """
 
-    filename_str = filename.encode('utf-8')
-    old_path = os.path.join(settings.UNMANAGED_PATH, filename_str)
-    new_path = os.path.join(settings.NEW_PATH, filename_str)
+    old_path = os.path.join(settings.UNMANAGED_PATH, filename)
+    new_path = os.path.join(settings.NEW_PATH, filename)
     new_dir = os.path.split(new_path)[0]
     if not os.path.isdir(new_dir):
         os.makedirs(new_dir)
     new_dir = os.path.split(new_path)[0]
     if not os.path.isdir(new_dir):
         os.makedirs(new_dir)
@@ -157,20 +155,7 @@ def move_to_new(request, filename):
 def publish(request, aid, publish=True):
     """ mark file for publishing """
     audiobook = get_object_or_404(models.Audiobook, id=aid)
 def publish(request, aid, publish=True):
     """ mark file for publishing """
     audiobook = get_object_or_404(models.Audiobook, id=aid)
-    tags = {
-        'name': audiobook.title,
-        'url': audiobook.url,
-        'tags': audiobook.new_publish_tags(),
-        }
-    audiobook.set_mp3_tags(tags)
-    audiobook.set_ogg_tags(tags)
-    audiobook.mp3_status = audiobook.ogg_status = status.WAITING
-    audiobook.save()
-    # isn't there a race here?
-    audiobook.mp3_task = tasks.Mp3Task.delay(request.user.id, aid, publish).task_id
-    audiobook.ogg_task = tasks.OggTask.delay(request.user.id, aid, publish).task_id
-    audiobook.save()
-
+    audiobook.publish(request.user, publish=publish)
     return redirect(file_managed, aid)
 
 
     return redirect(file_managed, aid)
 
 
@@ -287,7 +272,7 @@ def list_unmanaged(request):
 
 
 def file_unmanaged(request, filename):
 
 
 def file_unmanaged(request, filename):
-    tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename.encode('utf-8')))
+    tags = mutagen.File(os.path.join(settings.UNMANAGED_PATH, filename))
     if not tags:
         tags = {}
     
     if not tags:
         tags = {}
     
@@ -299,6 +284,39 @@ class BookView(ListView):
     template_name = 'archive/book.html'
 
     def get_queryset(self):
     template_name = 'archive/book.html'
 
     def get_queryset(self):
-        return models.Audiobook.objects.filter(slug=self.kwargs["slug"]).order_by(
+        qs = models.Audiobook.objects.filter(slug=self.kwargs["slug"]).order_by(
             "index"
         )
             "index"
         )
+        last_vol = None
+        last_vol_sub = None
+        for b in qs:
+            if last_vol is None or last_vol.youtube_volume_index != b.youtube_volume_index:
+                last_vol = b
+                b.total = 0
+                if last_vol_sub is None or b.youtube_volume:
+                    last_vol_sub = last_vol
+                    last_vol_sub.total_for_sub = 0
+            last_vol.total += b.duration
+            last_vol_sub.total_for_sub += b.duration
+            b.subtotal = last_vol_sub.total_for_sub
+        return list(qs)
+
+
+@permission_required('archive.change_audiobook')
+def book_youtube_volume(request, aid):
+    audiobook = get_object_or_404(models.Audiobook, id=aid)
+    slug = audiobook.slug
+    cur_vol = audiobook.youtube_volume
+    new_vol = request.POST.get('volume', '')
+
+    audiobook.youtube_volume = new_vol
+    audiobook.save()
+    
+    for a in models.Audiobook.objects.filter(slug=slug, youtube_volume=cur_vol, index__gt=audiobook.index).order_by('index'):
+        if a.youtube_volume != cur_vol:
+            break
+        a.youtube_volume = new_vol
+        a.save()
+    
+    return redirect('book', audiobook.slug)
+    
index f36fe81..87f53dc 100644 (file)
@@ -20,6 +20,9 @@ DATABASES = {
     }
 }
 
     }
 }
 
+DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
+
+
 # Local time zone for this installation. Choices can be found here:
 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
 # although not all choices may be available on all operating systems.
 # Local time zone for this installation. Choices can be found here:
 # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
 # although not all choices may be available on all operating systems.
index 1e86547..c6101b8 100644 (file)
Binary files a/src/youtube/locale/pl/LC_MESSAGES/django.mo and b/src/youtube/locale/pl/LC_MESSAGES/django.mo differ
index 6446cb2..87d3e6d 100644 (file)
@@ -7,23 +7,35 @@ msgid ""
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
 msgstr ""
 "Project-Id-Version: \n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-04-01 14:18+0200\n"
-"PO-Revision-Date: 2020-04-01 14:18+0200\n"
+"POT-Creation-Date: 2022-10-25 13:56+0200\n"
+"PO-Revision-Date: 2022-10-25 13:57+0200\n"
+"Last-Translator: \n"
+"Language-Team: \n"
 "Language: pl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Language: pl\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
-"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
-"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
-"Last-Translator: \n"
-"Language-Team: \n"
-"X-Generator: Poedit 2.2.4\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && "
+"(n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
+"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
+"X-Generator: Poedit 3.0.1\n"
+
+#: youtube/models.py:37
+msgid "public"
+msgstr "publiczny"
+
+#: youtube/models.py:38
+msgid "unlisted"
+msgstr "niepubliczny"
+
+#: youtube/models.py:39
+msgid "private"
+msgstr "prywatny"
 
 
-#: models.py:23
+#: youtube/models.py:44
 msgid "YouTube configuration"
 msgstr "konfiguracja YouTube"
 
 msgid "YouTube configuration"
 msgstr "konfiguracja YouTube"
 
-#: models.py:24
+#: youtube/models.py:45
 msgid "YouTube configurations"
 msgstr "konfiguracje YouTube"
 msgid "YouTube configurations"
 msgstr "konfiguracje YouTube"
index fd50e0c..c480830 100644 (file)
@@ -16,8 +16,8 @@ class Command(BaseCommand):
             .exclude(youtube_queued=None)
             .order_by("youtube_queued")[: options["limit"]]
         ):
             .exclude(youtube_queued=None)
             .order_by("youtube_queued")[: options["limit"]]
         ):
-            audiobook.youtube_task = tasks.YouTubeTask.delay(
+            tasks.YouTubeTask.delay(
                 None, audiobook.id, True
             ).task_id
             audiobook.youtube_status = status.WAITING
                 None, audiobook.id, True
             ).task_id
             audiobook.youtube_status = status.WAITING
-            audiobook.save(update_fields=["youtube_task", "youtube_status"])
+            audiobook.save(update_fields=["youtube_status"])
index a54cf12..15909f0 100644 (file)
@@ -18,7 +18,7 @@ def move_definitions(apps, schema_editor):
     ThumbnailTemplate = apps.get_model('youtube', 'ThumbnailTemplate')
     order = 1
     for youtube in YouTube.objects.all():
     ThumbnailTemplate = apps.get_model('youtube', 'ThumbnailTemplate')
     order = 1
     for youtube in YouTube.objects.all():
-        src_def = yaml.load(youtube.thumbnail_definition)
+        src_def = yaml.safe_load(youtube.thumbnail_definition)
         version_lists = [
             box['versions']
             for box in src_def['boxes']
         version_lists = [
             box['versions']
             for box in src_def['boxes']
index cad3d11..7cf5eac 100644 (file)
@@ -10,7 +10,7 @@ class YouTubeTask(AudioFormatTask):
     def encode(self, in_paths, out_path):
         self.audiobook.project.youtube.prepare_file(in_paths, out_path)
 
     def encode(self, in_paths, out_path):
         self.audiobook.project.youtube.prepare_file(in_paths, out_path)
 
-    def set_tags(self, audiobook, filename):
+    def set_tags(self, tags, filename):
         pass
 
     @classmethod
         pass
 
     @classmethod
@@ -23,12 +23,16 @@ class YouTubeTask(AudioFormatTask):
 
     def get_source_file_paths(self, audiobook):
         if not audiobook.youtube_volume:
 
     def get_source_file_paths(self, audiobook):
         if not audiobook.youtube_volume:
-            return [audiobook.source_file.path]
-        return [
-            a.source_file.path
-            for a in type(audiobook)
-            .objects.filter(
-                slug=audiobook.slug, youtube_volume=audiobook.youtube_volume
-            )
-            .order_by("index")
-        ]
+            paths = [audiobook.source_file.path]
+        else:
+            paths = [
+                a.source_file.path
+                for a in type(audiobook)
+                .objects.filter(
+                    slug=audiobook.slug, youtube_volume=audiobook.youtube_volume
+                )
+                .order_by("index")
+            ]
+        if audiobook.project.info_flac:
+            paths.append(audiobook.project.info_flac.path)
+        return paths
index e40b552..c64e5b5 100644 (file)
@@ -70,7 +70,7 @@ def draw_box_with_scaling(img, d, context, get_font_path):
 
 def create_thumbnail(background_path, defn, context, get_font_path):
     img = Image.open(background_path)
 
 def create_thumbnail(background_path, defn, context, get_font_path):
     img = Image.open(background_path)
-    d = yaml.load(defn)
+    d = yaml.safe_load(defn)
     for boxdef in d['boxes']:
         if not draw_box_with_scaling(img, boxdef, context, get_font_path):
             raise ValueError()
     for boxdef in d['boxes']:
         if not draw_box_with_scaling(img, boxdef, context, get_font_path):
             raise ValueError()
index 8a4618b..91dbeb4 100644 (file)
@@ -1,9 +1,8 @@
-from django.conf.urls import url
 from django.urls import path
 from . import views
 
 urlpatterns = [
 from django.urls import path
 from . import views
 
 urlpatterns = [
-    url(r'^publish/(\d+)/$', views.publish, name="youtube_publish"),
+    path('publish/<int:aid>/', views.publish, name="youtube_publish"),
     path('book/<slug:slug>/publish/', views.book_publish, name="youtube_book_publish"),
     path('thumbnail/<int:aid>/', views.thumbnail, name='youtube_thumbnail'),
     path('thumbnail/<int:aid>/<int:thumbnail_id>/', views.thumbnail, name='youtube_thumbnail'),
     path('book/<slug:slug>/publish/', views.book_publish, name="youtube_book_publish"),
     path('thumbnail/<int:aid>/', views.thumbnail, name='youtube_thumbnail'),
     path('thumbnail/<int:aid>/<int:thumbnail_id>/', views.thumbnail, name='youtube_thumbnail'),
index 3b64018..87fcf1a 100644 (file)
@@ -1,3 +1,4 @@
+import hashlib
 import os
 import shutil
 import subprocess
 import os
 import shutil
 import subprocess
@@ -31,7 +32,16 @@ def process_to_file(cmdline, prefix='', suffix='', cache_key=None, output_path=N
         output_path = tmp.name
 
     if cache_key:
         output_path = tmp.name
 
     if cache_key:
-        cache_path = FILE_CACHE + cache_key.replace('/', '__')
+        cache_path = cache_key.replace('/', '__')
+        if len(cache_path) > 200:
+            parts = cache_path.rsplit('.', 1)
+            limit = 200 - 9
+            if len(parts) > 1:
+                limit -= len(parts[1]) + 1
+            cache_path = parts[0][:limit] + '.' + hashlib.sha1(cache_key.encode('utf-8')).hexdigest()[:8]
+            if len(parts) > 1:
+                cache_path += '.' + parts[1]
+        cache_path = FILE_CACHE + cache_path
 
     if cache_key and os.path.exists(cache_path):
         link_or_copy(cache_path, output_path)
 
     if cache_key and os.path.exists(cache_path):
         link_or_copy(cache_path, output_path)