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.
--- /dev/null
+# 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'),
+ ),
+ ]
--- /dev/null
+# 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'),
+ ),
+ ]
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)
info_flac = models.FileField(upload_to='archive/info_flac', blank=True)
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=_('license'), related_name='secondary')
# 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_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)
- 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_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)
- 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)
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 prepare_for_publish(self):
- tags = {
- 'name': self.title,
- 'url': self.url,
- 'tags': self.new_publish_tags(),
- }
- self.set_mp3_tags(tags)
- self.set_ogg_tags(tags)
- self.mp3_status = self.ogg_status = status.WAITING
- self.save()
-
def publish(self, user, publish=True):
from . import tasks
- # isn't there a race here?
- self.mp3_task = tasks.Mp3Task.delay(user.id, self.pk, publish=publish).task_id
- self.ogg_task = tasks.OggTask.delay(user.id, self.pk, publish=publish).task_id
- self.save()
+ 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 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
def prepare_audio(self):
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()
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
**{field: getattr(audiobook, field)})
@classmethod
- def published(cls, aid):
+ def published(cls, aid, tags):
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,
}
@classmethod
def put(cls, user, audiobook, path):
- tags = getattr(audiobook, "get_%s_tags" % cls.prefix)()
data = {
- 'book': tags['url'],
+ 'book': audiobook.url,
'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,
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.published(aid)
+ self.published(aid, tags)
else:
self.set_status(aid, None)
])
@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)
- 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:]))
<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-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>
+ </div>
+ </div>
+ </div>
+
+
+</div>
+
+
+
+
+
+
+
+
+<div class="row">
+
+ <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 %}
+ </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 %}
+
+ <div class="
+ {% if audiobook.youtube_id %}
+ <form method="post" action="{% url 'youtube_update_thumbnail' audiobook.id %}">
+ {% csrf_token %}
+ <input class="btn btn-secondary" type="submit" value="{% trans "Update YouTube thumbnail" %}">
+ </form>
+ <br>
+
+ <form method="post" action="{% url 'youtube_update' audiobook.id %}">
+ {% csrf_token %}
+ <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>
+ {% endif %}
+
+ </div>
+ <div class="card-footer">
+ {% 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 %}
+ <p>{% trans "Published:" %} {{ audiobook.youtube_published }}</a></p>
</div>
</div>
</div>
+ <div class="col-xl-4">
+
+ <div class="card mt-4">
+ <div class="card-header">
+ <h3>Metadane dla MP3, Ogg</h3>
+ </div>
+ <div class="card-body">
+ <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>
+
+ </div>
+
+
<div class="col-xl-5">
{% if audiobook.mp3_status or audiobook.ogg_status or audiobook.youtube_status %}
<h2>{% trans "Publishing pending" %}</h2>
<hr/>
<h2>MP3</h2>
- {% tags_table audiobook.get_mp3_tags.tags %}
-
<p>Status: <b>{{ audiobook.get_mp3_status_display }}</b></p>
{% endif %}
<hr/>
<h2>Ogg Vorbis</h2>
- {% tags_table audiobook.get_ogg_tags.tags %}
-
<p>Status: <b>{{ audiobook.get_ogg_status_display }}</b></p>
{% endif %}
<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 %}
<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 %}
</div>
</div>
- <div class="card mt-4">
- <div class="card-header">
- <h3>YouTube</h3>
- </div>
- <div class="card-body">
- {% if audiobook.youtube_status %}
- <hr/>
- <h2>YouTube</h2>
-
- <p>Status: <b>{{ audiobook.get_youtube_status_display }}</b></p>
- {% endif %}
-
- {% 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>
- {% endif %}
- {% else %}
- <p>{% trans "YouTube file hasn't been generated yet." %}</p>
- {% endif %}
-
- {% if audiobook.youtube_id %}
- <form method="post" action="{% url 'youtube_update_thumbnail' audiobook.id %}">
- {% csrf_token %}
- <input class="btn btn-secondary" type="submit" value="{% trans "Update YouTube thumbnail" %}">
- </form>
- <br>
-
- <form method="post" action="{% url 'youtube_update' audiobook.id %}">
- {% csrf_token %}
- <input class="btn btn-secondary" type="submit" value="{% trans "Update YouTube metadata" %}">
- </form>
- {% endif %}
-
- {% if audiobook.is_youtube_publishable %}
- <br>
- <p>
- <a href="{% url 'youtube_preview' audiobook.id %}">
- {% trans "Preview YouTube metadata" %}
- </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 %}
-
- </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>
+ (informacje fizycznie ze źródłowego pliku)
</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>
+
{% endblock %}
def publish(request, aid, publish=True):
""" mark file for publishing """
audiobook = get_object_or_404(models.Audiobook, id=aid)
- audiobook.prepare_for_publish()
- if publish:
- audiobook.publish(request.user)
+ audiobook.publish(request.user, publish=publish)
return redirect(file_managed, aid)
.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
- audiobook.save(update_fields=["youtube_task", "youtube_status"])
+ audiobook.save(update_fields=["youtube_status"])
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