Package ewa :: Module audio
[hide private]
[frames] | no frames]

Source Code for Module ewa.audio

  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   
 23  path_join=os.path.join 
 24  path_exists=os.path.exists 
 25  getmtime=os.path.getmtime 
 26   
27 -def is_original(s):
28 return getattr(s, 'is_original', False)
29
30 -class AudioProviderException(RuntimeError):
31 pass
32
33 -class FileNotFound(AudioProviderException):
34 pass
35
36 -class BaseAudioProvider(object):
37 - def __init__(self, basedir):
38 self.basedir=os.path.normpath(os.path.abspath(basedir))
39
40 - def get_main_path(self, audioname):
41 return path_join(self.basedir, 42 'main', 43 audioname)
44
45 - def get_extra_master_path(self, 46 audioname):
47 p=path_join(self.basedir, 48 'extra', 49 'master', 50 audioname) 51 if path_exists(p): 52 return p 53 raise FileNotFound(p)
54 55
56 - def get_extra_transcoded_path(self, 57 audioname, 58 mode, 59 bitrate, 60 samplerate, 61 create=False):
62 path= path_join(self.basedir, 63 'extra', 64 'transcoded', 65 str(bitrate), 66 str(samplerate), 67 mode, 68 audioname) 69 if not path.endswith('.mp3') or path.endswith('.MP3'): 70 path+='.mp3' 71 if create: 72 orig_path=self.get_extra_master_path(audioname) 73 if path_exists(path): 74 trans_mtime=getmtime(path) 75 orig_mtime=getmtime(orig_path) 76 if orig_mtime <= trans_mtime: 77 # no transcoding necessary, return 78 return path 79 # either transcoded file is out of date 80 # or it doesn't exist, transcode 81 transcode(orig_path, path, bitrate, samplerate, mode) 82 return path
83
84 - def get_playlist(self, audioname, rule, create=True):
85 symbols=list(rule(audioname)) 86 if not symbols: 87 return symbols 88 audiopath=self.get_main_path(audioname) 89 isvbr, bitrate, samplerate, mode=get_vbr_bitrate_samplerate_mode(audiopath) 90 if isvbr: 91 warn("file is vbr: %s", audiopath) 92 raise AudioProviderException, "vbr not supported: %s" % audiopath 93 94 def resolve(x): 95 if is_original(x): 96 path=self.get_main_path(x) 97 if create and not path_exists(path): 98 raise FileNotFound(path) 99 return path 100 else: 101 try: 102 return self.get_extra_transcoded_path(x, mode, bitrate, samplerate, create) 103 except FileNotFound: 104 warn("extra audio not found: %s", x) 105 return None
106 107 return [y for y in (resolve(x) for x in symbols) if y]
108 109
110 -class FSAudioProvider(BaseAudioProvider):
111
112 - def __init__(self, basedir, targetdir=None):
113 super(FSAudioProvider, self).__init__(basedir) 114 if targetdir is None: 115 targetdir=path_join(basedir, 'combined') 116 self.targetdir=os.path.abspath(targetdir)
117
118 - def get_combined_path(self, audioname):
119 return path_join(self.targetdir, audioname)
120
121 - def create_combined(self, audioname, rule, **spliceKwargs):
122 if audioname.startswith('/'): 123 audioname=audioname[1:] 124 mainpath=self.get_main_path(audioname) 125 playlist=self.get_playlist(audioname, rule) 126 target=self.get_combined_path(audioname) 127 parent=os.path.dirname(target) 128 if not path_exists(parent): 129 os.makedirs(parent) 130 renamed='%s%d~%d~' % (target, 131 os.getpid(), 132 thread.get_ident()) 133 fp=open(renamed, 'wb') 134 for chunk in splice(playlist, mainpath, **spliceKwargs): 135 fp.write(chunk) 136 fp.close() 137 os.rename(renamed, target) 138 return target
139
140 -class StreamAudioProvider(BaseAudioProvider):
141
142 - def create_combined(self, audioname, rule, **spliceKwargs):
143 if audioname.startswith('/'): 144 audioname=audioname[1:] 145 mainpath=self.get_main_path(audioname) 146 playlist=self.get_playlist(audioname, rule) 147 return splice(playlist, mainpath, **spliceKwargs)
148 149 150 151 __all__=['AudioProviderException', 152 'FileNotFound', 153 'FSAudioProvider', 154 'StreamAudioProvider'] 155