Skip to content

Commit 49a23ac

Browse files
committed
Add support for module dependencies for encode/decode
Also redo a bit of the main module.
1 parent 242dcdf commit 49a23ac

File tree

7 files changed

+131
-94
lines changed

7 files changed

+131
-94
lines changed

formats/ape.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@
55
import subprocess
66
from util import forkexec, copyfileobj
77

8-
required = { "encode": "mac", "decode": "mac" }
8+
required = {
9+
"encode": ["mac"],
10+
"decode": ["mac"]
11+
}
12+
913
format = "ape"
1014

1115
# return a dictionary file of the metadata
1216
# key names are based on output of vorbiscomment
1317
def getMetadata(path):
18+
# No support for APE metadata
1419
return dict()
1520

1621
# return open file object with audio stream

formats/flac.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
import subprocess
66
import util
77

8-
required = { "encode": "flac",
9-
"decode": "flac",
10-
"gettags": "metaflac" }
8+
required = {
9+
"encode": ["flac"],
10+
"decode": ["flac"],
11+
"gettags": ["metaflac"],
12+
}
13+
1114
format = "flac"
1215

1316
# return a dictionary file of the metadata

formats/mp3.py

+16-15
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,18 @@
66
import subprocess
77
from util import forkexec
88

9-
required = { "encode": "lame", "decode": "mpg321" }
9+
required = {
10+
"encode": ["lame"],
11+
"decode": ["mpg321"],
12+
"encode_module": ["eyeD3"],
13+
}
14+
1015
format = "mp3"
1116

1217
# return a dictionary file of the metadata
1318
# key names are based on output of vorbiscomment
1419
def getMetadata(path):
15-
try: import eyeD3
16-
except:
17-
sys.stderr.write("Warning: no ID3 support, please install python-eyed3")
18-
return dict()
20+
import eyeD3
1921

2022
tag = eyeD3.Tag()
2123
tag.link(path)
@@ -52,16 +54,15 @@ def encodeAudioStream(input_stream, destination, metadata=dict()):
5254
return pid
5355

5456
def tagOutputFile(path, tags):
55-
tag_bind = { 'ARTIST': 'TPE1',
56-
'TITLE': 'TIT2',
57-
'ALBUM': 'TALB',
58-
'DATE': 'TYER',
59-
'TRACKNUMBER': 'TRCK' }
60-
61-
try: import eyeD3
62-
except:
63-
print "Can't tag! Install python-eyed3."
64-
return
57+
import eyeD3
58+
59+
tag_bind = {
60+
'ARTIST': 'TPE1',
61+
'TITLE': 'TIT2',
62+
'ALBUM': 'TALB',
63+
'DATE': 'TYER',
64+
'TRACKNUMBER': 'TRCK'
65+
}
6566

6667
tag = eyeD3.Tag()
6768
tag.link(path)

formats/ogg.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@
55
import subprocess
66
import util
77

8-
required = { "encode": "oggenc",
9-
"decode": "ogg123",
10-
"gettags": "vorbiscomment" }
8+
required = {
9+
"encode": ["oggenc"],
10+
"decode": ["ogg123"],
11+
"gettags": ["vorbiscomment"],
12+
}
1113

1214
format = "ogg"
1315

formats/shn.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
import os
44
import string
55
import subprocess
6-
#from util import copyfileobj
76
from util import forkexec, copyfileobj
87

9-
required = { "encode": "shorten", "decode": "shorten" }
8+
required = { "encode": ["shorten"], "decode": ["shorten"] }
109
format = "shn"
1110

1211
# return a dictionary file of the metadata

ify.py

+94-70
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
# Local imports into current namespace
1414
from util import *
1515

16+
# XXX: Global.
17+
FORMATS = dict()
18+
1619
def process_file(path):
1720
basename, ext = os.path.splitext(path)
1821
basename = os.path.basename(path)
1922
ext = ext[1:]
20-
if formats.has_key(ext):
23+
if FORMATS.has_key(ext):
2124
# Be more vocal about this because the user passed the file in
2225
# explicitly, there's more of a chance that a botched --convert-formats
2326
# arg was at fault.
@@ -55,7 +58,7 @@ def run_encode_queue():
5558

