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, basedir, tolerate_vbr=True):
43 self.basedir = os.path.normpath(os.path.abspath(basedir))
44 self.tolerate_vbr = tolerate_vbr
45
46 - def get_main_path(self, audioname):
47 return path_join(self.basedir,
48 'main',
49 audioname)
50
53 p = path_join(self.basedir,
54 'extra',
55 'master',
56 audioname)
57 if path_exists(p):
58 return p
59 raise FileNotFound(p)
60
67 path = path_join(self.basedir,
68 'extra',
69 'transcoded',
70 str(bitrate),
71 str(samplerate),
72 mode,
73 audioname)
74 if not path.endswith('.mp3') or path.endswith('.MP3'):
75 path += '.mp3'
76 if create:
77 orig_path = self.get_extra_master_path(audioname)
78 if path_exists(path):
79 trans_mtime = getmtime(path)
80 orig_mtime = getmtime(orig_path)
81 if orig_mtime <= trans_mtime:
82
83 return path
84
85
86 transcode(orig_path, path, bitrate, samplerate, mode)
87 return path
88
90 symbols = list(rule(audioname))
91 if not symbols:
92 return symbols
93 audiopath = self.get_main_path(audioname)
94 (isvbr, bitrate,
95 samplerate, mode) = get_vbr_bitrate_samplerate_mode(audiopath)
96 if isvbr:
97 warn("file is vbr: %s", audiopath)
98 if not self.tolerate_vbr:
99 raise AudioProviderException("vbr not supported: %s" % audiopath)
100 else:
101
102 symbols = list(DefaultRule()(audioname))
103
104 def resolve(x):
105 if is_original(x):
106 path = self.get_main_path(x)
107 if create and not path_exists(path):
108 raise FileNotFound(path)
109 return path
110 else:
111 try:
112 return self.get_extra_transcoded_path(x,
113 mode,
114 bitrate,
115 samplerate,
116 create)
117 except FileNotFound:
118 warn("extra audio not found: %s", x)
119 return None
120
121 return [y for y in (resolve(x) for x in symbols) if y]
122
123
125
126 - def __init__(self, basedir, tolerate_vbr=True, targetdir=None):
131
133 return path_join(self.targetdir, audioname)
134
136 if audioname.startswith('/'):
137 audioname = audioname[1:]
138 mainpath = self.get_main_path(audioname)
139 playlist = self.get_playlist(audioname, rule)
140 target = self.get_combined_path(audioname)
141 parent = os.path.dirname(target)
142 if not path_exists(parent):
143 os.makedirs(parent)
144 renamed = '%s%d~%d~' % (target,
145 os.getpid(),
146 thread.get_ident())
147 fp = open(renamed, 'wb')
148 for chunk in splice(playlist, mainpath, **spliceKwargs):
149 fp.write(chunk)
150 fp.close()
151 os.rename(renamed, target)
152 return target
153
154
156
158 if audioname.startswith('/'):
159 audioname = audioname[1:]
160 mainpath = self.get_main_path(audioname)
161 playlist = self.get_playlist(audioname, rule)
162 return splice(playlist, mainpath, **spliceKwargs)
163
164
165 __all__ = ['AudioProviderException',
166 'FileNotFound',
167 'FSAudioProvider',
168 'StreamAudioProvider']
169