| 1 | #!/usr/bin/env python |
| 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 | |
| 12 | # import those needed modules. |
| 13 | |
| 14 | import os |
| 15 | import re |
| 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> |
| 27 | |
| 28 | """ |
| 29 | |
| 30 | help = """This is abcde version """ + __version__ + """ |
| 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 | |
| 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 |
| 96 | |
| 97 | def log(status,logstring): |
| 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 |
| 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: |
| 143 | log("error","file "+file+" cannot be read") |
| 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 | |
| 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: |