5659
if pid in encoder_pids:
5760
# Run the tag hook.
58-
encode_plugin = formats[prefs["format"]]
61+
encode_plugin = FORMATS[prefs["format"]]
5962
encode_plugin.tagOutputFile(*encoder_pids[pid])
6063

6164
del encoder_pids[pid] # and carry on
@@ -97,18 +100,22 @@ def process_audio_file_real(from_path, to_path):
97100

98101
ify_print("[%s->%s] %s", old_ext, prefs["format"], from_path)
99102

100-
decode_plugin = formats[old_ext]
101-
try:
102-
if "decode" in decode_plugin.required and not in_path(decode_plugin.required["decode"]):
103-
raise MissingProgramError(decode_plugin.required["decode"])
104-
if "gettags" in decode_plugin.required and not in_path(decode_plugin.required["gettags"]):
105-
raise MissingProgramError(decode_plugin.required["gettags"])
106-
except MissingProgramError, error:
107-
print "Missing required external program: %s" % error.value
108-
sys.exit(1)
103+
decode_plugin = FORMATS[old_ext]
104+
for toolCheck in ('decode', 'gettags'):
105+
if toolCheck in decode_plugin.required:
106+
for tool in decode_plugin.required[toolCheck]:
107+
if not in_path(tool):
108+
raise MissingProgramError(tool)
109+
for moduleCheck in ('decode_module', 'gettags_module'):
110+
if moduleCheck in decode_plugin.required:
111+
for module in decode_plugin.required[moduleCheck]:
112+
try:
113+
__import__(module)
114+
except ImportError:
115+
raise MissingModuleError(module)
109116

110117
if not prefs["dry_run"]:
111-
encode_plugin = formats[prefs["format"]]
118+
encode_plugin = FORMATS[prefs["format"]]
112119

113120
tags = decode_plugin.getMetadata(from_path)
114121
audio = decode_plugin.getAudioStream(from_path)
@@ -151,7 +158,7 @@ def sort_alpha(a, b):
151158
process_dir(file_fullpath, os.path.join(prefix, containing_dir))
152159
elif os.path.isfile(file_fullpath):
153160
(basename, ext) = os.path.splitext(file)
154-
if ext[1:] in formats and check_want_convert(ext[1:]):
161+
if ext[1:] in FORMATS and check_want_convert(ext[1:]):
155162
process_audio_file(file_fullpath, os.path.join(prefs["destination"], prefix, containing_dir, os.path.splitext(file)[0] + "." + prefs["format"]))
156163

157164
def process(arg):
@@ -195,20 +202,20 @@ def usage():
195202
'plugin_dir': os.path.join(sys.path[0], "formats"),
196203
'concurrency': 1 }
197204

198-
try:
205+
def main(argv):
199206
shortargs = "hd:o:fqj:"
200207
longargs = ["help",
201208
"destination=",
202-
#changed from convert-formats
203-
"convert-formats=",
204-
"format=",
205-
"force",
206-
"quiet",
207-
"delete",
208-
"dry-run",
209-
"plugin-dir="]
210-
211-
opts, args = getopt.gnu_getopt(sys.argv[1:], shortargs, longargs)
209+
"convert-formats=",
210+
"format=",
211+
"force",
212+
"quiet",
213+
"delete",
214+
"dry-run",
215+
"plugin-dir="]
216+
217+
opts, args = getopt.gnu_getopt(argv[1:], shortargs, longargs)
218+
212219
for (option, arg) in opts:
213220
if option == "--help" or option == "-h":
214221
usage()
@@ -240,52 +247,69 @@ def usage():
240247
elif False in [os.path.exists(file) for file in args]:
241248
raise getopt.GetoptError("One or more input files does not exist!")
242249

