From 16b83ce6bfdb454579fd89db09fb37074dec5f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Lalinsk=C3=BD?= Date: Sun, 24 Sep 2006 11:14:52 +0200 Subject: [PATCH] MP3 and TTA plugins. --- picard/plugins/picardmutagen/__init__.py | 10 +- picard/plugins/picardmutagen/_id3.py | 136 ------------- picard/plugins/picardmutagen/id3.py | 189 ++++++++++++++++++ picard/plugins/picardmutagen/mp3.py | 70 ------- .../picardmutagen/mutagenext/compatid3.py | 13 +- 5 files changed, 203 insertions(+), 215 deletions(-) delete mode 100644 picard/plugins/picardmutagen/_id3.py create mode 100644 picard/plugins/picardmutagen/id3.py delete mode 100644 picard/plugins/picardmutagen/mp3.py diff --git a/picard/plugins/picardmutagen/__init__.py b/picard/plugins/picardmutagen/__init__.py index f35d18cff..5a302ed3c 100644 --- a/picard/plugins/picardmutagen/__init__.py +++ b/picard/plugins/picardmutagen/__init__.py @@ -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): diff --git a/picard/plugins/picardmutagen/_id3.py b/picard/plugins/picardmutagen/_id3.py deleted file mode 100644 index 968f1dc65..000000000 --- a/picard/plugins/picardmutagen/_id3.py +++ /dev/null @@ -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") - diff --git a/picard/plugins/picardmutagen/id3.py b/picard/plugins/picardmutagen/id3.py new file mode 100644 index 000000000..a7afbc449 --- /dev/null +++ b/picard/plugins/picardmutagen/id3.py @@ -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 + diff --git a/picard/plugins/picardmutagen/mp3.py b/picard/plugins/picardmutagen/mp3.py deleted file mode 100644 index de22f8d04..000000000 --- a/picard/plugins/picardmutagen/mp3.py +++ /dev/null @@ -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) - diff --git a/picard/plugins/picardmutagen/mutagenext/compatid3.py b/picard/plugins/picardmutagen/mutagenext/compatid3.py index a7afcc1b8..011cc18cb 100644 --- a/picard/plugins/picardmutagen/mutagenext/compatid3.py +++ b/picard/plugins/picardmutagen/mutagenext/compatid3.py @@ -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.