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 functools
import wraps
16 from audiomangler
.config
import Config
17 from audiomangler
import util
18 from audiomangler
.codecs
import sync_sets
, get_codec
19 from audiomangler
.scanner
import scan
20 from audiomangler
.task
import PoolTask
21 from audiomangler
.logging
import *
23 def parse_options(options
= []):
28 if len(sys
.argv
) == 1:
36 for (s_opt
, l_opt
, name
, desc
) in options
:
38 name_map
['-'+s_opt
.rstrip(':')] = name
41 name_map
['--'+l_opt
.rstrip('=')] = name
43 s_opts
= ''.join(s_opts
)
45 (opts
, args
) = getopt
.getopt(args
, s_opts
, l_opts
)
46 except getopt
.GetoptError
:
48 traceback
.print_exception(*sys
.exc_info())
58 def print_usage(opts
):
60 %s [options] [files or directories to process]
62 options:""" % sys
.argv
[0]
63 for short
, long_
, name
, desc
in opts
:
64 print " -%s, --%-10s %s" % (short
.rstrip(':'), long_
.rstrip('='), desc
)
67 ('b:', 'base=', 'base', 'base directory for target files'),
68 ('p:', 'profile=', 'profile', 'profile to load settings from'),
69 ('f:', 'filename=', 'filename', 'format for target filenames'),
72 @parse_options(common_opts
)
74 dir_list
= scan(args
)[1]
75 util
.test_splits(dir_list
)
76 onsplit
= Config
['onsplit']
77 for (dir_
, files
) in dir_list
.items():
78 dir_p
= util
.fsdecode(dir_
)
79 msg(consoleformat
=u
"from dir %(dir_p)s:",
80 format
="enter: %(dir_)r", dir_
=dir_
, dir_p
=dir_p
, loglevel
=INFO
)
85 dst
= util
.fsencode(file_
.format())
86 src_p
= util
.fsdecode(src
)
87 dst_p
= util
.fsdecode(dst
)
89 msg(consoleformat
=u
" skipping %(src_p)s, already named correctly",
90 format
="skip: %(src)r",
91 src_p
=srcp_p
, src
=src
, loglevel
=INFO
)
93 dstdir
= os
.path
.split(dst
)[0]
94 if dstdir
not in dstdirs
and dstdir
!= dir_
:
98 if e
.errno
!= errno
.EEXIST
or not os
.path
.isdir(dstdir
):
101 msg(consoleformat
=u
" %(src_p)s -> %(dst_p)s",
102 format
="move: %(src)r, %(dst)r",
103 src
=src
, dst
=dst
, src_p
=src_p
, dst_p
=dst_p
, loglevel
=INFO
)
105 if len(dstdirs
) == 1:
106 dstdir
= dstdirs
.pop()
107 for file_
in os
.listdir(dir_
):
108 src
= os
.path
.join(dir_
, file_
)
109 dst
= os
.path
.join(dstdir
, file_
)
110 src_p
= util
.fsdecode(src
)
111 dst_p
= util
.fsdecode(dst
)
112 msg(consoleformat
=u
" %(src_p)s -> %(dst_p)s",
113 format
="move: %(src)r, %(dst)r", src
=src
, dst
=dst
,
114 src_p
=src_p
, dst_p
=dst_p
, loglevel
=INFO
)
116 while len(os
.listdir(dir_
)) == 0:
117 dir_p
= util
.fsdecode(dir_
)
118 msg(consoleformat
=u
" remove empty directory: %(dir_p)s",
119 format
="rmdir: %(dir_)r",
120 dir_
=dir_
, dir_p
=dir_p
, loglevel
=INFO
)
125 newdir
= os
.path
.split(dir_
)[0]
131 if onsplit
== 'warn':
132 msg(consoleformat
=u
"WARNING: tracks in %(dir_p)s were placed in different directories, other files may be left in the source directory",
133 format
="split: %(dir_)r",
134 dir_
=dir_
, dir_p
=dir_p
, loglevel
=WARNING
)
136 @parse_options(common_opts
+ (
137 ('t:', 'type=', 'type', 'type of audio to encode to'),
138 ('s:', 'preset=', 'preset', 'codec preset to use'),
139 ('e:', 'encopts=', 'encopts', 'encoder options to use'),
140 ('j:', 'jobs=', 'jobs', 'number of jobs to run'),
144 (album_list
, dir_list
) = scan(args
)[:2]
145 targettids
= scan(Config
['base'])[2]
146 sync_sets(album_list
.values(), targettids
)
148 def replaygain_task_generator(album_list
):
149 for key
, album
in album_list
.items():
153 getattr(track
, 'type_', None),
154 getattr(getattr(track
, 'info', None), 'sample_rate', None),
155 getattr(getattr(track
, 'info', None), 'channels', None)
157 if len(profiles
) != 1:
159 profile
= profiles
.pop()
160 dir_
= album
[0].meta
.flat()['dir']
161 if profile
[1] not in (8000, 11025, 12000, 16000, 22050, 24, 32, 44100, 48000):
162 print "invalid bitrate for %s" % dir_
164 codec
= get_codec(profile
[0])
165 if not codec
or not codec
.has_replaygain
:
166 print "replaygain not supported for %s" % dir_
168 if reduce(lambda x
, y
: x
and y
.has_replaygain(), album
, True):
169 print "all tracks have replaygain for %s" % dir_
171 msg(consoleformat
=u
"Adding replaygain values to %(albumtitle)s",
172 format
="rg: %(tracks)r",
173 albumtitle
=album
[0].meta
.flat().get('album', '[unknown]'), tracks
=tuple(t
.filename
for t
in album
))
174 yield codec
.add_replaygain([t
.filename
for t
in album
])
176 @parse_options(common_opts
[:2] + (
177 ('j:', 'jobs=', 'jobs', 'number of jobs to run'),
180 def replaygain(*args
):
182 args
= (Config
['base'], )
183 (album_list
) = scan(args
)[0]
184 PoolTask(replaygain_task_generator(album_list
)).run()