Attached below is a patch to add UTF-8 support to jack 3.1.1. I've tested this in a Latin1 and UTF-8 locale with OGG; MP3 hasn't been tested.
-- Martin Michlmayr http://www.cyrius.com/
diff -urN site-packages.orig/jack_config.py site-packages/jack_config.py --- site-packages.orig/jack_config.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_config.py 2005-04-23 00:16:38.000000000 +0100 @@ -177,15 +177,13 @@ 'type': types.StringType, 'val': "", 'usage': "convert file names using a python method", - 'doc': r"""an example which converts to lowercase, even with non-ascii charsets (you have to specify the charset): ".decode(charset).lower().encode(charset)" """, + 'doc': r"""an example which converts to lowercase, even with non-ascii charsets: ".lower()" """, 'long': 'AUTO', }, 'charset': { 'type': types.StringType, - 'val': "latin-1", - 'usage': "charset of freedb data", - 'doc': "examples: latin-1 ascii, utf-8, ...", - 'long': 'AUTO', + 'val': "utf-8", + # for backwards compatibility only; now ignored. }, 'unusable_chars': { 'type': types.ListType, Binary files site-packages.orig/jack_config.pyc and site-packages/jack_config.pyc differ diff -urN site-packages.orig/jack_display.py site-packages/jack_display.py --- site-packages.orig/jack_display.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_display.py 2005-04-22 22:50:51.000000000 +0100 @@ -63,9 +63,9 @@ if jack_freedb.names_available: jack_term.tmod.extra_lines = jack_term.tmod.extra_lines + 1 if jack_term.term_type == "curses": - discname = jack_tag.track_names[0][0] + " - " + jack_tag.track_names[0][1] + discname = jack_tag.locale_names[0][0] + " - " + jack_tag.locale_names[0][1] else: - options_string = center_line(jack_tag.track_names[0][0] + " - " + jack_tag.track_names[0][1], fill = "- ", fill_r = " -", width = jack_term.size_x) + "\n" + center_line(options_string, fill = " ", fill_r = " ", width = jack_term.size_x) + options_string = center_line(jack_tag.locale_names[0][0] + " - " + jack_tag.locale_names[0][1], fill = "- ", fill_r = " -", width = jack_term.size_x) + "\n" + center_line(options_string, fill = " ", fill_r = " ", width = jack_term.size_x) def sig_handler(sig, frame): "signal handler and general cleanup procedure" Binary files site-packages.orig/jack_display.pyc and site-packages/jack_display.pyc differ diff -urN site-packages.orig/jack_freedb.py site-packages/jack_freedb.py --- site-packages.orig/jack_freedb.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_freedb.py 2005-04-23 01:03:12.000000000 +0100 @@ -20,6 +20,8 @@ import string import sys import os +import locale +import codecs import jack_playorder import jack_functions @@ -53,9 +55,9 @@ global names_available, dir_created freedb_rename = 0 if warn == None: - err, track_names, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, freedb_form_file, verb = verb) + 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, cd_id, revision = freedb_names(freedb_id(all_tracks), all_tracks, freedb_form_file, verb = verb, warn = warn) + 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 @@ -83,7 +85,7 @@ names_available = 1 else: freedb_rename = 0 - return err, track_names, freedb_rename, revision + return err, track_names, locale_names, freedb_rename, revision #/ end of interpret_db_file /# def local_freedb(cd_id, freedb_dir, outfile = "/tmp/testfilefreedb"): @@ -214,7 +216,7 @@ 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=3", "=&") + 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: @@ -227,8 +229,8 @@ f = urllib2.urlopen(url) buf = f.readline() if buf and buf[0:1] == "2": - if buf[0:3] == "211": # Found inexact matches, list follows - print "Found inexact matches. Choose one:" + 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: @@ -278,7 +280,7 @@ 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=3", "=&") + 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 @@ -319,6 +321,10 @@ 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 @@ -591,8 +597,11 @@ else: print "Warning: track %i (starting at 0) has no EXTT entry." % i - # clean up a bit: + 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]) @@ -602,7 +611,10 @@ 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) - return err, names, read_id, revision + 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:" @@ -634,7 +646,7 @@ 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=3", "=&") + 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": @@ -697,12 +709,20 @@ h.putheader('User-Email', email) #h.putheader('Submit-Mode', 'test') h.putheader('Submit-Mode', 'submit') - h.putheader('Charset', 'ISO-8859-1') + h.putheader('Charset', 'UTF-8') h.putheader('X-Cddbd-Note', 'Problems submitting with ' + prog_name + '? Visit jack.sf.net.') h.putheader('Content-Length', str(jack_utils.filesize(file))) h.endheaders() - f = open(file, "r") - h.send(f.read()) + # 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 Binary files site-packages.orig/jack_freedb.pyc and site-packages/jack_freedb.pyc differ diff -urN site-packages.orig/jack_init.py site-packages/jack_init.py --- site-packages.orig/jack_init.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_init.py 2005-04-23 00:48:31.000000000 +0100 @@ -78,4 +78,3 @@ pyid3lib = dummy_pyid3() -os.environ['LC_ALL'] = "C" Binary files site-packages.orig/jack_init.pyc and site-packages/jack_init.pyc differ diff -urN site-packages.orig/jack_prepare.py site-packages/jack_prepare.py --- site-packages.orig/jack_prepare.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_prepare.py 2005-04-22 22:34:31.000000000 +0100 @@ -106,7 +106,7 @@ unique_dirs.append(jack_dirs[i]) for i in unique_dirs: jack_ripstuff.all_tracks, dummy, track1_offset = jack_functions.cdrdao_gettoc(os.path.join(i, cf['_toc_file'])) - err, jack_tag.track_names, cd_id, revision = freedb_names(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, os.path.join(i, cf['_freedb_form_file']), verb = 0, warn = 0) + err, jack_tag.track_names, jack_tag.locale_names, cd_id, revision = freedb_names(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, os.path.join(i, cf['_freedb_form_file']), verb = 0, warn = 0) if err or cf['_force']:# this means freedb data is not there yet info("matching dir found: %d" % i) pid = os.fork() @@ -465,7 +465,7 @@ if not is_submittable: error("can't submit in current state, please fix jack.freedb") - err, jack_tag.track_names, cd_id, revision = jack_freedb.freedb_names(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, cf['_freedb_form_file']) + err, jack_tag.track_names, jack_tag.locale_names, cd_id, revision = jack_freedb.freedb_names(jack_freedb.freedb_id(jack_ripstuff.all_tracks), jack_ripstuff.all_tracks, cf['_freedb_form_file']) if err: error("invalid freedb file") else: @@ -492,11 +492,11 @@ jack_utils.ex_edit(cf['_freedb_form_file']) if cf['_query_on_start']: - err, jack_tag.track_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = cf['_query_on_start'], dirs = 1) + err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = cf['_query_on_start'], dirs = 1) if err: error("query on start failed to give a good freedb file, aborting.") else: - err, jack_tag.track_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = cf['_query_on_start'], warn = cf['_query_on_start']) + err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = cf['_query_on_start'], warn = cf['_query_on_start']) return freedb_rename def undo_rename(status, todo): Binary files site-packages.orig/jack_prepare.pyc and site-packages/jack_prepare.pyc differ diff -urN site-packages.orig/jack_ripstuff.py site-packages/jack_ripstuff.py --- site-packages.orig/jack_ripstuff.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_ripstuff.py 2005-04-22 22:28:03.000000000 +0100 @@ -18,6 +18,8 @@ import jack_freedb +import locale + from jack_globals import * all_tracks_orig = [] @@ -66,7 +68,8 @@ tmp = tmp + track_names[i[NUM]][0] + " - " + track_names[i[NUM]][1] else: tmp = tmp + track_names[i[NUM]][1] - printable_names[i[NUM]] = tmp + "." * (max_name_len - len(tmp)) + p_tmp = tmp.encode(locale.getpreferredencoding(), "replace") + printable_names[i[NUM]] = p_tmp + "." * (max_name_len - len(tmp)) else: if cf['_show_time']: printable_names[i[NUM]] = ("%02i " % i[NUM]) + len_tmp + "." * (max_name_len - len(i[NAME]) - 6) Binary files site-packages.orig/jack_ripstuff.pyc and site-packages/jack_ripstuff.pyc differ Binary files site-packages.orig/jack_t_curses.pyc and site-packages/jack_t_curses.pyc differ diff -urN site-packages.orig/jack_tag.py site-packages/jack_tag.py --- site-packages.orig/jack_tag.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_tag.py 2005-04-23 00:21:39.000000000 +0100 @@ -18,6 +18,7 @@ import string import os, sys +import locale import jack_functions import jack_ripstuff @@ -33,6 +34,7 @@ from jack_globals import * track_names = None +locale_names = None genretxt = None a_artist = None @@ -57,6 +59,8 @@ if jack_freedb.names_available: a_artist = track_names[0][0] a_title = track_names[0][1] + p_artist = locale_names[0][0] + p_title = locale_names[0][1] if cf['_set_id3tag'] or freedb_rename: jack_m3u.init() @@ -135,13 +139,14 @@ vf = ogg.vorbis.VorbisFile(mp3name) oggi = vf.comment() oggi.clear() - oggi.add_tag('ALBUM', a_title.decode(cf['_charset']).encode('utf-8')) + oggi.add_tag('ALBUM', a_title.encode("utf-8")) + oggi.add_tag('TRACKNUMBER', `i[NUM]`) - oggi.add_tag('TITLE', t_name.decode(cf['_charset']).encode('utf-8')) + oggi.add_tag('TITLE', t_name.encode("utf-8")) if t_artist: - oggi.add_tag('ARTIST', t_artist.decode(cf['_charset']).encode('utf-8')) + oggi.add_tag('ARTIST', t_artist.encode("utf-8")) else: - oggi.add_tag('ARTIST', a_artist.decode(cf['_charset']).encode('utf-8')) + oggi.add_tag('ARTIST', a_artist.encode("utf-8")) if cf['_id3_genre'] != -1: oggi.add_tag('GENRE', id3genres[cf['_id3_genre']]) if cf['_id3_year'] != -1: @@ -158,35 +163,41 @@ exec("newname = newname" + cf['_char_filter']) for char_i in range(len(cf['_unusable_chars'])): newname = string.replace(newname, cf['_unusable_chars'][char_i], cf['_replacement_chars'][char_i]) + oldname = i[NAME] + i[NAME] = unicode(i[NAME], "utf-8") if i[NAME] != newname: + p_newname = newname.encode(locale.getpreferredencoding(), "replace") + newname = newname.encode("utf-8", "replace") + p_mp3name = mp3name.encode(locale.getpreferredencoding(), "replace") + p_wavname = wavname.encode(locale.getpreferredencoding(), "replace") ok = 1 if os.path.exists(newname + ext): ok = 0 - print 'NOT renaming "' + mp3name + '" to "' + newname + ext + '" because dest. exists.' + print 'NOT renaming "' + p_mp3name + '" to "' + p_newname + ext + '" because dest. exists.' if cf['_keep_wavs']: - print 'NOT renaming "' + wavname + '" to "' + newname + ".wav" + '" because dest. exists.' + print 'NOT renaming "' + p_wavname + '" to "' + p_newname + ".wav" + '" because dest. exists.' elif cf['_keep_wavs'] and os.path.exists(newname + ".wav"): ok = 0 - print 'NOT renaming "' + wavname + '" to "' + newname + ".wav" + '" because dest. exists.' - print 'NOT renaming "' + mp3name + '" to "' + newname + ext + '" because WAV dest. exists.' + print 'NOT renaming "' + p_wavname + '" to "' + p_newname + ".wav" + '" because dest. exists.' + print 'NOT renaming "' + p_mp3name + '" to "' + p_newname + ext + '" because WAV dest. exists.' if ok: if not cf['_only_dae']: try: os.rename(mp3name, newname + ext) except OSError: - error('Cannot rename "%s" to "%s" (Filename is too long or has unusable characters)' % (mp3name, newname + ext)) + error('Cannot rename "%s" to "%s" (Filename is too long or has unusable characters)' % (p_mp3name, p_newname + ext)) jack_m3u.add(newname + ext) if cf['_keep_wavs']: os.rename(wavname, newname + ".wav") jack_m3u.add_wav(newname + ".wav") - jack_functions.progress(i[NUM], "ren", "%s-->%s" % (i[NAME], newname)) + jack_functions.progress(i[NUM], "ren", "%s-->%s" % (oldname, newname)) elif cf['_silent_mode']: jack_functions.progress(i[NUM], "err", "while renaming track") print if not cf['_silent_mode']: if jack_freedb.names_available: - print "Done with \"" + a_artist+ " - " + a_title + "\"." + print "Done with \"" + p_artist+ " - " + p_title + "\"." else: print "All done.", if cf['_set_id3tag'] and cf['_id3_year'] != -1: Binary files site-packages.orig/jack_tag.pyc and site-packages/jack_tag.pyc differ diff -urN site-packages.orig/jack_utils.py site-packages/jack_utils.py --- site-packages.orig/jack_utils.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_utils.py 2005-04-23 00:08:02.000000000 +0100 @@ -167,6 +167,7 @@ for i in dirs: replace_list = (("%a", names[0][0]), ("%l", names[0][1]), ("%y", `cf['_id3_year']`), ("%g", cf['_id3_genre_txt'])) x = jack_misc.multi_replace(i, replace_list, unusable_charmap) + x = x.encode("utf-8", "replace") exec("x = x" + cf['_char_filter']) dirs2.append(x) if cf['_append_year'] and len(`cf['_id3_year']`) == 4: # Y10K bug! Binary files site-packages.orig/jack_utils.pyc and site-packages/jack_utils.pyc differ diff -urN site-packages.orig/jack_workers.py site-packages/jack_workers.py --- site-packages.orig/jack_workers.py 2005-04-22 21:31:37.000000000 +0100 +++ site-packages/jack_workers.py 2005-04-22 22:50:29.000000000 +0100 @@ -55,7 +55,7 @@ default_signals() if nice_value: os.nice(nice_value) - os.execvp(args[0], args) + os.execvp(args[0], [a.encode("utf-8", "replace") for a in args]) else: data['pid'] = pid if os.uname()[0] == "Linux": Binary files site-packages.orig/jack_workers.pyc and site-packages/jack_workers.pyc differ
--- /usr/bin/jack 2005-04-01 02:54:08.000000000 +0100 +++ ./jack-3.1 2005-04-22 22:45:04.000000000 +0100 @@ -149,7 +149,7 @@ ### (10) update freedb dbfile if cf['_update_freedb']: if not jack_tag.track_names: - err, jack_tag.track_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 0) + err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 0) jack_freedb.freedb_template(jack_ripstuff.all_tracks, jack_tag.track_names, revision + 1) jack_utils.ex_edit(cf['_freedb_form_file']) info("now submit your changes if you like, using the option --submit (via http POST). Don't forget to activate your changes locally with -R") @@ -242,7 +242,7 @@ jack_display.exit() if cf['_query_when_ready'] or cf['_read_freedb_file'] or cf['_query_on_start']: - err, jack_tag.track_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 1) + err, jack_tag.track_names, jack_tag.locale_names, freedb_rename, revision = jack_freedb.interpret_db_file(jack_ripstuff.all_tracks, cf['_freedb_form_file'], verb = 1, dirs = 1) if err: error("could not read freedb file")