243-
# build formats data structure
244-
formats = dict()
250+
# build FORMATS data structure
251+
for path in os.listdir(prefs["plugin_dir"]):
252+
path = os.path.join(prefs["plugin_dir"], path)
253+
if os.path.isfile(path):
254+
name, ext = os.path.splitext(os.path.basename(path))
255+
file = open(path, "r")
256+
if ext == ".py":
257+
# ify_print ("Loading module %s...", name)
258+
plugin = imp.load_source(name, path, file)
259+
FORMATS[plugin.format] = plugin
260+
elif ext == ".pyc":
261+
pass
262+
else:
263+
ify_print("Can't load plugin %s, bad suffix \"%s\"", path,
264+
ext)
265+
file.close()
266+
if not prefs['format'] in FORMATS:
267+
raise getopt.GetoptError("Format must be one of: %s" %
268+
', '.join(FORMATS.keys()))
269+
# Now that format is validated, check that required programs are
270+
# available for encoding
271+
req = FORMATS[prefs['format']].required
272+
273+
for toolCheck in ('encode',):
274+
if toolCheck in req:
275+
for tool in req[toolCheck]:
276+
if not in_path(tool):
277+
raise MissingProgramError(tool)
278+
for moduleCheck in ('encode_module',):
279+
if moduleCheck in req:
280+
for module in req[moduleCheck]:
281+
try:
282+
__import__(module)
283+
except ImportError:
284+
raise MissingModuleError(module)
285+
286+
for arg in args:
287+
process(arg)
288+
289+
try: run_encode_queue()
290+
except KeyboardInterrupt:
291+
for job in encoder_pids.values():
292+
print "[deleted] %s" % job[0]
293+
os.unlink(job[0])
294+
sys.exit(1)
245295

296+
if __name__ == '__main__':
246297
try:
247-
for path in os.listdir(prefs["plugin_dir"]):
248-
path = os.path.join(prefs["plugin_dir"], path)
249-
if os.path.isfile(path):
250-
name, ext = os.path.splitext(os.path.basename(path))
251-
file = open(path, "r")
252-
if ext == ".py":
253-
# ify_print ("Loading module %s...", name)
254-
plugin = imp.load_source(name, path, file)
255-
formats[plugin.format] = plugin
256-
elif ext == ".pyc":
257-
pass
258-
else:
259-
ify_print("Can't load plugin %s, bad suffix \"%s\"", path,
260-
ext)
261-
file.close()
262-
if not prefs['format'] in formats:
263-
raise getopt.GetoptError("Format must be one of {%s}" %
264-
string.join(formats.keys()))
265-
# Now that format is validated, check that required programs are
266-
# available for encoding
267-
req = formats[prefs['format']].required
268-
if 'encode' in req and not in_path(req['encode']):
269-
raise MissingProgramError(req['encode'])
270-
271-
except MissingProgramError, error:
272-
print "Missing required external program: %s" % error
298+
main(sys.argv)
299+
except getopt.GetoptError, error:
300+
if error.opt:
301+
print "Error parsing option %s: %s" % (error.opt, error.msg)
302+
else:
303+
print "Error reading command line options: %s\n" % error.msg
304+
305+
print "List of accepted arguments:"
306+
usage()
307+
sys.exit(1)
308+
except MissingModuleError, module:
309+
print 'Missing Python module: %s' % module
310+
print 'Install it through your package manager and try again.'
311+
sys.exit(1)
312+
except MissingProgramError, prog:
313+
print 'Missing encode/decode program: %s' % prog
314+
print 'Install it through your package manager and try again.'
273315
sys.exit(1)
274-
except ImportError, error:
275-
print "Import error has occured: %r" % error.args
276-
277-
except getopt.GetoptError, error:
278-
print "Error parsing arguments: %s %s\n" % (error.opt, error.msg)
279-
print "List of accepted arguments:"
280-
usage()
281-
sys.exit(1)
282-
283-
for arg in args:
284-
process(arg)
285-
286-
try: run_encode_queue()
287-
except KeyboardInterrupt:
288-
for job in encoder_pids.values():
289-
print "[deleted] %s" % job[0]
290-
os.unlink(job[0])
291-
sys.exit(1)

util.py

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
class MissingProgramError(Exception):
77
pass
88

9+
class MissingModuleError(Exception):
10+
pass
11+
912
# Yoinked from Christopher Lenz at
1013
# http://bitten.cmlenz.net/browser/trunk/bitten/util/md5sum.py
1114
def getchecksum(filename):

0 commit comments

Comments
 (0)