class TreePrefixInstance(list): def __init__(self): self.log = SoundforestLogger().default_stream self.db = ConfigDB() common_prefixes = set(DEFAULT_PATHS + [prefix.path for prefix in self.db.tree_prefixes]) for path in common_prefixes: for name, codec in self.db.codec_configuration.items(): prefix_path = os.path.join(path, name) prefix = MusicTreePrefix(prefix_path, [codec.name] + codec.extensions) self.add_prefix(prefix) if 'm4a' in self.db.codec_configuration.keys(): prefix_path = os.path.join(path, 'm4a') prefix = MusicTreePrefix(prefix_path, self.db.codec_configuration.extensions('m4a')) self.add_prefix(prefix) itunes_prefix = MusicTreePrefix(ITUNES_MUSIC, self.db.codec_configuration.extensions('m4a')) self.add_prefix(itunes_prefix) self.load_user_config() def load_user_config(self): if not os.path.isfile(USER_PATH_CONFIG): return try: with open(USER_PATH_CONFIG, 'r') as config: user_codecs = {} for line in config: try: if line.strip() == '' or line[:1] == '#': continue (codec_name, paths) = [x.strip() for x in line.split('=', 1)] paths = [x.strip() for x in paths.split(',')] except ValueError: self.log.debug('Error parsing line: {}'.format(line)) continue user_codecs[codec_name] = paths for codec_name in reversed(sorted(user_codecs.keys())): paths = user_codecs[codec_name] if codec_name == 'itunes': codec = match_codec('m4a') else: codec = match_codec(codec_name) if not codec: continue for path in reversed(paths): prefix = MusicTreePrefix(path, self.db.codec_configuration.extensions('aac')) if codec_name == 'itunes': self.add_prefix(prefix, prepend=False) else: self.add_prefix(prefix, prepend=True) except IOError as e: raise PrefixError('Error reading {}: {}'.format( USER_PATH_CONFIG, e, )) def index(self, prefix): if not isinstance(prefix, MusicTreePrefix): raise PrefixError('Prefix must be MusicTreePrefix instance') for index, existing in enumerate(self): if prefix.realpath == existing.realpath: return index raise IndexError('Prefix is not registered') def add_prefix(self, prefix, extensions=[], prepend=False): if isinstance(prefix, str): prefix = MusicTreePrefix(prefix, extensions) if not isinstance(prefix, MusicTreePrefix): raise PrefixError('prefix must be string or MusicTreePrefix instance') try: index = self.index(prefix) if prepend and index != 0: prefix = self.pop(index) self.insert(0, prefix) except IndexError: if prepend: self.insert(0, prefix) else: self.append(prefix) return prefix def match_extension(self, extension, match_existing=False): for prefix in self: if match_existing and not os.path.isdir(prefix.path): continue if prefix.match_extension(extension): return prefix return None def match(self, path, match_existing=False): for prefix in self: if match_existing and not os.path.isdir(prefix.path): continue if prefix.match(path): return prefix return None def relative_path(self, path): prefix = self.match(path) if not prefix: return path return prefix.relative_path(path)
class AudioFileFormat(object): """AudioFileFormat Common file format wrapper for various codecs """ def __init__(self, path): self.log = SoundforestLogger().default_stream self.path = path_string(path) self.codec = None self.description = None self.is_metadata = False self.codec = match_codec(path) if self.codec is not None: self.description = self.codec.description.lower() else: m = match_metadata(path) if m: self.is_metadata = True self.description = m.description.lower() elif os.path.isdir(path): self.description = 'unknown directory' else: self.description = 'unknown file format' def __repr__(self): return '{0} {1}'.format(self.codec, self.path) @property def directory(self): return os.path.dirname(self.path) @property def filename(self): return os.path.basename(self.path) @property def extension(self): return os.path.splitext(self.path)[1][1:] @property def size(self): if not self.path.isfile: return None return os.stat(self.path).st_size @property def ctime(self): if not self.path.isfile: return None return os.stat(self.path).st_ctime @property def mtime(self): if not self.path.isfile: return None return os.stat(self.path).st_mtime def get_temporary_file(self, dir=SOUNDFOREST_CACHE_DIR, prefix='tmp', suffix=''): if not os.path.isdir(dir): try: os.makedirs(dir) except IOError as e: raise SoundforestError('Error creating directory {0}: {1}'.format(SOUNDFOREST_CACHE_DIR, e)) except OSError as e: raise SoundforestError('Error creating directory {0}: {1}'.format(SOUNDFOREST_CACHE_DIR, e)) return tempfile.mktemp(dir=dir, prefix=prefix, suffix=suffix) def get_tag_parser(self): if self.codec is None: return None if self.codec.name in TAG_PARSERS.keys(): classpath = TAG_PARSERS[self.codec.name] else: try: classpath = TAG_PARSERS[TAG_EXTENSION_ALIASES[self.codec.name]] except KeyError: return None module_path = '.'.join(classpath.split('.')[:-1]) class_name = classpath.split('.')[-1] m = __import__(module_path, globals(), fromlist=[class_name]) return getattr(m, class_name) def get_available_encoders(self): if self.codec is None or not self.codec.encoders: return [] return filter_available_command_list(self.codec.encoders) def get_available_decoders(self): if self.codec is None or not self.codec.decoders: return [] return filter_available_command_list(self.codec.decoders) def get_available_testers(self): if self.codec is None or not self.codec.testers: return [] return filter_available_command_list(self.codec.testers) def execute(self, args): self.log.debug('running: {0}'.format(' '.join(args))) p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) (stdout, stderr) = p.communicate() if stdout: self.log.debug('output:\n{0}'.format(stdout)) if stderr: self.log.debug('errors:\n{0}'.format(stderr)) return p.returncode, stdout, stderr
class TreePrefixInstance(list): def __init__(self): self.log = SoundforestLogger().default_stream list.__init__(self) self.db = ConfigDB() common_prefixes = set(DEFAULT_PATHS + [prefix.path for prefix in self.db.prefixes]) for path in common_prefixes: for name, codec in self.db.codecs.items(): prefix_path = os.path.join(path, name) prefix = MusicTreePrefix(prefix_path, [codec.name] + codec.extensions) self.register_prefix(prefix) if 'm4a' in self.db.codecs.keys(): prefix_path = os.path.join(path, 'm4a') prefix = MusicTreePrefix(prefix_path, self.db.codecs.extensions('m4a')) self.register_prefix(prefix) itunes_prefix = MusicTreePrefix(ITUNES_MUSIC, self.db.codecs.extensions('m4a')) self.register_prefix(itunes_prefix) self.load_user_config() def load_user_config(self): if not os.path.isfile(USER_PATH_CONFIG): return try: with open(USER_PATH_CONFIG, 'r') as config: user_codecs = {} for line in config: try: if line.strip() == '' or line[:1] == '#': continue (codec_name, paths) = [x.strip() for x in line.split('=', 1)] paths = [x.strip() for x in paths.split(',')] except ValueError: self.log.debug('Error parsing line: %s' % line) continue user_codecs[codec_name] = paths for codec_name in reversed(sorted(user_codecs.keys())): paths = user_codecs[codec_name] if codec_name == 'itunes': codec = match_codec('m4a') else: codec = match_codec(codec_name) if not codec: continue for path in reversed(paths): prefix = MusicTreePrefix(path, self.db.codecs.extensions('aac')) if codec_name == 'itunes': self.register_prefix(prefix, prepend=False) else: self.register_prefix(prefix, prepend=True) except IOError, (ecode, emsg): raise PrefixError('Error reading %s: %s' % (USER_PATH_CONFIG, emsg))