1e401ac2 |
1 | #!/usr/bin/env python |
2c5ad283 |
2 | # Copyright (c) 2007 Jesus Climent <jesus.climent@hispalinux.es> |
3 | # This code is hereby licensed for public consumption under either the |
4 | # GNU GPL v2 or greater, or Larry Wall's Artistic license - your choice. |
5 | # |
6 | # You should have received a copy of the GNU General Public License along |
7 | # with this program; if not, write to the Free Software Foundation, Inc., |
8 | # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
9 | # |
10 | # $Id: abcde 232 2007-03-22 21:39:30Z data $ |
11 | |
2c5ad283 |
12 | # import those needed modules. |
13 | |
14 | import os |
15 | import re |
1e401ac2 |
16 | import sys |
17 | import time |
18 | import getopt |
19 | import string |
20 | import select |
21 | |
22 | __version__ = "1.0-$Revision$" |
23 | |
24 | """ |
25 | abcde.py - A Better CD Encoder - python release |
26 | Copyright (C) 2007 Jesus Climent <jesus.climent@hispalinux.es> |
2c5ad283 |
27 | |
1e401ac2 |
28 | """ |
2c5ad283 |
29 | |
1e401ac2 |
30 | help = """This is abcde version """ + __version__ + """ |
2c5ad283 |
31 | |
32 | usage: abcde.py [options] [tracks] |
33 | Options: |
34 | -1 Encode the whole CD in a single file |
35 | -a <action1[,action2]...> |
36 | Actions to perform: |
37 | cddb,read,normalize,encode,tag,move,replaygain,playlist,clean |
38 | -b Enable batch normalization |
39 | -c <file> |
40 | Specify a configuration file (overrides system and user config files) |
41 | -C <discid#> |
42 | Specify discid to resume from (only needed if you no longer have the cd) |
43 | -d <device> |
44 | Specify CDROM device to grab (flac uses a single-track flac file) |
45 | -D Debugging mode (equivalent to sh -x abcde) |
46 | -e Erase encoded track information from status file |
47 | -f Force operations that otherwise are considered harmful. Read "man abcde" |
48 | -g Use "lame --nogap" for MP3 encoding. Disables low disk and pipes flags |
49 | -h This help information |
50 | #-i Tag files while encoding, when possible (local only) -NWY- |
51 | -j <#> Number of encoder processes to run at once (localhost) |
52 | -k Keep the wav tracks for later use |
53 | -l Use low disk space algorithm |
54 | -L Use local CDDB storage directory |
55 | -n No lookup. Don't query CDDB, just create and use template |
56 | -N Noninteractive. Never prompt for anything |
57 | -m Modify playlist to include CRLF endings, to comply with some players |
58 | WARNING: Deprecated. Use \"cue\" action |
59 | -o <type1[,type2]...> |
60 | Output file type(s) (vorbis,mp3,flac,spx,mpc,wav,m4a). Defaults to vorbis |
61 | -p Pad track numbers with 0's (if less than 10 tracks) |
62 | -P Use UNIX pipes to read+encode without wav files |
63 | -q <level> |
64 | Set quality level (high,medium,low) |
65 | -r <host1[,host2]...> |
66 | Also encode on these remote hosts |
67 | -R Use local CDDB in recursive mode |
68 | -s <field> |
69 | Show dielfs from the CDDB info (year,genre) |
70 | -S <#> Set the CD speed |
71 | -t <#> Start the track numbering at a given number |
72 | -T <#> Same as -t but modifies tag numbering |
73 | -U Do NOT use UNICODE (UTF8) tags and comments |
74 | -v Show version number and exit |
75 | -V Be a bit more verbose about what is happening behind the scenes |
76 | -x Eject CD after all tracks are read |
77 | -w <comment> |
78 | Add a comment to the CD tracks |
79 | -W <#> Contatenate CDs: -T #01 -w "CD #" |
80 | -z Use debug CDROMREADERSYNTAX option (needs cdparanoia) |
81 | |
82 | Tracks is a space-delimited list of tracks to grab. |
83 | Ranges specified with hyphens are allowed (i.e., 1-5). |
84 | |
85 | """ |
86 | |
87 | def usage (): |
88 | print help |
89 | |
1e401ac2 |
90 | def addstatus(status,file): |
91 | try: |
92 | file = open(file, "w") |
93 | except: |
94 | log("error","file",file,"cannot be read") |
95 | return -1 |
2c5ad283 |
96 | |
97 | def log(status,logstring): |
1e401ac2 |
98 | if re.compile("info").match(status): |
99 | status = "[INFO]" |
100 | pass |
101 | elif re.compile("warning").match(status): |
102 | status = "[WARNING]" |
103 | pass |
104 | elif re.compile("error").match(status): |
105 | returncode = 1 |
106 | status = "[ERROR] %s\n" |
107 | sys.stderr.write(status % logstring) |
108 | sys.exit(1) |
109 | else: |
110 | return 1 |
2c5ad283 |
111 | |
112 | def f_seq_row (min,max): |
113 | try: |
114 | seq = range(min,max) |
115 | return seq |
116 | except: |
117 | log(error,"syntax error while processing track numbers") |
118 | return -1 |
119 | |
120 | def f_seq_line (min,max): |
121 | try: |
122 | seq = range(min,max) |
123 | return seq |
124 | except: |
125 | log(error,"syntax error while processing track numbers") |
126 | return -1 |
127 | |
128 | #usage() |
129 | |
130 | # get_first and get_last can be substituted by range[0] and range[:-1] |
131 | |
132 | # checkstatus(string) |
133 | # Returns "0" if the string was found, returns 1 if it wasn't |
134 | # Puts the blurb content, if available, on stdout. |
135 | # Otherwise, returns "". |
136 | def checkstatus (string, file): |
137 | |
138 | patern = re.compile("^"+string+"(=.*)?$") |
139 | |
140 | try: |
141 | file = open(file, "r") |
142 | except: |
1e401ac2 |
143 | log("error","file "+file+" cannot be read") |
2c5ad283 |
144 | return -1 |
145 | |
146 | blurb = [] |
147 | while 1: |
148 | line = file.readline() |
149 | if line == "": break |
150 | blurb.append(re.search(patern,line).string) |
151 | |
152 | print blurb |
153 | if blurb[-1]: |
154 | return 0 |
155 | else: |
156 | return 1 |
157 | |
1e401ac2 |
158 | # which(program) |
159 | # checks where we can find a program in the path |
160 | def which(program): |
161 | for path in string.split(os.environ["PATH"], ":"): |
162 | if os.path.exists(os.path.join(path, program)): |
163 | return os.path.join(path, program) |
164 | |
165 | |
166 | |
167 | def main(): |
168 | try: |
169 | opts, args = getopt.getopt(sys.argv[1:], "1a:bc:C:d:DefghjklLnNmopPqrRsStTUvVxwWz") |
170 | except: |
171 | log("error","unknown error") |
172 | sys.stderr.write(usage % sys.argv[0]) |
173 | sys.exit(1) |
174 | |
175 | try: |
176 | #abcde.setup() |
177 | for opt, optarg in opts: |
178 | print opt, optarg |
179 | if opt == "-1": o_onetrack = "y" |
180 | if opt == "-a": o_actions = optarg |
181 | if opt == "-b": o_batchnormalize = "y" |
182 | if opt == "-B": o_nobatchreplygain = "y" |
183 | if opt == "-c": |
184 | o_configfile = str(optarg) |
185 | try: |
186 | if not re.compile("\.\/").search(o_configfile): |
187 | o_configfile = os.environ.get("PWD", "./") + "/" + o_configfile |
188 | os.path.exists(o_configfile) |
189 | except: |
190 | log("error",o_configfile+" cannot be read") |
191 | if opt == "-C": |
192 | if re.compile("abcde\.").match(optarg): |
193 | o_discid = optarg |
194 | else: |
195 | o_discid = "abcde." + optarg |
196 | if opt == "-d": o_cdrom = optarg |
197 | if opt == "-D": o_debug = "y" |
198 | if opt == "-h": |
199 | usage() |
200 | sys.exit(1) |
201 | if opt == "-e": o_eraseencodedstatus = "y" |
202 | # if opt == "-E": o_encoding |
203 | if opt == "-f": o_force = "y" |
204 | if opt == "-g": o_nogap = "y" |
205 | if opt == "-j": o_maxprocs = optarg |
206 | if opt == "-k": o_keepwavs = "y" |
207 | if opt == "-l": o_lowdisk = "y" |
208 | if opt == "-L": o_localcddb = "y" |
209 | if opt == "-n": o_cddbavailable = "n" |
210 | if opt == "-m": o_dosplaylist = "y" |
211 | if opt == "-M": o_docue = "y" |
212 | if opt == "-N": o_interactive = "n" |
213 | if opt == "-o": o_outputtypes = optarg |
214 | if opt == "-p": o_padtracks = "y" |
215 | if opt == "-P": o_usepipes = "y" |
216 | if opt == "-q": o_qualitylevel = optarg |
217 | #if opt == "-r": o_remotehosts = optarg |
218 | if opt == "-R": o_localcddbrecursive = "y" |
219 | if opt == "-s": o_showcddbfields = "y" |
220 | if opt == "-S": o_cdspeed = optarg |
221 | if opt == "-t": o_starttracknumber = optarg |
222 | if opt == "-T": |
223 | o_starttracknumber = optarg |
224 | o_starttracknumbertag = "y" |
225 | if opt == "-U": o_cddbproto = 5 |
226 | if opt == "-v": |
227 | print "This is abcde v", __version__ |
228 | print "Usage: abcde.py [options] [tracks]" |
229 | print "abcde -h for extra help" |
230 | sys.exit(0) |
231 | if opt == "-V": o_verbose = "y" |
232 | if opt == "-x": o_eject = "y" |
233 | # if opt == "-X": o_cue2discid = optarg |
234 | if opt == "-w": o_comment = optarg |
235 | if opt == "-W": |
236 | if re.compile("^\d+$").search(optarg) |
237 | o_starttracknumber = optarg + "01" |
238 | o_starttracknumbertag = "y" |
239 | o_comment = "CD" + optarg |
240 | else: |
241 | log("error","opt -W must be an integer") |
242 | sys.exit(1) |
243 | |
244 | except: |
245 | #log("error","arguments were not correct") |
246 | pass |
247 | |
248 | |
249 | #try: |
250 | ## checkstatus("test", "/tmp/status") |
251 | # pass |
252 | #except: |
253 | # sys.exit(1) |
254 | |
255 | # ------------------------------- |
256 | if __name__ == "__main__": main() |
257 | |
258 | # b:is_python |
259 | # vim:tabstop=4: |