1 from datetime import datetime
 
   8 from tempfile import NamedTemporaryFile
 
  11 #from celery.decorators import task
 
  12 from celery.task import Task
 
  13 from fabric import api
 
  14 from mutagen import File
 
  15 from mutagen import id3
 
  19 from archive.constants import status
 
  20 from archive.models import Audiobook
 
  21 from archive.settings import (BUILD_PATH, COVER_IMAGE,
 
  22     UPLOAD_HOST, UPLOAD_USER, UPLOAD_PASSWORD, UPLOAD_PATH, UPLOAD_CMD, UPLOAD_SUDO)
 
  23 from archive.utils import ExistingFile
 
  25 api.env.host_string = UPLOAD_HOST
 
  26 api.env.user = UPLOAD_USER
 
  27 api.env.password = UPLOAD_PASSWORD
 
  29 class AudioFormatTask(Task):
 
  33     def set_status(cls, audiobook, status):
 
  34         Audiobook.objects.filter(pk=audiobook.pk).update(
 
  35             **{'%s_status' % cls.ext: status})
 
  38     def encode(in_path, out_path):
 
  42     def set_tags(cls, audiobook, file_name):
 
  43         audio = File(file_name)
 
  44         for k, v in getattr(audiobook, "%s_tags" % cls.ext)['tags'].items():
 
  49     def save(cls, audiobook, file_name):
 
  50         field = "%s_file" % cls.ext
 
  51         getattr(audiobook, field).save(
 
  52             "%d.%s" % (audiobook.pk, cls.ext),
 
  53             ExistingFile(file_name),
 
  56         Audiobook.objects.filter(pk=audiobook.pk).update(
 
  57             **{field: getattr(audiobook, field)})
 
  60     def published(cls, audiobook):
 
  62             "%s_published_tags" % cls.ext: 
 
  63                     getattr(audiobook, "%s_tags" % cls.ext),
 
  64             "%s_tags" % cls.ext: None,
 
  65             "%s_published" % cls.ext: datetime.now(),
 
  66             '%s_status' % cls.ext: None,
 
  68         Audiobook.objects.filter(pk=audiobook.pk).update(**kwargs)
 
  71     def put(cls, audiobook):
 
  72         tags = getattr(audiobook, "%s_tags" % cls.ext)
 
  73         prefix, slug = tags['url'].rstrip('/').rsplit('/', 1)
 
  75         path = getattr(audiobook, "%s_file" % cls.ext).path
 
  76         api.put(path, UPLOAD_PATH)
 
  77         command = UPLOAD_CMD + (u' %s %s %s > output.txt' % (
 
  78             pipes.quote(os.path.join(UPLOAD_PATH, os.path.basename(path))),
 
  83             api.sudo(command, user=UPLOAD_SUDO, shell=False)
 
  88         audiobook = Audiobook.objects.get(id=aid)
 
  89         self.set_status(audiobook, status.ENCODING)
 
  92             os.makedirs(BUILD_PATH)
 
  94             if e.errno == errno.EEXIST:
 
  99         out_file = NamedTemporaryFile(delete=False, prefix='audiobook-', suffix='.%s' % self.ext, dir=BUILD_PATH)
 
 101         self.encode(audiobook.source_file.path, out_file.name)
 
 102         self.set_status(audiobook, status.TAGGING)
 
 103         self.set_tags(audiobook, out_file.name)
 
 104         self.save(audiobook, out_file.name)
 
 105         self.set_status(audiobook, status.SENDING)
 
 109         self.published(audiobook)
 
 112 class Mp3Task(AudioFormatTask):
 
 115     # these shouldn't be staticmethods
 
 116     def id3_text(tag, text):
 
 117         return tag(encoding=1, text=text)
 
 118     def id3_url(tag, text):
 
 120     def id3_comment(tag, text, lang=u'pol'):
 
 121         return tag(encoding=1, lang=lang, desc=u'', text=text)
 
 122     def id3_sha1(tag, text, what=u''):
 
 123         return tag(owner='http://wolnelektury.pl?%s' % what, data=text)
 
 126         'album': (id3_text, id3.TALB),
 
 127         'albumartist': (id3_text, id3.TPE2),
 
 128         'artist': (id3_text, id3.TPE1),
 
 129         'conductor': (id3_text, id3.TPE3),
 
 130         'copyright': (id3_text, id3.TCOP),
 
 131         'date': (id3_text, id3.TDRC),
 
 132         'genre': (id3_text, id3.TCON),
 
 133         'language': (id3_text, id3.TLAN),
 
 134         'organization': (id3_text, id3.TPUB),
 
 135         'title': (id3_text, id3.TIT2),
 
 136         'comment': (id3_comment, id3.COMM, 'pol'),
 
 137         'contact': (id3_url, id3.WOAF),
 
 138         'license': (id3_url, id3.WCOP),
 
 139         'flac_sha1': (id3_sha1, id3.PRIV, 'flac_sha1'),
 
 143     def encode(in_path, out_path):
 
 144         # 44.1kHz 64kbps mono MP3
 
 145         subprocess.check_call(['ffmpeg', 
 
 155     def set_tags(cls, audiobook, file_name):
 
 156         audio = id3.ID3(file_name)
 
 157         for k, v in audiobook.mp3_tags['tags'].items():
 
 158             factory_tuple = cls.TAG_MAP[k]
 
 159             factory, tagtype = factory_tuple[:2]
 
 160             audio.add(factory(tagtype, v, *factory_tuple[2:]))
 
 163             mime = mimetypes.guess_type(COVER_IMAGE)
 
 164             f = open(COVER_IMAGE)
 
 165             audio.add(id3.APIC(encoding=0, mime=mime, type=3, desc=u'', data=f.read()))
 
 171 class OggTask(AudioFormatTask):
 
 175     def encode(in_path, out_path):
 
 176         # 44.1kHz 64kbps mono Ogg Vorbis
 
 177         subprocess.check_call(['oggenc', 
 
 179             '--discard-comments',
 
 180             '--resample', '44100',