X-Git-Url: https://git.mdrn.pl/audio.git/blobdiff_plain/65e9eb19f0c8fb7ec7b81653a63c3de9f970e2d2..6b9d2a8ea0a58826f0f30f135a3f7d065b3bb435:/apps/archive/tasks.py?ds=sidebyside diff --git a/apps/archive/tasks.py b/apps/archive/tasks.py old mode 100755 new mode 100644 index 8d8df5e..a46b79c --- a/apps/archive/tasks.py +++ b/apps/archive/tasks.py @@ -4,13 +4,16 @@ import mimetypes import os import os.path import pipes +import stat import subprocess from tempfile import NamedTemporaryFile from time import sleep #from celery.decorators import task from celery.task import Task +from django.db.models import F from fabric import api +from fabric.network import disconnect_all from mutagen import File from mutagen import id3 @@ -19,7 +22,7 @@ import mutagen from archive.constants import status from archive.models import Audiobook from archive.settings import (BUILD_PATH, COVER_IMAGE, - UPLOAD_HOST, UPLOAD_USER, UPLOAD_PATH, UPLOAD_CMD, UPLOAD_SUDO) + UPLOAD_HOST, UPLOAD_USER, UPLOAD_PASSWORD, UPLOAD_PATH, UPLOAD_CMD, UPLOAD_SUDO) from archive.utils import ExistingFile api.env.host_string = UPLOAD_HOST @@ -29,58 +32,77 @@ api.env.password = UPLOAD_PASSWORD class AudioFormatTask(Task): abstract = True + class RemoteOperationError(BaseException): + pass + @classmethod - def set_status(cls, audiobook, status): - setattr(audiobook, '%s_status' % cls.ext, status) - audiobook.save() + def set_status(cls, aid, status): + Audiobook.objects.filter(pk=aid).update( + **{'%s_status' % cls.ext: status}) @staticmethod def encode(in_path, out_path): - pass + raise NotImplemented @classmethod def set_tags(cls, audiobook, file_name): + tags = getattr(audiobook, "%s_tags" % cls.ext)['tags'] + if not tags.get('flac_sha1'): + tags['flac_sha1'] = audiobook.get_source_sha1() audio = File(file_name) - for k, v in getattr(audiobook, "%s_tags" % cls.ext)['tags'].items(): + for k, v in tags.items(): audio[k] = v audio.save() @classmethod def save(cls, audiobook, file_name): - getattr(audiobook, "%s_file" % cls.ext).save( + field = "%s_file" % cls.ext + getattr(audiobook, field).save( "%d.%s" % (audiobook.pk, cls.ext), - ExistingFile(file_name) + ExistingFile(file_name), + save=False ) + os.chmod(getattr(audiobook, field).path, stat.S_IREAD|stat.S_IWRITE|stat.S_IRGRP|stat.S_IROTH) + Audiobook.objects.filter(pk=audiobook.pk).update( + **{field: getattr(audiobook, field)}) @classmethod - def published(cls, audiobook): - setattr(audiobook, "%s_published_tags" % cls.ext, - getattr(audiobook, "%s_tags" % cls.ext)) - setattr(audiobook, "%s_tags" % cls.ext, None) - setattr(audiobook, "%s_published" % cls.ext, datetime.now()) - cls.set_status(audiobook, None) + def published(cls, aid): + kwargs = { + "%s_published_tags" % cls.ext: F("%s_tags" % cls.ext), + "%s_tags" % cls.ext: None, + "%s_published" % cls.ext: datetime.now(), + '%s_status' % cls.ext: None, + } + Audiobook.objects.filter(pk=aid).update(**kwargs) @classmethod - def put(cls, audiobook): + def put(cls, audiobook, path): tags = getattr(audiobook, "%s_tags" % cls.ext) prefix, slug = tags['url'].rstrip('/').rsplit('/', 1) name = tags['name'] - path = getattr(audiobook, "%s_file" % cls.ext).path - api.put(path, UPLOAD_PATH) - command = UPLOAD_CMD + (u' %s %s %s > output.txt' % ( + command = UPLOAD_CMD + (u' %s %s %s %s %s %s > output.txt' % ( pipes.quote(os.path.join(UPLOAD_PATH, os.path.basename(path))), pipes.quote(slug), - pipes.quote(name) + pipes.quote(name), + pipes.quote(audiobook.part_name), + audiobook.index, + audiobook.parts_count, )).encode('utf-8') - print command - if UPLOAD_SUDO: - api.sudo(command, user=UPLOAD_SUDO, shell=False) - else: - api.run(command) + try: + api.put(path, UPLOAD_PATH) + if UPLOAD_SUDO: + api.sudo(command, user=UPLOAD_SUDO, shell=False) + else: + api.run(command) + disconnect_all() + except SystemExit, e: + raise cls.RemoteOperationError - def run(self, aid): + def run(self, aid, publish=True): + aid = int(aid) audiobook = Audiobook.objects.get(id=aid) - self.set_status(audiobook, status.ENCODING) + self.set_status(aid, status.ENCODING) try: os.makedirs(BUILD_PATH) @@ -90,18 +112,24 @@ class AudioFormatTask(Task): else: raise - out_file = NamedTemporaryFile(delete=False, prefix='audiobook-', suffix='.%s' % self.ext, dir=BUILD_PATH) + out_file = NamedTemporaryFile(delete=False, prefix='%d-' % aid, suffix='.%s' % self.ext, dir=BUILD_PATH) out_file.close() self.encode(audiobook.source_file.path, out_file.name) - self.set_status(audiobook, status.TAGGING) + self.set_status(aid, status.TAGGING) self.set_tags(audiobook, out_file.name) - self.save(audiobook, out_file.name) - self.set_status(audiobook, status.SENDING) + self.set_status(aid, status.SENDING) - self.put(audiobook) + if publish: + self.put(audiobook, out_file.name) + self.published(aid) + else: + self.set_status(aid, None) - self.published(audiobook) - audiobook.save() + self.save(audiobook, out_file.name) + + def on_failure(self, exc, task_id, args, kwargs, einfo): + aid = (args[0], kwargs.get('aid'))[0] + self.set_status(aid, None) class Mp3Task(AudioFormatTask): @@ -114,8 +142,8 @@ class Mp3Task(AudioFormatTask): return tag(url=text) def id3_comment(tag, text, lang=u'pol'): return tag(encoding=1, lang=lang, desc=u'', text=text) - def id3_sha1(tag, text, what=u''): - return tag(owner='http://wolnelektury.pl?%s' % what, data=text) + def id3_priv(tag, text, what=u''): + return tag(owner='wolnelektury.pl?%s' % what, data=text.encode('utf-8')) TAG_MAP = { 'album': (id3_text, id3.TALB), @@ -131,25 +159,31 @@ class Mp3Task(AudioFormatTask): 'comment': (id3_comment, id3.COMM, 'pol'), 'contact': (id3_url, id3.WOAF), 'license': (id3_url, id3.WCOP), - 'flac_sha1': (id3_sha1, id3.PRIV, 'flac_sha1'), + 'flac_sha1': (id3_priv, id3.PRIV, 'flac_sha1'), + 'project': (id3_priv, id3.PRIV, 'project'), + 'funded_by': (id3_priv, id3.PRIV, 'funded_by'), } @staticmethod def encode(in_path, out_path): # 44.1kHz 64kbps mono MP3 subprocess.check_call(['ffmpeg', - '-i', in_path, + '-i', in_path.encode('utf-8'), '-ar', '44100', '-ab', '64k', '-ac', '1', '-y', - out_path + '-acodec', 'libmp3lame', + out_path.encode('utf-8') ]) @classmethod def set_tags(cls, audiobook, file_name): + mp3_tags = audiobook.mp3_tags['tags'] + if not mp3_tags.get('flac_sha1'): + mp3_tags['flac_sha1'] = audiobook.get_source_sha1() audio = id3.ID3(file_name) - for k, v in audiobook.mp3_tags['tags'].items(): + for k, v in mp3_tags.items(): factory_tuple = cls.TAG_MAP[k] factory, tagtype = factory_tuple[:2] audio.add(factory(tagtype, v, *factory_tuple[2:])) @@ -169,11 +203,12 @@ class OggTask(AudioFormatTask): @staticmethod def encode(in_path, out_path): # 44.1kHz 64kbps mono Ogg Vorbis - subprocess.check_call(['oggenc', - in_path, - '--discard-comments', - '--resample', '44100', - '--downmix', - '-b', '64', - '-o', out_path + subprocess.check_call(['ffmpeg', + '-i', in_path.encode('utf-8'), + '-ar', '44100', + '-ab', '64k', + '-ac', '1', + '-y', + '-acodec', 'libvorbis', + out_path.encode('utf-8') ])