1 """
2
3 This module is responsible for managing audio files:
4
5 * managing the main (content) audio files, located in
6 <audioroot>/main/path/to/audiofile
7 * managing extra audio files, located in
8 <audioroot/extra, in two subdirectories,
9 <audioroot/extra/masters and <audioroot/extra/transcoded.
10 * resolving audiofile symbolic names to files within
11 the managed hierarchy.
12 * creating combined (spliced) files according to rules passed
13 in.
14
15 """
16 import os
17 import thread
18
19 from ewa.mp3 import get_vbr_bitrate_samplerate_mode, splice
20 from ewa.transcode import transcode
21 from ewa.logutil import warn
22 from ewa.rules import DefaultRule
23
24 path_join = os.path.join
25 path_exists = os.path.exists
26 getmtime = os.path.getmtime
27
28
30 return getattr(s, 'is_original', False)
31
32
35
36
39
40
42 - def __init__(self,
43 basedir,
44 tolerate_vbr=True,
45 tolerate_broken=True):
46 self.basedir = os.path.normpath(os.path.abspath(basedir))
47 self.tolerate_vbr = tolerate_vbr
48 self.tolerate_broken = tolerate_broken
49
50 - def get_main_path(self, audioname):
51 return path_join(self.basedir,
52 'main',
53 audioname)
54
57 p = path_join(self.basedir,
58 'extra',
59 'master',
60 audioname)
61 if path_exists(p):
62 return p
63 raise FileNotFound(p)
64
71 path = path_join(self.basedir,
72 'extra',
73 'transcoded',
74 str(bitrate),
75 str(samplerate),
76 mode,
77 audioname)
78 if not path.endswith('.mp3') or path.endswith('.MP3'):
79 path += '.mp3'
80 if create:
81 orig_path = self.get_extra_master_path(audioname)
82 if path_exists(path):
83 trans_mtime = getmtime(path)
84 orig_mtime = getmtime(orig_path)
85 if orig_mtime <= trans_mtime:
86
87 return path
88
89
90 transcode(orig_path, path, bitrate, samplerate, mode)
91 return path
92
94 symbols = list(rule(audioname))
95 if not symbols:
96 return symbols
97 audiopath = self.get_main_path(audioname)
98 try:
99 (isvbr, bitrate,
100 samplerate, mode) = get_vbr_bitrate_samplerate_mode(audiopath)
101 except (InvalidAudioFormatException, TagException), exc:
102 if self.tolerate_broken:
103 warn('got %s for %s', exc, audiopath)
104
105 symbols = list(DefaultRule()(audioname))
106 isvbr = bitrate = samplerate = mode = None
107 else:
108 raise exc
109 else:
110 if isvbr:
111 warn("file is vbr: %s", audiopath)
112 if not self.tolerate_vbr:
113 raise AudioProviderException("vbr not supported: %s" \
114 % audiopath)
115 else:
116
117 symbols = list(DefaultRule()(audioname))
118
119 def resolve(x):
120 if is_original(x):
121 path = self.get_main_path(x)
122 if create and not path_exists(path):
123 raise FileNotFound(path)
124 return path
125 else:
126 try:
127 return self.get_extra_transcoded_path(x,
128 mode,
129 bitrate,
130 samplerate,
131 create)
132 except FileNotFound:
133 warn("extra audio not found: %s", x)
134 return None
135
136 return [y for y in (resolve(x) for x in symbols) if y]
137
138
140
141 - def __init__(self, basedir, tolerate_vbr=True,
142 tolerate_broken=True, targetdir=None):
149
151 return path_join(self.targetdir, audioname)
152
154 if audioname.startswith('/'):
155 audioname = audioname[1:]
156 mainpath = self.get_main_path(audioname)
157 playlist = self.get_playlist(audioname, rule)
158 target = self.get_combined_path(audioname)
159 parent = os.path.dirname(target)
160 if not path_exists(parent):
161 os.makedirs(parent)
162 renamed = '%s%d~%d~' % (target,
163 os.getpid(),
164 thread.get_ident())
165 fp = open(renamed, 'wb')
166 for chunk in splice(playlist, mainpath, **spliceKwargs):
167 fp.write(chunk)
168 fp.close()
169 os.rename(renamed, target)
170 return target
171
172
174
176 if audioname.startswith('/'):
177 audioname = audioname[1:]
178 mainpath = self.get_main_path(audioname)
179 playlist = self.get_playlist(audioname, rule)
180 return splice(playlist, mainpath, **spliceKwargs)
181
182
183 __all__ = ['AudioProviderException',
184 'FileNotFound',
185 'FSAudioProvider',
186 'StreamAudioProvider']
187