1 # -*- coding: utf-8 -*-
2 ###########################################################################
3 # Copyright (C) 2008 by Andrew Mahone
4 # <andrew.mahone@gmail.com>
6 # Copyright: See COPYING file that comes with this distribution
8 ###########################################################################
15 from audiomangler
import from_config
, NormMetaData
, Expr
16 from mutagen
import File
17 from mutagen
import version
as mutagen_version
20 db_version
= (mutagen_version
, (0,0))
22 def scan_track(path
, from_dir
= ''):
26 except Exception: pass
29 t
.relpath
= t
.filename
.replace(from_dir
,'',1).lstrip('/')
30 t
.reldir
= t
.relpath
.rsplit('/',1)
32 t
.reldir
= t
.reldir
[0]
37 def scan(items
, groupby
= None, sortby
= None, trackid
= None):
38 groupbytxt
, sortbytxt
, trackidtxt
= from_config('groupby', 'sortby', 'trackid')
39 groupby
= Expr(groupby
or groupbytxt
)
40 sortby
= Expr(sortby
or sortbytxt
)
41 trackid
= Expr(trackid
or trackidtxt
)
42 homedir
= os
.getenv('HOME')
43 if homedir
is not None:
44 cachefile
= os
.path
.join(homedir
,'.audiomangler')
49 cachefile
= os
.path
.join(cachefile
,'cache')
51 cachefile
= 'audiomangler.cache'
55 dircache
= shelve
.open(cachefile
,protocol
=2)
58 if dircache
.get('//version',None) != db_version
:
60 dircache
['//version'] = db_version
61 if isinstance(items
,basestring
):
66 items
= map(os
.path
.abspath
, items
)
81 print "unable to stat dir %s" % path
83 cached
= dircache
.get(path
,None)
84 if cached
and cached
['key'] == (dst
.st_ino
, dst
.st_mtime
):
88 for track
in cached
['tracks']:
90 fst
= os
.stat(track
['path'])
93 if track
['key'] == (fst
.st_ino
, fst
.st_size
, fst
.st_mtime
):
94 newtracks
.append(track
)
96 t
._meta
_cache
= (False,False)
97 t
.relpath
= t
.filename
.replace(item
,'',1).lstrip('/')
98 t
.reldir
= t
.relpath
.rsplit('/',1)
100 t
.reldir
= t
.reldir
[0]
105 t
= scan_track(track
['path'])
108 newtracks
.append({'path':track
['path'],'obj':t
,'key':(fst
.st_ino
,fst
.st_size
,fst
.st_mtime
)})
109 for file_
in cached
['files']:
111 fst
= os
.stat(file_
['path'])
114 if file_
['key'] == (fst
.st_ino
, fst
.st_size
, fst
.st_mtime
):
115 newfiles
.append(file_
)
117 t
= scan_track(file_
['path'])
120 newtracks
.append({'path':file_
['path'],'obj':t
,'key':(fst
.st_ino
,fst
.st_size
,fst
.st_mtime
)})
122 newfiles
.append({'path':file_
['path'],'key':(fst
.st_ino
,fst
.st_size
,fst
.st_mtime
)})
123 newcached
['tracks'] = newtracks
124 newcached
['files'] = newfiles
126 newcached
= {'tracks':[],'dirs':[],'files':[]}
127 newcached
['key'] = (dst
.st_ino
, dst
.st_mtime
)
128 paths
= (os
.path
.join(path
,f
) for f
in sorted(os
.listdir(path
)))
129 for filename
in paths
:
130 if filename
in scanned
:
133 scanned
.add(filename
)
134 if os
.path
.isdir(filename
):
135 newcached
['dirs'].append(filename
)
136 elif os
.path
.isfile(filename
):
138 fst
= os
.stat(filename
)
141 t
= scan_track(filename
)
144 newcached
['tracks'].append({'path':filename
,'obj':t
,'key':(fst
.st_ino
,fst
.st_size
,fst
.st_mtime
)})
146 newcached
['files'].append({'path':filename
,'key':(fst
.st_ino
,fst
.st_size
,fst
.st_mtime
)})
149 dirs
.extend(newcached
['dirs'])
150 newdircache
[path
] = newcached
152 for key
in dircache
.keys():
153 if key
.startswith(item
):
155 dircache
.update(newdircache
)
156 if hasattr(dircache
,'close'):
162 t
.sortkey
= t
.meta
.evaluate(sortby
)
163 albums
.setdefault(t
.meta
.evaluate(groupby
),[]).append(t
)
164 dirs
.setdefault(os
.path
.split(t
.filename
)[0],[]).append(t
)
165 t
.tid
= t
.meta
.evaluate(trackid
)
166 if t
.tid
in trackids
:
167 print "trackid collision"
169 print trackids
[t
.tid
].filename
171 #trying not to evaluate sort expressions for every comparison. don't modify
172 #metadata during sort. ;)
173 for v
in albums
.itervalues():
174 v
.sort(lambda x
,y
: cmp(x
.sortkey
,y
.sortkey
))
175 for v
in dirs
.itervalues():
176 v
.sort(lambda x
,y
: cmp(x
.sortkey
,y
.sortkey
))
177 return albums
, dirs
, trackids