def _format(self, filename=None, base=None, preadd=(), postadd=()): filename, base = from_config('filename', 'base') meta = NormMetaData(preadd) meta.update(self.meta.flat()) meta.update(postadd) filename = FileFormat(filename) base = os.path.abspath(base) return os.path.join(base, filename.evaluate(meta))
def scan(items, groupby = None, sortby = None, trackid = None): groupbytxt, sortbytxt, trackidtxt = from_config('groupby', 'sortby', 'trackid') groupby = Expr(groupby or groupbytxt) sortby = Expr(sortby or sortbytxt) trackid = Expr(trackid or trackidtxt) homedir = os.getenv('HOME') if homedir is not None: cachefile = os.path.join(homedir, '.audiomangler') try: os.mkdir(cachefile) except OSError: pass cachefile = os.path.join(cachefile, 'cache') else: cachefile = 'audiomangler.cache' dircache = {} if shelve: try: dircache = shelve.open(cachefile, protocol=2) except Exception: pass if dircache.get('//version', None) != db_version: dircache.clear() dircache['//version'] = db_version if isinstance(items, basestring): items = (items, ) tracks = [] scanned = set() newdircache = {} items = map(os.path.abspath, items) for item in items: if item in scanned: continue t = scan_track(item) if t is not None: tracks.append(t) scanned.add(item) else: dirs = [item] while dirs: path = dirs.pop(0) try: dst = os.stat(path) except OSError: print "unable to stat dir %s" % path continue cached = dircache.get(path, None) if cached and cached['key'] == (dst.st_ino, dst.st_mtime): newcached = cached newtracks = [] newfiles = [] for track in cached['tracks']: try: fst = os.stat(track['path']) except Exception: continue if track['key'] == (fst.st_ino, fst.st_size, fst.st_mtime): newtracks.append(track) t = track['obj'] t._meta_cache = (False, False) t.relpath = t.filename.replace(item, '', 1).lstrip('/') t.reldir = t.relpath.rsplit('/', 1) if len(t.reldir) > 1: t.reldir = t.reldir[0] else: t.reldir = '' tracks.append(t) else: t = scan_track(track['path']) if t is not None: tracks.append(t) newtracks.append({'path':track['path'], 'obj':t, 'key':(fst.st_ino, fst.st_size, fst.st_mtime)}) for file_ in cached['files']: try: fst = os.stat(file_['path']) except Exception: continue if file_['key'] == (fst.st_ino, fst.st_size, fst.st_mtime): newfiles.append(file_) else: t = scan_track(file_['path']) if t is not None: tracks.append(t) newtracks.append({'path':file_['path'], 'obj':t, 'key':(fst.st_ino, fst.st_size, fst.st_mtime)}) else: newfiles.append({'path':file_['path'], 'key':(fst.st_ino, fst.st_size, fst.st_mtime)}) newcached['tracks'] = newtracks newcached['files'] = newfiles else: newcached = {'tracks':[], 'dirs':[], 'files':[]} newcached['key'] = (dst.st_ino, dst.st_mtime) try: paths = (os.path.join(path, f) for f in sorted(os.listdir(path))) except OSError: continue for filename in paths: if filename in scanned: continue else: scanned.add(filename) if os.path.isdir(filename): newcached['dirs'].append(filename) elif os.path.isfile(filename): try: fst = os.stat(filename) except Exception: continue t = scan_track(filename) if t is not None: tracks.append(t) newcached['tracks'].append({'path':filename, 'obj':t, 'key':(fst.st_ino, fst.st_size, fst.st_mtime)}) else: newcached['files'].append({'path':filename, 'key':(fst.st_ino, fst.st_size, fst.st_mtime)}) else: continue dirs.extend(newcached['dirs']) newdircache[path] = newcached for item in items: for key in dircache.keys(): if key.startswith(item): del dircache[key] dircache.update(newdircache) if hasattr(dircache, 'close'): dircache.close() albums = {} dirs = {} trackids = {} for t in tracks: t.sortkey = t.meta.evaluate(sortby) albums.setdefault(t.meta.evaluate(groupby), []).append(t) dirs.setdefault(os.path.split(t.filename)[0], []).append(t) t.tid = t.meta.evaluate(trackid) if t.tid in trackids: print "trackid collision" print t.filename print trackids[t.tid].filename trackids[t.tid] = t #trying not to evaluate sort expressions for every comparison. don't modify #metadata during sort. ;) for v in albums.itervalues(): v.sort(lambda x, y: cmp(x.sortkey, y.sortkey)) for v in dirs.itervalues(): v.sort(lambda x, y: cmp(x.sortkey, y.sortkey)) return albums, dirs, trackids