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_PATH, UPLOAD_CMD, UPLOAD_SUDO)
23 from archive.utils import ExistingFile
25 api.env.host_string = UPLOAD_HOST
26 api.env.user = UPLOAD_USER
28 class AudioFormatTask(Task):
32 def set_status(cls, audiobook, status):
33 setattr(audiobook, '%s_status' % cls.ext, status)
37 def encode(in_path, out_path):
41 def set_tags(cls, audiobook, file_name):
42 audio = File(file_name)
43 for k, v in getattr(audiobook, "%s_tags" % cls.ext)['tags'].items():
48 def save(cls, audiobook, file_name):
49 getattr(audiobook, "%s_file" % cls.ext).save(
50 "%d.%s" % (audiobook.pk, cls.ext),
51 ExistingFile(file_name)
55 def published(cls, audiobook):
56 setattr(audiobook, "%s_published_tags" % cls.ext,
57 getattr(audiobook, "%s_tags" % cls.ext))
58 setattr(audiobook, "%s_tags" % cls.ext, None)
59 setattr(audiobook, "%s_published" % cls.ext, datetime.now())
60 cls.set_status(audiobook, None)
63 def put(cls, audiobook):
64 tags = getattr(audiobook, "%s_tags" % cls.ext)
65 prefix, slug = tags['url'].rstrip('/').rsplit('/', 1)
67 path = getattr(audiobook, "%s_file" % cls.ext).path
68 api.put(path, UPLOAD_PATH)
69 command = UPLOAD_CMD + (u' %s %s %s > output.txt' % (
70 pipes.quote(os.path.join(UPLOAD_PATH, os.path.basename(path))),
76 api.sudo(command, user=UPLOAD_SUDO, shell=False)
81 audiobook = Audiobook.objects.get(id=aid)
82 self.set_status(audiobook, status.ENCODING)
85 os.makedirs(BUILD_PATH)
87 if e.errno == errno.EEXIST:
92 out_file = NamedTemporaryFile(delete=False, prefix='audiobook-', suffix='.%s' % self.ext, dir=BUILD_PATH)
94 self.encode(audiobook.source_file.path, out_file.name)
95 self.set_status(audiobook, status.TAGGING)
96 self.set_tags(audiobook, out_file.name)
97 self.save(audiobook, out_file.name)
98 self.set_status(audiobook, status.SENDING)
102 self.published(audiobook)
106 class Mp3Task(AudioFormatTask):
109 # these shouldn't be staticmethods
110 def id3_text(tag, text):
111 return tag(encoding=1, text=text)
112 def id3_url(tag, text):
114 def id3_comment(tag, text, lang=u'pol'):
115 return tag(encoding=1, lang=lang, desc=u'', text=text)
116 def id3_sha1(tag, text, what=u''):
117 return tag(owner='http://wolnelektury.pl?%s' % what, data=text)
120 'album': (id3_text, id3.TALB),
121 'albumartist': (id3_text, id3.TPE2),
122 'artist': (id3_text, id3.TPE1),
123 'conductor': (id3_text, id3.TPE3),
124 'copyright': (id3_text, id3.TCOP),
125 'date': (id3_text, id3.TDRC),
126 'genre': (id3_text, id3.TCON),
127 'language': (id3_text, id3.TLAN),
128 'organization': (id3_text, id3.TPUB),
129 'title': (id3_text, id3.TIT2),
130 'comment': (id3_comment, id3.COMM, 'pol'),
131 'contact': (id3_url, id3.WOAF),
132 'license': (id3_url, id3.WCOP),
133 'flac_sha1': (id3_sha1, id3.PRIV, 'flac_sha1'),
137 def encode(in_path, out_path):
138 # 44.1kHz 64kbps mono MP3
139 subprocess.check_call(['ffmpeg',
149 def set_tags(cls, audiobook, file_name):
150 audio = id3.ID3(file_name)
151 for k, v in audiobook.mp3_tags['tags'].items():
152 factory_tuple = cls.TAG_MAP[k]
153 factory, tagtype = factory_tuple[:2]
154 audio.add(factory(tagtype, v, *factory_tuple[2:]))
157 mime = mimetypes.guess_type(COVER_IMAGE)
158 f = open(COVER_IMAGE)
159 audio.add(id3.APIC(encoding=0, mime=mime, type=3, desc=u'', data=f.read()))
165 class OggTask(AudioFormatTask):
169 def encode(in_path, out_path):
170 # 44.1kHz 64kbps mono Ogg Vorbis
171 subprocess.check_call(['oggenc',
173 '--discard-comments',
174 '--resample', '44100',