MP3 and TTA plugins.

This commit is contained in:
Lukáš Lalinský
2006-09-24 11:14:52 +02:00
parent b8fe58e2c1
commit 16b83ce6bf
5 changed files with 203 additions and 215 deletions

View File

@@ -20,7 +20,10 @@
from picard.api import IFileOpener
from picard.component import Component, implements
from picard.plugins.picardmutagen.asf import MutagenASFFile
from picard.plugins.picardmutagen.mp3 import MutagenMP3File
from picard.plugins.picardmutagen.id3 import (
MP3File,
TrueAudioFile,
)
from picard.plugins.picardmutagen.apev2 import (
MonkeysAudioFile,
MusepackFile,
@@ -40,8 +43,9 @@ class MutagenComponent(Component):
implements(IFileOpener)
__supported_formats = {
".mp3": (MutagenMP3File, "MPEG Layer-3"),
".mp3": (MP3File, "MPEG Layer-3"),
".mpc": (MusepackFile, "Musepack"),
".tta": (TrueAudioFile, "The True Audio"),
".wma": (MutagenASFFile, "Windows Media Audio"),
".wmv": (MutagenASFFile, "Windows Media Video"),
".asf": (MutagenASFFile, "ASF"),
@@ -52,7 +56,7 @@ class MutagenComponent(Component):
".flac": (FLACFile, "FLAC"),
".oggflac": (OggFLACFile, "Ogg FLAC"),
".spx": (OggSpeexFile, "Ogg Speex"),
".oggx": (OggVorbisFile, "Ogg Vorbis"),
".ogg": (OggVorbisFile, "Ogg Vorbis"),
}
def get_supported_formats(self):

View File

@@ -1,136 +0,0 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2006 Lukáš Lalinský
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from mutagen import id3
from picard.plugins.picardmutagen.mutagenext import compatid3
def read_id3_tags(tags, metadata):
"""Read tags from an ID3 object to Picard's metadata."""
def read_text_frame(frame_id, name):
if frame_id in tags:
metadata[name] = unicode(tags[frame_id])
def read_free_text_frame(desc, name):
frames = tags.getall("TXXX:%s" % desc)
if frames:
metadata[name] = unicode(frames[0])
read_text_frame("TPE1", "artist")
read_text_frame("TPE2", "ensemble")
read_text_frame("TPE3", "conductor")
read_text_frame("TPE4", "remixer")
read_text_frame("TCOM", "composer")
read_text_frame("TALB", "album")
read_text_frame("TIT2", "title")
read_text_frame("TEXT", "lyricist")
read_text_frame("TCMP", "compilation")
read_text_frame("TDRC", "date")
read_text_frame("XDOR", "date")
if "TRCK" in tags:
text = unicode(tags["TRCK"])
if "/" in text:
track, total = text.split("/")
metadata["tracknumber"] = track
metadata["totaltracks"] = total
else:
metadata["tracknumber"] = text
if "TPOS" in tags:
text = unicode(tags["TPOS"])
if "/" in text:
disc, total = text.split("/")
metadata["discnumber"] = disc
metadata["totaldiscs"] = total
else:
metadata["discnumber"] = text
frames = tags.getall("UFID:http://musicbrainz.org")
if frames:
metadata["musicbrainz_trackid"] = unicode(frames[0].data)
read_free_text_frame("MusicBrainz Artist Id", "musicbrainz_artistid")
read_free_text_frame("MusicBrainz Album Id", "musicbrainz_albumid")
read_free_text_frame("MusicBrainz Album Artist Id",
"musicbrainz_albumartistid")
read_free_text_frame("ALBUMARTIST", "albumartist")
frames = tags.getall("APIC")
if frames:
metadata["~artwork"] = []
for frame in frames:
metadata["~artwork"].append((frame.mime, frame.data))
def write_id3_tags(tags, metadata, encoding, v23=False):
"""Write tags from Picard's metadata to an ID3 object."""
def add_text_frame(frame_class, name):
if name in metadata:
tags.add(frame_class(encoding=encoding,
text=metadata[name]))
def add_free_text_frame(desc, name):
if name in metadata:
tags.delall("TXXX:%s" % desc.upper())
tags.add(id3.TXXX(encoding=encoding, desc=desc,
text=metadata[name]))
add_text_frame(id3.TPE1, "artist")
add_text_frame(id3.TPE2, "ensemble")
add_text_frame(id3.TPE3, "conductor")
add_text_frame(id3.TPE4, "remixer")
add_text_frame(id3.TCOM, "composer")
add_text_frame(id3.TALB, "album")
add_text_frame(id3.TIT2, "title")
add_text_frame(id3.TEXT, "lyricist")
add_text_frame(compatid3.TCMP, "compilation")
add_text_frame(id3.TDRC, "date")
if "tracknumber" in metadata:
if "totaltracks" in metadata:
text = "%s/%s" % (metadata["tracknumber"],
metadata["totaltracks"])
else:
text = metadata["tracknumber"]
tags.add(id3.TRCK(encoding=0, text=text))
if "discnumber" in metadata:
if "totaldiscs" in metadata:
text = "%s/%s" % (metadata["discnumber"],
metadata["totaldiscs"])
else:
text = metadata["discnumber"]
tags.add(id3.TPOS(encoding=0, text=text))
if "comment" in metadata:
tags.add(id3.COMM(encoding=encoding,
text=metadata["COMMENT"]))
if "musicbrainz_trackid" in metadata:
tags.add(id3.UFID(owner="http://musicbrainz.org",
data=metadata["musicbrainz_trackid"]))
add_free_text_frame("MusicBrainz Artist Id", "musicbrainz_artistid")
add_free_text_frame("MusicBrainz Album Id", "musicbrainz_albumid")
add_free_text_frame("MusicBrainz Album Artist Id",
"musicbrainz_albumartistid")
add_free_text_frame("ALBUMARTIST", "albumartist")

View File

@@ -0,0 +1,189 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2006 Lukáš Lalinský
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import mutagen.mp3
import mutagen.trueaudio
from mutagen import id3
from picard.file import File
from picard.plugins.picardmutagen.mutagenext import compatid3
from picard.util import encode_filename
class ID3File(File):
"""Generic ID3-based file."""
_File = None
def read(self):
file = self._File(encode_filename(self.filename),
ID3=compatid3.CompatID3)
if not file.tags:
file.add_tags()
tags = file.tags
metadata = self.metadata
def read_text_frame(frame_id, name):
if frame_id in tags:
metadata[name] = unicode(tags[frame_id])
def read_free_text_frame(desc, name):
frames = tags.getall("TXXX:%s" % desc)
if frames:
metadata[name] = unicode(frames[0])
read_text_frame("TPE1", "artist")
read_text_frame("TPE2", "ensemble")
read_text_frame("TPE3", "conductor")
read_text_frame("TPE4", "remixer")
read_text_frame("TCOM", "composer")
read_text_frame("TALB", "album")
read_text_frame("TIT2", "title")
read_text_frame("TEXT", "lyricist")
read_text_frame("TCMP", "compilation")
read_text_frame("TDRC", "date")
read_text_frame("XDOR", "date")
if "TRCK" in tags:
text = unicode(tags["TRCK"])
if "/" in text:
track, total = text.split("/")
metadata["tracknumber"] = track
metadata["totaltracks"] = total
else:
metadata["tracknumber"] = text
if "TPOS" in tags:
text = unicode(tags["TPOS"])
if "/" in text:
disc, total = text.split("/")
metadata["discnumber"] = disc
metadata["totaldiscs"] = total
else:
metadata["discnumber"] = text
frames = tags.getall("UFID:http://musicbrainz.org")
if frames:
metadata["musicbrainz_trackid"] = unicode(frames[0].data)
read_free_text_frame("MusicBrainz Artist Id", "musicbrainz_artistid")
read_free_text_frame("MusicBrainz Album Id", "musicbrainz_albumid")
read_free_text_frame("MusicBrainz Album Artist Id",
"musicbrainz_albumartistid")
read_free_text_frame("ALBUMARTIST", "albumartist")
frames = tags.getall("APIC")
if frames:
metadata["~artwork"] = []
for frame in frames:
metadata["~artwork"].append((frame.mime, frame.data))
self.metadata["~#length"] = int(file.info.length * 1000)
self.orig_metadata.copy(self.metadata)
def save(self):
"""Save metadata to the file."""
try:
tags = compatid3.CompatID3(encode_filename(self.filename))
except mutagen.id3.ID3NoHeaderError:
tags = compatid3.CompatID3()
if self.config.setting["clear_existing_tags"]:
tags.clear()
if self.config.setting["write_id3v1"]:
v1 = 2
else:
v1 = 0
if self.config.setting["id3v2_encoding"].lower() == "utf-8":
encoding = 3
elif self.config.setting["id3v2_encoding"].lower() == "utf-16":
encoding = 1
else:
encoding = 0
metadata = self.metadata
def add_text_frame(frame_class, name):
if name in metadata:
tags.add(frame_class(encoding=encoding,
text=metadata[name]))
def add_free_text_frame(desc, name):
if name in metadata:
tags.delall("TXXX:%s" % desc.upper())
tags.add(id3.TXXX(encoding=encoding, desc=desc,
text=metadata[name]))
add_text_frame(id3.TPE1, "artist")
add_text_frame(id3.TPE2, "ensemble")
add_text_frame(id3.TPE3, "conductor")
add_text_frame(id3.TPE4, "remixer")
add_text_frame(id3.TCOM, "composer")
add_text_frame(id3.TALB, "album")
add_text_frame(id3.TIT2, "title")
add_text_frame(id3.TEXT, "lyricist")
add_text_frame(compatid3.TCMP, "compilation")
add_text_frame(id3.TDRC, "date")
if "tracknumber" in metadata:
if "totaltracks" in metadata:
text = "%s/%s" % (metadata["tracknumber"],
metadata["totaltracks"])
else:
text = metadata["tracknumber"]
tags.add(id3.TRCK(encoding=0, text=text))
if "discnumber" in metadata:
if "totaldiscs" in metadata:
text = "%s/%s" % (metadata["discnumber"],
metadata["totaldiscs"])
else:
text = metadata["discnumber"]
tags.add(id3.TPOS(encoding=0, text=text))
if "comment" in metadata:
tags.add(id3.COMM(encoding=encoding,
text=metadata["COMMENT"]))
if "musicbrainz_trackid" in metadata:
tags.add(id3.UFID(owner="http://musicbrainz.org",
data=metadata["musicbrainz_trackid"]))
add_free_text_frame("MusicBrainz Artist Id", "musicbrainz_artistid")
add_free_text_frame("MusicBrainz Album Id", "musicbrainz_albumid")
add_free_text_frame("MusicBrainz Album Artist Id",
"musicbrainz_albumartistid")
add_free_text_frame("ALBUMARTIST", "albumartist")
if self.config.setting["write_id3v23"]:
tags.update_to_v23()
tags.save(encode_filename(self.filename), v2=3, v1=v1)
else:
tags.update_to_v24()
tags.save(encode_filename(self.filename), v2=4, v1=v1)
class MP3File(ID3File):
"""MP3 file."""
_File = mutagen.mp3.MP3
class TrueAudioFile(ID3File):
"""TTA file."""
_File = mutagen.trueaudio.TrueAudio

View File

@@ -1,70 +0,0 @@
# -*- coding: utf-8 -*-
#
# Picard, the next-generation MusicBrainz tagger
# Copyright (C) 2006 Lukáš Lalinský
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
"""Mutagen-based MP3 metadata reader/tagger."""
from picard.file import File
from picard.util import encode_filename
from mutagen.mp3 import MP3
from mutagen import id3
from picard.plugins.picardmutagen.mutagenext.compatid3 import CompatID3, TCMP
from picard.plugins.picardmutagen._id3 import read_id3_tags, write_id3_tags
class MutagenMP3File(File):
def read(self):
mp3file = MP3(encode_filename(self.filename), ID3=CompatID3)
read_id3_tags(mp3file.tags, self.orig_metadata)
self.orig_metadata["~filename"] = self.base_filename
self.orig_metadata["~#length"] = int(mp3file.info.length * 1000)
self.orig_metadata["~#bitrate"] = int(mp3file.info.bitrate / 1000)
self.metadata.copy(self.orig_metadata)
def save(self):
"""Save ID3 tags to the file."""
tags = CompatID3(encode_filename(self.filename), translate=False)
if self.config.setting["clear_existing_tags"]:
tags.clear()
if self.config.setting["write_id3v1"]:
v1 = 2
else:
v1 = 0
if self.config.setting["id3v2_encoding"].lower() == "utf-8":
encoding = 3
elif self.config.setting["id3v2_encoding"].lower() == "utf-16":
encoding = 1
else:
encoding = 0
if self.config.setting["write_id3v23"]:
write_id3_tags(tags, self.metadata, encoding, True)
tags.update_to_v23()
tags.save(v2=3, v1=v1)
else:
write_id3_tags(tags, self.metadata, encoding, False)
tags.update_to_v24()
tags.save(v2=4, v1=v1)

View File

@@ -40,12 +40,13 @@ class CompatID3(ID3):
def __init__(self, *args, **kwargs):
self.unknown_frames = []
known_frames = dict(Frames)
known_frames.update(dict(Frames_2_2))
known_frames["TCMP"] = TCMP
known_frames["XDOR"] = XDOR
kwargs["known_frames"] = known_frames
super(ID3, self).__init__(*args, **kwargs)
if args:
known_frames = dict(Frames)
known_frames.update(dict(Frames_2_2))
known_frames["TCMP"] = TCMP
known_frames["XDOR"] = XDOR
kwargs["known_frames"] = known_frames
super(CompatID3, self).__init__(*args, **kwargs)
def save(self, filename=None, v1=1, v2=4):
"""Save changes to a file.