[mp3togo] audiotags diff
Justus Pendleton
justus at ryoohki.net
Sun May 28 21:42:57 PDT 2006
Here is a patch to change mp3togo over to using the audiotags library I
posted earlier. It is actually pretty small. Most of tags.py goes away
with this change. A few functions got changed from methods to regular
functions. I've only tested it on a few mp3s this evening but it seems
to be working as expected.
-------------- next part --------------
=== modified file 'mp3togo/main.py'
--- mp3togo/main.py
+++ mp3togo/main.py
@@ -48,7 +48,6 @@
sys.exit(code)
def main(argv):
-
# Read in configuration
try:
opts = conf.Options(argv)
=== modified file 'mp3togo/tags.py'
--- mp3togo/tags.py
+++ mp3togo/tags.py
@@ -19,298 +19,66 @@
import os, sys
-import UserDict
-import threading
import mp3togo.conf as setup
# This mess needs to be fixed,
# Tags() is just going to have to
# take an Options() instance.
-try:
- import ogg.vorbis
-except ImportError:
- HAVE_VORBIS = False
-else:
- HAVE_VORBIS = True
-
-try:
- import ID3
-except ImportError:
- HAVE_ID3 = False
-else:
- HAVE_ID3 = True
-
-HAVE_METAFLAC=False
-for path in os.environ['PATH'].split(':'):
- if os.path.exists(os.path.join(path, 'metaflac')):
- HAVE_METAFLAC=True
- break
-
-
-class Tags(UserDict.DictMixin):
- """Manage per track metadata.
-
- Provide a filename in the constructor
- Call read() to read in the tags
- modify tags if necessary
- Call write(name) with the output file the tags
- are to be written to
- Tags are available through a dictionary interface
- format(fmt) returns a formatted string of metadata
- """
-
- def __init__(self, filename):
- if not os.path.exists(filename):
- raise setup.ErrorNoFile
- self._file = filename
- self._type = setup.getfiletype(filename)
- self._tags = {}
- self._readok = threading.Event()
- self._readok.clear()
- self._lock = threading.Lock()
-
-
- def read(self, block=True):
- if not self._lock.acquire(block) and not block:
- return False
- self._readok.clear()
-
- def copytags(d):
- o = {}
- for k in d.keys():
- o[k] = list(d[k])
- return o
-
- if self._type == 'mp3' and HAVE_ID3:
- info = ID3.ID3(self._file, as_tuple=1).as_dict()
- self._tags = copytags(info)
- del info
- elif self._type == 'ogg' and HAVE_VORBIS:
- info = ogg.vorbis.VorbisFile(self._file).comment().as_dict()
- self._tags = copytags(info)
- del info
- elif self._type == 'flac' and HAVE_METAFLAC:
- cmd = '%s --export-tags-to=- "%s" ' % ('metaflac', self._file)
- fd = os.popen(cmd)
- info = fd.read()
- fd.close()
- info = map(lambda x: x.split('=', 1), info.split('\n'))
- info = filter(lambda x: len(x) == 2, info)
- info = map(lambda x: [x[0].upper(), x[1:]], info)
- self._tags = dict(info)
- elif self._type == 'wav':
- pass
-
-
- # Try to guess from the file's path - better than nothing
- path = os.path.splitext(self._file)[0]
- path = path.replace('_', ' ')
- for id, depth in [('ARTIST', -3), ('ALBUM', -2), ('TITLE', -1)]:
- if not id in self._tags or self._tags[id][0] == '':
- try:
- self._tags[id] = [path.split(os.sep)[depth]]
- except IndexError:
- self._tags[id] = "%s unknown" % id.lower()
-
- self._readok.set()
- self._lock.release()
- return True
-
-
- def write(self, filename, block=True):
- if not self._lock.acquire(block) and not block:
- return False
-
- if not os.path.exists(filename):
- self._lock.release()
- raise setup.ErrorNoFile
-
- def puttags(d):
- for key in self._tags.keys(): # Not self.keys()
- if key == 'GENRE' and fmt == 'mp3':
- if type(self._tags[key][0]) is type(1) and 0 <= self._tags[key][0] < 256:
- d[key] = self._tags[key][0]
- elif self._tags[key][0] in map(str, range(256)):
- d[key] = int(self._tags[key][0])
- else:
- d[key] = int(genres.get(self._tags[key][0], '255'))
- else:
- d[key] = self._tags[key][0]
- # No! don't unlock here dumbass! return from puttags
- return d
-
- try:
- fmt = setup.getfiletype(filename)
- except setup.ErrorUnknownFileType:
- self._lock.release()
- raise
-
- if fmt == 'ogg':
- vf = ogg.vorbis.VorbisFile(filename)
- out = vf.comment()
- puttags(out)
- try:
- out.write_to(filename)
- except:
- pass
- del out
- del vf
- elif fmt == 'mp3':
- out = ID3.ID3(filename, as_tuple=1)
- puttags(out)
- try:
- out.write()
- except:
- # Tagging failed, but the file should be okay.
- pass
- del out
+
+def writeindex(tags, filename, indexname):
+ try:
+ ifile = file(indexname, 'a')
+ ifile.write(filename + "\n")
+ keys = tags.keys()
+ keys.sort()
+ for k in keys:
+ for q in tags[k]:
+ ifile.write("%s: %s\n" % (k, q))
+ ifile.write("\n")
+ ifile.close()
+ except:
+ raise
+
+ return True
+
+def format(tags, fmt):
+ """Pretty print the tag information
+
+ The following format strings apply:
+ %% Literal %
+ %n Track number
+ %a Artist
+ %t Track title
+ %l Album title
+ %y Album release year
+ %g Album genre"""
+
+ esc = {'n': 'tracknumber',
+ 'a': 'artist',
+ 't': 'title',
+ 'l': 'album',
+ 'y': 'year',
+ 'g': 'genre'}
+ #'z': Used for literal '%'
+
+ out = ""
+ fmt = fmt.replace('%%', '%z')
+ fmt = fmt.split('%')
+ while fmt:
+ out += fmt[0]
+ if len(fmt) <= 1:
+ break
+ fmt = fmt[1:]
+ code = fmt[0] and fmt[0][0]
+ if code == 'z':
+ fmt[0] = '%' + fmt[0][1:]
+ elif code in esc.keys():
+ fmt[0] = tags[esc[code]] + fmt[0][1:]
else:
- self._lock.release()
- raise setup.ErrorUnknownFileType
-
- self._lock.release()
- return True
-
-
- def writeindex(self, filename, indexname, block=True):
- if not self._lock.acquire(block) and not block:
- return False
-
- try:
- ifile = file(indexname, 'a')
- ifile.write(filename + "\n")
- keys = self._tags.keys()
- keys.sort()
- for k in keys:
- for q in self._tags[k]:
- ifile.write("%s: %s\n" % (k, q))
- ifile.write("\n")
- ifile.close()
- except:
- self._lock.release()
- raise
-
- self._lock.release()
- return True
-
- def format(self, fmt, block=True):
- """Pretty print the tag information
-
- The following format strings apply:
- %% Literal %
- %n Track number
- %a Artist
- %t Track title
- %l Album title
- %y Album release year
- %g Album genre"""
- if not self._lock.acquire(block) and not block:
- return False
-
- esc = {'n': 'TRACKNUMBER',
- 'a': 'ARTIST',
- 't': 'TITLE',
- 'l': 'ALBUM',
- 'y': 'YEAR',
- 'g': 'GENRE_NAME'}
- #'z': Used for literal '%'
-
- out = ""
- fmt = fmt.replace('%%', '%z')
- fmt = fmt.split('%')
- while fmt:
- out += fmt[0]
- if len(fmt) <= 1:
- break
- fmt = fmt[1:]
- code = fmt[0] and fmt[0][0]
- if code == 'z':
- fmt[0] = '%' + fmt[0][1:]
- elif code in esc.keys():
- fmt[0] = self._tags.get(esc[code], ('',))[0] + fmt[0][1:]
- else:
- self._lock.release()
- raise setup.ErrorBadFormat
-
- self._lock.release()
- return out
-
-
- def __getitem__(self, key, block=True):
-
- if not self._lock.acquire(block) and not block:
- return False
-
- if key == 'GENRE_NAME':
- if not self._tags.has_key('GENRE'):
- out = ''
- else:
- out = [genrenumbers.get(self._tags['GENRE'][0], self._tags['GENRE'][0])]
- else:
- try:
- out = self._tags[key.upper()]
- except KeyError:
- self._lock.release()
- raise
-
- self._lock.release()
- return out
-
-
- def __setitem__(self, key, value, block=True):
-
- if not self._lock.acquire(block) and not block:
- return False
-
- if type(value) != type([]):
- value = [value]
- self._tags[key.upper()] = value
-
- self._lock.release()
- return True
-
-
- def setorappend(self, key, value, block=True):
- if not self._lock.acquire(block) and not block:
- return False
-
- key = key.upper()
- if self._tags.has_key(key):
- self._tags[key].append(value)
- else:
- self[key] = value
-
- self._lock.release()
- return True
-
-
- def __delitem__(self, key, block=True):
- if not self._lock.acquire(block) and not block:
- return False
-
- try:
- del self._tags[key]
- except KeyError:
- self._lock.release()
- raise
-
- self._lock.release()
- return True
-
-
- def keys(self, block=True):
- if not self._lock.acquire(block) and not block:
- return False
-
- if self._tags.has_key('GENRE'):
- out = self._tags.keys() + ['GENRE_NAME']
- else:
- out = self._tags.keys()
-
- self._lock.release()
- return out
-
+ raise setup.ErrorBadFormat
+
+ return out
def remove_from_index(trackname, indexname):
"""Remove an entry from an index file."""
=== modified file 'mp3togo/track.py'
--- mp3togo/track.py
+++ mp3togo/track.py
@@ -24,6 +24,7 @@
import mp3togo.conf as setup
import mp3togo.tags as tags
+import audiotags
import mp3togo.task as task
import mp3togo.cache as cache
import mp3togo.helpers
@@ -82,8 +83,9 @@
# Read the tags
# Do this early so that 'treestructure' can access them
- self.tags = tags.Tags(filename)
- self.tags.read()
+ self.tags = audiotags.AudioFile(filename)
+ if not audiotags.supported(self.tags):
+ raise setup.UnknownFileType(filename)
# Names
filetype = setup.getfiletype(filename)
@@ -93,9 +95,9 @@
base = opts.cleanfilename(base)
if opts['treestructure'] != '':
# Standard format string
- # See tags.Tags.format.__doc__
+ # See tags.format.__doc__
fmt = opts['treestructure']
- dest = self.tags.format(fmt)
+ dest = tags.format(self.tags, fmt)
self._outdir = os.path.dirname(dest)
self._outdir = os.path.join(opts['playerdir'], self._outdir)
@@ -215,10 +217,10 @@
if opts['index']:
indexname = os.path.join(self._outdir, '2go.index')
def undo_index():
- tags.remove_from_index(self._outname, indexname)
+ tags.remove_from_index(self.tags, self._outname, indexname)
return True
def write_index():
- self.tags.writeindex(self._outname, indexname)
+ tags.writeindex(self.tags, self._outname, indexname)
return True
job = task.SimpleTask(self, write_index, None,
undo_index, name='Writing index')
@@ -229,7 +231,12 @@
# tag files from the cache as well, brwarning may have changed
if not opts['notags']:
def tag_output():
- self.tags.write(self._outname)
+ outfile = audiotags.AudioFile(self._outname)
+ if not audiotags.supported(outfile):
+ raise setup.UnknownFileType(self._outname)
+ for k in self.tags.realkeys():
+ outfile.add(k, self.tags[k])
+ outfile.write()
return True
job = task.SimpleTask(self, tag_output, None,
lambda: True, name="Tagging")
@@ -283,5 +290,3 @@
for child in self._queue:
child._parent = None
self._queue = ()
-
-
More information about the mp3togo
mailing list