#!/usr/bin/env python # Module for retrieving CDDB v1 data from CDDB servers via HTTP # Written 17 Nov 1999 by Ben Gertzfield # This work is released under the GNU GPL, version 2 or later. # Release version 1.3 # CVS ID: $Id: CDDB.py,v 1.4 2004/11/14 19:26:38 dischi Exp $ import urllib, string, socket, os, struct, re name = 'CDDB.py' version = 1.3 if os.environ.has_key('EMAIL'): (default_user, hostname) = string.split(os.environ['EMAIL'], '@') else: try: default_user = os.geteuid() or os.environ['USER'] or 'user' except: default_user = 'user' hostname = socket.gethostname() or 'host' proto = 4 default_server = 'http://freedb.freedb.org/~cddb/cddb.cgi' def query(track_info, server_url=default_server, user=default_user, host=hostname, client_name=name, client_version=version, trying=0): disc_id = track_info[0] num_tracks = track_info[1] query_str = (('%08lx %d ') % (long(disc_id), num_tracks)) for i in track_info[2:]: query_str = query_str + ('%d ' % i) query_str = urllib.quote_plus(string.rstrip(query_str)) url = "%s?cmd=cddb+query+%s&hello=%s+%s+%s+%s&proto=%i" % \ (server_url, query_str, user, host, client_name, client_version, proto) response = urllib.urlopen(url) # Four elements in header: status, category, disc-id, title header = string.split(string.rstrip(response.readline()), ' ', 3) try: header[0] = string.atoi(header[0]) except: if trying > 10: return [ 900, None ] return query(track_info, default_server, default_user, hostname, name, version, trying+1) if header[0] == 200: # OK result = { 'category': header[1], 'disc_id': header[2], 'title': header[3] } return [ header[0], result ] elif header[0] == 211 or header[0] == 210: # multiple matches result = [] for line in response.readlines(): line = string.rstrip(line) if line == '.': # end of matches break # otherwise: # split into 3 pieces, not 4 # (thanks to bgp for the fix!) match = string.split(line, ' ', 2) result.append({ 'category': match[0], 'disc_id': match[1], 'title': match[2] }) return [ header[0], result ] else: return [ header[0], None ] def read(category, disc_id, server_url=default_server, user=default_user, host=hostname, client_name=name, client_version=version, trying=0): url = "%s?cmd=cddb+read+%s+%s&hello=%s+%s+%s+%s&proto=%i" % \ (server_url, category, disc_id, user, host, client_name, client_version, proto) response = urllib.urlopen(url) header = string.split(string.rstrip(response.readline()), ' ', 3) try: header[0] = string.atoi(header[0]) except: if trying > 10: return [ 900, None ] return read(category, disc_id, default_server, user, host, client_name, client_version, trying+1) if header[0] == 210 or header[0] == 417: # success or access denied reply = [] for line in response.readlines(): line = string.rstrip(line) if line == '.': break; line = string.replace(line, r'\t', "\t") line = string.replace(line, r'\n', "\n") line = string.replace(line, r'\\', "\\") reply.append(line) if header[0] == 210: # success, parse the reply return [ header[0], parse_read_reply(reply) ] else: # access denied. :( return [ header[0], reply ] else: return [ header[0], None ] def parse_read_reply(comments): len_re = re.compile(r'#\s*Disc length:\s*(\d+)\s*seconds') revis_re = re.compile(r'#\s*Revision:\s*(\d+)') submit_re = re.compile(r'#\s*Submitted via:\s*(.+)') keyword_re = re.compile(r'([^=]+)=(.*)') result = {} for line in comments: keyword_match = keyword_re.match(line) if keyword_match: (keyword, data) = keyword_match.groups() if result.has_key(keyword): result[keyword] = result[keyword] + data else: result[keyword] = data continue len_match = len_re.match(line) if len_match: result['disc_len'] = int(len_match.group(1)) continue revis_match = revis_re.match(line) if revis_match: result['revision'] = int(revis_match.group(1)) continue submit_match = submit_re.match(line) if submit_match: result['submitted_via'] = submit_match.group(1) continue return result