scanner.py now stores a cached of File objects in .audiomangler/cache - approximately...
[audiomangler.git] / audiomangler / cli.py
blobce66ac623ab2ce83eb615182a4a9b50e7eae5bdf
1 ###########################################################################
2 # Copyright (C) 2008 by Andrew Mahone
3 # <andrew.mahone@gmail.com>
5 # Copyright: See COPYING file that comes with this distribution
7 ###########################################################################
8 import sys
9 import getopt
10 import shutil
11 import os
12 import os.path
13 import errno
14 from audiomangler import scan, Config, util, sync_sets, get_codec
16 def parse_options(args = None, options = []):
17 if args is None and len(sys.argv) == 1:
18 print_usage(options)
19 sys.exit(0)
20 if args == None:
21 args = sys.argv[1:]
22 name_map = {}
23 s_opts = []
24 l_opts = []
25 for (s_opt, l_opt, name, desc) in options:
26 if s_opt:
27 name_map['-'+s_opt.rstrip(':')] = name
28 s_opts.append(s_opt)
29 if l_opt:
30 name_map['--'+l_opt.rstrip('=')] = name
31 l_opts.append(l_opt)
32 s_opts = ''.join(s_opts)
33 try:
34 (opts, args) = getopt.getopt(args,s_opts,l_opts)
35 except getopt.GetoptError:
36 print_usage(options)
37 sys.exit(0)
38 for k,v in opts:
39 k = name_map[k]
40 Config[k] = v
41 return args
43 def print_usage(opts):
44 print """usage:
45 %s [options] [files or directories to process]
47 options:""" % sys.argv[0]
48 for short,long_,name,desc in opts:
49 print " -%s, --%-10s %s" %(short.rstrip(':'),long_.rstrip('='),desc)
51 common_opts = (
52 ('b:','base=','base','base directory for target files'),
53 ('p:','profile=','profile','profile to load settings from'),
54 ('f:','filename=','filename','format for target filenames'),
57 rename_opts = common_opts
58 def rename(args = None):
59 args = parse_options(args, rename_opts)
60 (album_list, dir_list) = scan(args)
61 for (dir_,files) in dir_list.items():
62 print "from dir %s:" % dir_
63 dstdirs = set()
64 moves = []
65 for file_ in files:
66 src = file_.filename
67 dst = file_.format()
68 if src == dst:
69 print " skipping %s, already named correctly" % src
70 continue
71 print " %s -> %s" % (src, dst)
72 dstdir = os.path.split(dst)[0]
73 if dstdir not in dstdirs and dstdir != dir_:
74 try:
75 os.makedirs(dstdir)
76 except OSError, e:
77 if e.errno != errno.EEXIST or not os.path.isdir(dstdir):
78 raise
79 dstdirs.add(dstdir)
80 util.move(src,dst)
81 if len(dstdirs) == 1:
82 dstdir = dstdirs.pop()
83 for file_ in os.listdir(dir_):
84 src = os.path.join(dir_,file_)
85 dst = os.path.join(dstdir,file_)
86 print " %s -> %s" % (src,dst)
87 shutil.move(src,dst)
88 while len(os.listdir(dir_)) == 0:
89 print " removing empty directory: %s" % dir_
90 try:
91 os.rmdir(dir_)
92 except Exception:
93 break
94 newdir = os.path.split(dir_)[0]
95 if newdir != dir_:
96 dir_ = newdir
97 else:
98 break
100 sync_opts = common_opts + (
101 ('t:','type=','type','type of audio to encode to'),
102 ('s:','preset=','preset','codec preset to use'),
103 ('e:','encopts=','encopts','encoder options to use'),
104 ('j:','jobs=','jobs','number of jobs to run'),
106 def sync(args = None):
107 args = parse_options(args, sync_opts)
108 (album_list, dir_list) = scan(args)[:2]
109 targettids = scan(Config['base'])[2]
110 sync_sets(album_list.values(),targettids)
112 replaygain_opts = common_opts[:2]
113 def replaygain(args = None):
114 args = parse_options(args, sync_opts)
115 if not args:
116 args = (Config['base'],)
117 (album_list) = scan(args)[0]
118 for album in album_list.values():
119 profiles = set()
120 for track in album:
121 profiles.add((
122 getattr(track,'type_',None),
123 getattr(getattr(track,'info',None),'sample_rate',None),
124 getattr(getattr(track,'info',None),'channels',None)
126 if len(profiles) != 1:
127 continue
128 profile = profiles.pop()
129 if profile[1] not in (8000,11025,12000,16000,22050,24,32,44100,48000):
130 continue
131 codec = get_codec(profile[0])
132 print codec
133 if not codec or not codec._replaygain:
134 continue
135 codec.add_replaygain([t.filename for t in album])
137 __all__ = ['rename']