diff options
author | Martin Michlmayr <tbm@cyrius.com> | 2006-02-05 20:24:07 +0100 |
---|---|---|
committer | Martin Michlmayr <tbm@cyrius.com> | 2006-02-05 20:24:07 +0100 |
commit | 97d87e1fa0808cf747bf0a4fe3b39d1cbdb5efc8 (patch) | |
tree | c817c2371ea765b6fd6f9e47f4985209dd1937dd /jack_freedb.py |
Import jack_3.1.1+cvs20050801.orig.tar.gz
[dgit import orig jack_3.1.1+cvs20050801.orig.tar.gz]
Diffstat (limited to 'jack_freedb.py')
-rw-r--r-- | jack_freedb.py | 809 |
1 files changed, 809 insertions, 0 deletions
diff --git a/jack_freedb.py b/jack_freedb.py new file mode 100644 index 0000000..f53fde7 --- /dev/null +++ b/jack_freedb.py @@ -0,0 +1,809 @@ +### jack_freedb: freedb server for use in +### jack - extract audio from a CD and encode it using 3rd party software +### Copyright (C) 1999-2003 Arne Zellentin <zarne@users.sf.net> + +### This program is free software; you can redistribute it and/or modify +### it under the terms of the GNU General Public License as published by +### the Free Software Foundation; either version 2 of the License, or +### (at your option) any later version. + +### This program is distributed in the hope that it will be useful, +### but WITHOUT ANY WARRANTY; without even the implied warranty of +### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +### GNU General Public License for more details. + +### You should have received a copy of the GNU General Public License +### along with this program; if not, write to the Free Software +### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import urllib2, urllib +import string +import sys +import os +import locale +import codecs +import tempfile +import shutil +import re + +import jack_playorder +import jack_functions +import jack_progress +import jack_utils + +from jack_version import prog_version, prog_name +from jack_globals import * + +names_available = None # freedb info is available +dir_created = None # dirs are only renamed if we have created them +NUM, LEN, START, COPY, PRE, CH, RIP, RATE, NAME = range(9) + +freedb_servers = { + 'freedb': { + 'host': "freedb.freedb.org", + 'id': prog_name + " " + prog_version, + 'mail': "freedb-submit@freedb.org", + 'my_mail': "default" + }, + 'freedb-de': { + 'host': "de.freedb.org", + 'id': prog_name + " " + prog_version, + 'mail': "freedb-submit@freedb.org", + 'my_mail': "default" + }, +} + +def interpret_db_file(all_tracks, freedb_form_file, verb, dirs = 0, warn = None): + "read freedb file and rename dir(s)" + global names_available, dir_created + freedb_rename = 0 + if warn == None: + err, track_names, locale_names, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, freedb_form_file, verb = verb) + else: + err, track_names, locale_names, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, freedb_form_file, verb = verb, warn = warn) + if (not err) and dirs: + freedb_rename = 1 + +# The user wants us to use the current dir, unconditionally. + + if cf['_claim_dir']: + dir_created = jack_utils.split_dirname(os.getcwd())[-1] + jack_functions.progress("all", "mkdir", dir_created) + cf['_claim_dir'] = 0 + + if cf['_rename_dir'] and dir_created: + new_dirs, new_dir = jack_utils.mkdirname(track_names, cf['_dir_template']) + old_dir = os.getcwd() + old_dirs = jack_utils.split_dirname(old_dir) + dirs_created = jack_utils.split_dirname(dir_created) + +# only do the following if we are where we think we are and the dir has to be +# renamed. + + if jack_utils.check_path(dirs_created, old_dirs) and not jack_utils.check_path(dirs_created, new_dirs): + jack_utils.rename_path(dirs_created, new_dirs) + print "Info: cwd now", os.getcwd() + jack_functions.progress("all", 'ren', dir_created + "-->" + unicode(new_dir, cf['_charset'])) + + if not err: + names_available = 1 + else: + freedb_rename = 0 + return err, track_names, locale_names, freedb_rename, revision +#/ end of interpret_db_file /# + +def local_freedb(cd_id, freedb_dir, outfile = "/tmp/testfilefreedb"): + "Use file from local freedb directory" + # Moritz Moeller-Herrmann kindly provided this functionality. + if not os.path.isdir(freedb_dir): + error("freedb directory not found") + if not os.access(freedb_dir, 5): + error("freedb directory access not permitted") + cat=[freedb_dir] # category listing + for entry in os.listdir(freedb_dir): + if os.path.isdir(os.path.join(freedb_dir, entry)): + cat.append(os.path.join(freedb_dir, entry)) + for musicdir in cat: + for m in os.listdir(musicdir): + if m == cd_id: + idfile = os.path.join(musicdir, cd_id) + inf = open (idfile, "r") + outf = open (outfile, "w") + buf = inf.readline() + while buf: + buf = string.replace(buf, "\n", "") # we need trailing spaces + if buf != ".": + outf.write(buf + "\n") + buf = inf.readline() + inf.close() + outf.close() + return 0 + print "No local matching freedb entry found" + return 1 + +def freedb_sum(n): + "belongs to freedb_id" + ret = 0 + while n > 0: + ret = ret + (n % 10) + n = n / 10 + return ret + +def freedb_id(tracks, warn=0): + from jack_globals import START, MSF_OFFSET, CDDA_BLOCKS_PER_SECOND + "calculate freedb (aka CDDB) disc-id" + cdtoc = [] + if not tracks: + if warn: + warning("no tracks! No disc inserted? No/wrong ripper?") + return 0 + for i in tracks: + cdtoc.append(jack_functions.blockstomsf(i[START] + MSF_OFFSET)) + cdtoc.append(jack_functions.blockstomsf(tracks[-1][START] + tracks[-1][LEN])) + + n = t = 0 + for i in tracks: + n = n + freedb_sum((i[START] + MSF_OFFSET) / CDDA_BLOCKS_PER_SECOND) + t = (tracks[-1][START] + tracks[-1][LEN]) / CDDA_BLOCKS_PER_SECOND - tracks[0][START] / CDDA_BLOCKS_PER_SECOND + + return "%08x" % ((n % 0xff << long(24)) | (t << 8) | (len(tracks))) + +def freedb_split(field, s, max = 78): + "split a field into multiple lines of 78 char max." + x = "" + s = field + "=" + s + while len(s) > max: + x = x + s[:max] + "\n" + s = field + "=" + s[max:] + return x + s + "\n" + +def freedb_template(tracks, names = "", revision = 0): + "generate a freedb submission template" + if os.path.exists(cf['_freedb_form_file']): + os.rename(cf['_freedb_form_file'], cf['_freedb_form_file'] + ".bak") + f = open(cf['_freedb_form_file'], "w") + f.write("# xmcd CD database file\n#\n# Track frame offsets:\n") + for i in tracks: + f.write("# " + `i[START] + MSF_OFFSET` + "\n") + f.write("#\n# Disc length: " + `(MSF_OFFSET + tracks[-1][START] + tracks[-1][LEN]) / CDDA_BLOCKS_PER_SECOND`) + f.write(" seconds\n#\n# Revision: %i\n" % revision) + f.write("# Submitted via: " + prog_name + " " + prog_version + "\n#\n") + f.write("DISCID=" + freedb_id(tracks) + "\n") + if names: + if names[1][0]: # various + if string.find(string.upper(names[0][0]), "VARIOUS") >= 0: + f.write(freedb_split("DTITLE", "Various / " + names[0][1])) + else: + f.write(freedb_split("DTITLE", "Various / " + names[0][0] + " - " + names[0][1])) + else: + f.write(freedb_split("DTITLE", names[0][0] + " / " + names[0][1])) + else: + f.write("DTITLE=\n") + for i in tracks: + if names: + if names[i[NUM]][0]: # various + f.write( + freedb_split("TTITLE" + `i[NUM]-1`, + names[i[NUM]][0] + + " - " + + names[i[NUM]][1] + ) + ) + else: + f.write(freedb_split("TTITLE" + `i[NUM]-1`, names[i[NUM]][1])) + else: + f.write("TTITLE" + `i[NUM]-1` + "=\n") + freedb_year, freedb_id3genre = -1, -1 + if cf['_id3_genre'] >= 0 and cf['_id3_genre'] < len(id3genres) or cf['_id3_genre'] == 255: + freedb_id3genre = cf['_id3_genre'] + elif names and len(names[0]) == 4: + freedb_id3genre = names[0][3] + if cf['_id3_year'] >= 0: + freedb_year = cf['_id3_year'] + elif names and len(names[0]) == 4: + freedb_year = names[0][2] + if freedb_year >= 0 or freedb_id3genre >= 0: + f.write("EXTD=\\nYEAR: %4s ID3G: %3s\n" % (freedb_year, freedb_id3genre)) + else: + f.write("EXTD=\n") + for i in tracks: + f.write("EXTT" + `i[NUM]-1` + "=\n") + f.write("PLAYORDER=\n") + +def freedb_query(cd_id, tracks, file): + if cf['_freedb_dir']: + if local_freedb(cd_id, cf['_freedb_dir'], file)==0: # use local database (if any) + return 0 + + qs = "cmd=cddb query " + cd_id + " " + `len(tracks)` + " " # query string + for i in tracks: + qs = qs + `i[START] + MSF_OFFSET` + " " + qs = qs + `(MSF_OFFSET + tracks[-1][START] + tracks[-1][LEN]) / CDDA_BLOCKS_PER_SECOND` + hello = "hello=" + cf['_username'] + " " + cf['_hostname'] + " " + freedb_servers[cf['_freedb_server']]['id'] + qs = urllib.quote_plus(qs + "&" + hello + "&proto=6", "=&") + url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + qs + if cf['_cont_failed_query']: + try: + f = urllib2.urlopen(url) + except IOError: + traceback.print_exc() + err = 1 + return err + else: + f = urllib2.urlopen(url) + buf = f.readline() + if buf and buf[0:1] == "2": + if buf[0:3] in ("210", "211"): # Found inexact or multiple exact matches, list follows + print "Found the following matches. Choose one:" + num = 1 + matches = [] + while 1: + buf = f.readline() + try: + buf = unicode(buf, "utf-8") + except UnicodeDecodeError: + buf = unicode(buf, "latin-1") + if not buf: + break + buf = string.rstrip(buf) + if buf != ".": + print "%2i" % num + ".) " + buf.encode(locale.getpreferredencoding(), "replace") + matches.append(buf) + num = num + 1 + x = -1 + while x < 0 or x > num - 1: + input = raw_input(" 0.) none of the above: ") + if not input: + continue + try: + x = int(input) + except ValueError: + x = -1 # start the loop again + if not x: + print "ok, aborting." + sys.exit() + + buf = matches[x-1] + buf = string.split(buf, " ", 2) + freedb_cat = buf[0] + cd_id = buf[1] + err = 0 + + elif buf[0:3] == "200": + buf = string.split(buf) + freedb_cat = buf[1] + elif buf[0:3] == "202": + if cf['_cont_failed_query']: + warning(buf + f.read() + " How about trying another --server?") + err = 1 + return err + else: + error(buf + f.read() + " How about trying another --server?") + else: + if cf['_cont_failed_query']: + warning(buf + f.read() + " --don't know what to do, aborting query.") + err = 1 + return err + else: + error(buf + f.read() + " --don't know what to do, aborting query.") + + cmd = "cmd=cddb read " + freedb_cat + " " + cd_id + url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + urllib.quote_plus(cmd + "&" + hello + "&proto=6", "=&") + f = urllib2.urlopen(url) + buf = f.readline() + if buf and buf[0:3] == "210": # entry follows + if os.path.exists(file): + os.rename(file, file + ".bak") + of = open(file, "w") + buf = f.readline() + while buf: + buf = string.rstrip(buf) + if buf != ".": + of.write(buf + "\n") + buf = f.readline() + of.close() + jack_functions.progress("all", "freedb_cat", freedb_cat) + jack_progress.status_all['freedb_cat'] = freedb_cat + err = 0 + else: + print string.rstrip(buf) + print f.read() + warning("could not query freedb entry") + err = 1 + f.close() + else: + print string.rstrip(buf) + print f.read() + warning("could not check freedb category") + err = 2 + f.close() + return err + +def freedb_names(cd_id, tracks, name, verb = 0, warn = 1): + "returns err, [(artist, albumname), (track_01-artist, track_01-name), ...], cd_id, revision" + err = 0 + tracks_on_cd = tracks[-1][NUM] + freedb = {} + f = open(name, "r") # first the freedb info is read in... + while 1: + line = f.readline() + if not line: + break + try: + line = unicode(line, "utf-8") + except UnicodeDecodeError: + line = unicode(line, "latin-1") + line = string.replace(line, "\n", "") # cannot use rstrip, we need trailing + # spaces + line = string.replace(line, "\r", "") # I consider "\r"s as bugs in db info + if jack_functions.starts_with(line, "# Revision:"): + revision = int(line[11:]) + for i in ["DISCID", "DTITLE", "TTITLE", "EXTD", "EXTT", "PLAYORDER"]: + if jack_functions.starts_with(line, i): + buf = line + if string.find(buf, "=") != -1: + buf = string.split(buf, "=", 1) + if buf[1]: + if freedb.has_key(buf[0]): + if buf[0] == "DISCID": + freedb[buf[0]] = freedb[buf[0]] + ',' + buf[1] + else: + freedb[buf[0]] = freedb[buf[0]] + buf[1] + else: + freedb[buf[0]] = buf[1] + continue + + for i in tracks: # check that info is there for all tracks + if not freedb.has_key("TTITLE%i" % (i[NUM] - 1)): # -1 because freedb starts at 0 + err = 1 + if verb: + warning("no freedb info for track %02i (\"TTITLE%i\")" % (i[NUM], i[NUM] - 1)) + freedb["TTITLE%i" % (i[NUM] - 1)] = "[not set]" + + for i in freedb.keys():# check that there is no extra info + if i[0:6] == "TTITLE": + if int(i[6:]) > tracks_on_cd - 1: + err = 2 + if verb: + warning("extra freedb info for track %02i (\"%s\"), cd has only %02i tracks." % (int(i[6:]) + 1, i, tracks_on_cd)) + + if not freedb.has_key("DTITLE"): + err = 3 + if verb: + warning("freedb entry doesn't contain disc title info (\"DTITLE\").") + freedb['DTITLE'] = "[not set]" + + if not freedb.has_key("DISCID"): + err = 4 + if verb: + warning("freedb entry doesn't contain disc id info (\"DISCID\").") + read_id = "00000000" + else: + read_id = freedb['DISCID'] + read_ids = string.split(freedb['DISCID'], ",") + id_matched = 0 + for i in read_ids: + if i == cd_id: + id_matched = 1 + if not id_matched and warn: + print "Warning: calculated id (" + cd_id + ") and id from freedb file" + print " :", read_ids + print " : do not match, hopefully due to inexact match." + for i in read_ids: + for j in i: + if j not in "0123456789abcdef": + if verb: + warning("the disc's id is not 8-digit hex (\"DISCID\").") + err = 5 + if len(i) != 8: + if verb: + warning("the disc's id is not 8-digit hex (\"DISCID\").") + err = 5 + + if freedb.has_key('PLAYORDER'): + jack_playorder.order = freedb('PLAYORDER') + + dtitle = freedb['DTITLE'] + dtitle = string.replace(dtitle, " / ", "/") # kill superflous slashes + dtitle = string.replace(dtitle, "/ ", "/") + dtitle = string.replace(dtitle, " /", "/") + dtitle = string.replace(dtitle, "(unknown disc title)", "(unknown artist)/(unknown disc title)") # yukk! + if not dtitle: + dtitle = "(unknown artist)/(unknown disc title)" + if string.find(dtitle,"/") == -1: + if cf['_various'] == 1: + dtitle = "Various/" + dtitle + warning("bad disc title, using %s. Please fix and submit." % dtitle) + else: + dtitle = "(unknown artist)/" + dtitle + + names = [string.split(dtitle,"/",1)] + if freedb.has_key('EXTD'): + extra_tag_pos = string.find(freedb['EXTD'], "\\nYEAR:") + if extra_tag_pos >= 0: + try: + extd_info = freedb['EXTD'][extra_tag_pos + 7:] + extd_year, extd_id3g = string.split(extd_info, "ID3G:", 1) + extd_year, extd_id3g = int(extd_year), int(extd_id3g) + except: + print "can't handle '%s'." % freedb['EXTD'] + else: + names = [string.split(dtitle, "/", 1)] + names[0].extend([extd_year, extd_id3g]) + if names[0][0] == "(unknown artist)": + if verb: + warning("the disc's title must be set to \"artist / title\" (\"DTITLE\").") + err = 6 + + if string.upper(names[0][0]) in ("VARIOUS", "VARIOUS ARTISTS", "SAMPLER", "COMPILATION", "DIVERSE", "V.A.", "VA"): + if not cf['_various'] and not ['argv', False] in cf['various']['history']: + cf['_various'] = 1 + +# user says additional info is in the EXTT fields + + if cf['_various'] and cf['_extt_is_artist']: + for i in range(tracks_on_cd): + if freedb['EXTT'+`i`]: + names.append([freedb['EXTT'+`i`], freedb['TTITLE'+`i`]]) + else: + err = 8 + if verb: + warning("no EXTT info for track %02i." % i) + + elif cf['_various'] and cf['_extt_is_title']: + for i in range(tracks_on_cd): + if freedb['EXTT'+`i`]: + names.append([freedb['TTITLE'+`i`], freedb['EXTT'+`i`]]) + else: + err = 8 + if verb: + warning("no EXTT info for track %02i." % i) + +# we'll try some magic to separate artist and title + + elif cf['_various']: + found = [[], [], [], [], [], []] + # lenght=3 2 1 , 3 2 1 (secondary) + ignore = string.letters + string.digits + titles = [] + braces = [['"', '"'], ["'", "'"], ["(", ")"], ["[", "]"], ["{", "}"]] + +# first generate a list of track titles + + for i in range(tracks_on_cd): + titles.append(freedb['TTITLE'+`i`]) + +# now try to find a string common to all titles with length 3...1 + + for i in (3,2,1): + candidate_found = 0 + for j in range(len(titles[0])-(i-1)): + +# choose a possible candidate + + candidate = titles[0][j:j+i] + illegal_letter = 0 + for k in candidate: + if k in ignore: + +# candidate must not have characters from ignore + + illegal_letter = 1 + break + if illegal_letter: + continue + else: + candidate_found = 1 + +# if we have a candidate, check that it occurs in all titles + + if candidate_found: + all_matched = 1 + append_as_secondary = 0 + for l in titles: + matches = 0 + where = 0 + brace = 0 + for b in braces: + if b[0] in candidate: + brace = 1 + where2 = string.find(l, candidate) + len(candidate) + where = where2 + while string.find(l, b[1], where) != -1: + where = string.find(l, b[1], where) + len(candidate) + matches = matches + 1 + where = where2 + if not b[1] in candidate: + while string.find(l, candidate, where) != -1: + where = string.find(l, candidate, where) + len(candidate) + matches = matches + 1 + break # only treat the first pair of braces + if not brace: + while string.find(l, candidate, where) != -1: + matches = matches + 1 + where = string.find(l, candidate, where) + len(candidate) + if matches == 0: # not found + all_matched = 0 + break + elif matches == 1: # found exactly once + pass + else: # found multiple times + if cf['_freedb_pedantic']: + all_matched = 0 + break + else: + append_as_secondary = 1 + pass + if all_matched: + if append_as_secondary: + found[6-i].append(candidate) + else: + found[3-i].append(candidate) + +# if no candidate has been found, try one with less characters + + else: + continue + + tmp = [] + eliminate = [" "] + for i in found: + i.sort() # I'm not sure anymore why/if this is needed + i.reverse() + for j in i: + if j not in eliminate: + tmp.append(j) + found = tmp + del tmp + if found: + # FIXME: when I have time, all candidate should be associated with + # a priority. At the moment, fav_seps prefers favorites + # over secondary candidates (i.e. candidates occuring multiple + # times. EVIL! + fav_seps = [" - ", " / "] + sep = "" + for i in fav_seps: + if i in found: + sep = i + break + if not sep: + sep = found[0] + closing_brace = "" + for j in braces: + if j[0] in sep: + closing_brace = j[1] + break + for i in titles: + buf = string.split(i, sep, 1) + if closing_brace: + lenbefore = len(buf[0] + buf[1]) + buf[0] = string.replace(buf[0], closing_brace, "") + buf[1] = string.replace(buf[1], closing_brace, "") + lenafter = len(buf[0] + buf[1]) + if lenafter != lenbefore - len(closing_brace): + if verb: + warning("brace" + `j` + " does not close exactly once.") + err = 9 + + if cf['_various_swap']: + buf = [buf[1], buf[0]] + names.append(buf) + else: + err = 7 + if verb: + warning("could not separate artist and title in all TTITLEs. Try setting freedb_pedantic = 0 or use --no-various Maybe additional information is contained in the EXTT fields. check %s and use either --extt-is-artist or --extt-is-title." % cf['_freedb_form_file']) + else: + for i in range(tracks_on_cd): + buf = freedb['TTITLE'+`i`] + names.append(["", buf]) + + # append the EXTT fields to the track names + if cf['_extt_is_comment']: + for i in range(len(names[1:])): + if freedb.has_key('EXTT'+`i`) and freedb['EXTT'+`i`]: + names[i+1][1] = names[i+1][1] + " (%s)" % freedb['EXTT'+`i`] + else: + print "Warning: track %i (starting at 0) has no EXTT entry." % i + + locale_names = [] + # clean up a bit and create names for the appropriate locale: + # FIXME: this for loop doesn't actually change the variable names at all! + for i in names: + t = [] + for j in [0, 1]: + if i[j]: + i[j] = string.strip(i[j]) + while string.find(i[j], " ") != -1: + i[j] = string.replace(i[j], " ", " ") + while i[j][0] == '"' and i[j][-1] == '"': + i[j] = i[j][1:-1] + while i[j][0] == '"' and string.find(i[j][1:], '"') != -1: + i[j] = string.replace(i[j][1:], '"', '', 1) + x = i[j].encode(locale.getpreferredencoding(), "replace") + t.append(x) + locale_names.append(t) + return err, names, locale_names, read_id, revision + +def choose_cat(cat = ["blues", "classical", "country", "data", "folk", "jazz", "misc", "newage", "reggae", "rock", "soundtrack"]): + print "choose a category:" + cat.sort() + for i in range(1, len(cat)): + print "%2d" % i + ".) " + cat[i] + + x = -1 + while x < 0 or x > len(cat) - 1: + if jack_progress.status_all.has_key('freedb_cat') and jack_progress.status_all['freedb_cat'][-1] in cat: + input = raw_input(" 0.) none of the above (default='%s'): " % jack_progress.status_all['freedb_cat'][-1]) + if not input: + x = cat.index(jack_progress.status_all['freedb_cat'][-1]) + continue + else: + input = raw_input(" 0.) none of the above: ") + try: + x = int(input) + except ValueError: + x = -1 # start the loop again + + if not x: + print "ok, aborting." + sys.exit(0) + + return cat[x] + +def do_freedb_submit(file, cd_id): + import httplib + + hello = "hello=" + cf['_username'] + " " + cf['_hostname'] + " " + prog_name + " " + prog_version + print "Info: querying categories..." + url = "http://" + freedb_servers[cf['_freedb_server']]['host'] + "/~cddb/cddb.cgi?" + urllib.quote_plus("cmd=cddb lscat" + "&" + hello + "&proto=6", "=&") + f = urllib2.urlopen(url) + buf = f.readline() + if buf[0:3] == "500": + print "Info: LSCAT failed, using builtin categories..." + cat = choose_cat() + + elif buf[0:3] == "210": + cat = ["null", ] + while 1: + buf = f.readline() + if not buf: + break + buf = string.rstrip(buf) + if buf != ".": + cat.append(buf) + f.close() + cat = choose_cat(cat) + + else: + error("LSCAT failed: " + string.rstrip(buf) + f.read()) + + print "OK, using `" + cat + "'." + email = freedb_servers[cf['_freedb_server']]['my_mail'] + print "Your e-mail address is needed to send error messages to you." + x = raw_input("enter your e-mail-address [" + email + "]: ") + if x: + email = x + + info("Submitting...") + selector = '/~cddb/submit.cgi' + proxy = "" + if os.environ.has_key('http_proxy'): + proxy = os.environ['http_proxy'] + def splittype(url): + import re + _typeprog = re.compile('^([^/:]+):') + match = _typeprog.match(url) + if match: + scheme = match.group(1) + return scheme, url[len(scheme) + 1:] + return None, url + + def splithost(url): + import re + _hostprog = re.compile('^//([^/]+)(.*)$') + match = _hostprog.match(url) + if match: return match.group(1, 2) + return None, url + + type, proxy = splittype(proxy) + host, selector2 = splithost(proxy) + h = httplib.HTTP(host) + h.putrequest('POST', 'http://' + freedb_servers[cf['_freedb_server']]['host'] + selector) + else: + h = httplib.HTTP(freedb_servers[cf['_freedb_server']]['host']) + h.putrequest('POST', '/~cddb/submit.cgi') + h.putheader('Category', cat) + h.putheader('Discid', cd_id) + h.putheader('User-Email', email) + if cf['_debug']: + debug("will submit in test-mode, changes are not applied and you'll get an email which contains the data you submitted.") + h.putheader('Submit-Mode', 'test') + else: + h.putheader('Submit-Mode', 'submit') + h.putheader('Charset', 'UTF-8') + if cf['_debug']: + h.putheader('X-Cddbd-Note', 'Submission will not be applied to database if --debug is on.') + else: + h.putheader('X-Cddbd-Note', 'data submitted with ' + prog_name + ' (http://jack.sf.net)') + h.putheader('Content-Length', str(jack_utils.filesize(file))) + h.endheaders() + # The user just wrote the file with a text editor so we assume that it + # is in their locale. + f = codecs.open(file, "r", locale.getpreferredencoding()) + try: + text = f.read() + except UnicodeDecodeError: + print "The freedb file does not match your current locale. Please convert it" + print "to " + locale.getpreferredencoding() + " manually." + sys.exit(1) + h.send(text.encode("utf-8")) + f.close() + + print + + err, msg, headers = h.getreply() + f = h.getfile() + if proxy: + if err != 200: + error("proxy: " + `err` + " " + msg + f.read()) + else: + buf = f.readline() + err, msg = buf[0:3], buf[4:] + + # lets see if it worked: + if err == 404: + print "This server doesn't seem to support database submission via http." + print "consider submitting via mail (" + progname + " -m). full error:\n" + print err, msg + +def do_freedb_mailsubmit(file, cd_id): + warning("Support for freedb submission via e-mail may be dropped in future versions. Please begin to use HTTP to submit your entries (--submit)") + sendmail = '/usr/lib/sendmail -t' + #sendmail = 'cat > /tmp/jack.test.mailsubmit' + cat = choose_cat() + print "OK, using `" + cat + "'." + if string.find(freedb_servers[cf['_freedb_server']]['my_mail'], "@") >= 1 and len(freedb_servers[cf['_freedb_server']]['my_mail']) > 3: + return os.system("( echo 'To: " + freedb_servers[cf['_freedb_server']]['mail'] + "'; echo From: '" + freedb_servers[cf['_freedb_server']]['my_mail'] + "'; echo 'Subject: cddb " + cat + " " + cd_id + "' ; cat '" + file + "' ) | " + sendmail) + else: + print "please set your e-mail address. aborting..." + +def update_revision(file): + "Update the revision (and submitted-via) information in a FreeDB template" + + re_revision = re.compile(r"^#\s*Revision:\s*(\d+)") + re_agent = re.compile(r"^#\s*Submitted via:") + + tmp, tmpname = tempfile.mkstemp() + freedb_file = open(file, "r") + revision = 0 + comments = 1 + for line in freedb_file.readlines(): + rev = re_revision.match(line) + agent = re_agent.match(line) + if rev: + revision = int(rev.group(1)) + 1 + os.write(tmp, "# Revision: %d\n" % revision) + elif agent: + os.write(tmp, "# Submitted via: " + prog_name + " " + prog_version + "\n") + else: + if not line.startswith("#"): + # The 'Revisions' field is option but should be set when you + # submit a new version. Therefore, after the comments check + # whether we've seen a revision and if not write one. + if comments: + if revision == 0: + revision += 1 + os.write(tmp, "# Revision: %d\n" % revision) + comments = 0 + os.write(tmp, line) + os.close(tmp) + freedb_file.close() + try: + shutil.copyfile(tmpname, file) + except IOError: + print "Cannot copy updated template over existing one." + try: + os.unlink(tmpname) + except IOError: + print "Cannot remove temporary file %s." % tmpname + |