From 6038409d44c5de31852202bd8be77a95e374ef0d Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Tue, 11 Dec 2018 15:36:50 +0100 Subject: [PATCH 1/2] PICARD-490: Support load and rename for AAC (ADTS/ADIF) files --- picard/formats/__init__.py | 3 +++ picard/formats/aac.py | 45 +++++++++++++++++++++++++++++++++++++ test/data/test.aac | Bin 0 -> 1896 bytes test/test_formats.py | 12 ++++++++++ 4 files changed, 60 insertions(+) create mode 100644 picard/formats/aac.py create mode 100644 test/data/test.aac diff --git a/picard/formats/__init__.py b/picard/formats/__init__.py index d007fee75..17cc6bbc1 100644 --- a/picard/formats/__init__.py +++ b/picard/formats/__init__.py @@ -140,3 +140,6 @@ register_format(WAVFile) from picard.formats.midi import MIDIFile register_format(MIDIFile) + +from picard.formats.aac import AACFile +register_format(AACFile) diff --git a/picard/formats/aac.py b/picard/formats/aac.py new file mode 100644 index 000000000..29ef2cc7d --- /dev/null +++ b/picard/formats/aac.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# Copyright (C) 2018 Philipp Wolfer +# +# 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.aac import AAC + +from picard import log +from picard.file import File +from picard.metadata import Metadata +from picard.util import encode_filename + + +class AACFile(File): + EXTENSIONS = [".aac"] + NAME = "AAC" + _File = AAC + + def _load(self, filename): + log.debug("Loading file %r", filename) + metadata = Metadata() + file = self._File(encode_filename(filename)) + self._info(metadata, file) + return metadata + + def _save(self, filename, metadata): + log.debug("Saving file %r", filename) + + @classmethod + def supports_tag(cls, name): + return False diff --git a/test/data/test.aac b/test/data/test.aac new file mode 100644 index 0000000000000000000000000000000000000000..2a5926f0f95e33bbc4c97501a89c9d16a45a317f GIT binary patch literal 1896 zcmV-u2bcK&@lb#s-~8SL003-hVrF4sV<0guGBf}HLKT~y`n$jW?8!l}P>c{F1O$Nr zpg_bBAq7I)RhrEz^7D+XZq*k8jZHog@D!e3FCNJ_%H2H^aGqVijhfHD`seZpA1=YE z{QvR*{{Uc)`MN=zqfh`VDu5gSgB2za{0H~|9I$2g{X}?1qnF$5_M6k{uZRFWP*^Ay z5(R{VV4zqk6bl3bgaHshC=i3K>wS3m-nppNX0j1*DAd%_4*_uH_80sN_jNDbyXoU@ zkJB1|kjb*DKON1Kd*=0N8ie}qp>8p#2kY?mH3J+zpN}o*+xGiz71qQ)DuuzH=8-)TvLAYIW#!So}x!s=^*wExsLITDbNJS9TyDjN%VIbr)Yapi{Z0Xa!eS$-+a^fuBWRzblb9 zTDtw*LMvMxu9`%3X^Zz@wO6mfmQy^TtefJbIWZeIK@HF5jWuCX4Xtw#ITmT&#t`3%U{+f|3B=acflPg4Li#?sK{GmVepp6}%mDk=5h{ zTOP=w3xd^U+%6>AeEriuJ>+CUo6IQhE9e~Z%=s@op?$71YU6=B4wi!*_QfFaqMREN zNIe8-#}|B9wZ6C8;Q#SZfIt8IAu7)`?|t9@e1Ndfj1&t60>VMCP%I=91wz3K8Bt5qUF*gI+ce($!;^Zm)RGoD+Jk=HR=Yl+I7H^UwLjW;9 z%g?DqHO2YqBtWRy9zkA~y!x4rcDTMLTmP1>F|dbfqXKAKe!i0)C9l@Ns?zNwPK%uO z)w@!@3b_Th

bZ#`3Ft@E<9lekGqH%|RSO9Y`DHz{H&bAX!w>3DI~L9>MBfKb0$- z{r^56$g0lU=w=->b#uZ(QOa3e$NAs?kRKo{6bXffgHW)LOcVY~s7Irg(VezUQ?~F+3DvH7 z0$I5Rn7{pbcfX+jWTD|Xi`sQ3YU~Au;eE&pmm2E5>YglXjNIk%Qk*k78~EJP5Su*k z`8}dITAJY3Z^5SJXfd=CmwOSP(Bn&2sUvLlTxk?Pp5VLj*w)Um6S}q#%J+@e-b7r_ z(U*e8rE}CjEibC&Q13`6G7uRe!Ug%VixZOdd>AX;ro?Rn?awb#cyq+4}qi@Rr@$)f~B+*Z%< zlBAy-dPxRHaGdQO(FrlDbS#Xrt1EJ9g>Zkx-EuAet#I_CH)AEN2V3AFRp&yK3sK&* zGz!pXG|2%Z6VUT&lGVC`9ePTVfeCG*kdPmw*1K7e-3#xa9cTGD8PH!tr`$yk=cm4{ zxM`kgZ`qDq&}?f0$T3-)M9E2^gDy<>3sFv_1PdZcS5$N2?3i@)x%5%XwtFu;n0zOF zkjJfkn>sby(bu^%J&h6Y$0*3C1j0XWjKu2kmxp@sHKK8xW}1V$#z#t zcjYY^HR6@p)*4L}OjeM(6IL%=4-2xAX+u>_L`I`c^iw0(afFo4sd1ygkRdK?mLd0y zO%DNdizD3-X7&65p68;f!Xw(%X0B^dl{x`R_tT8000000000% iP(@ThM@3lB2LJ#d0000000000004jh0000000020l#pHk literal 0 HcmV?d00001 diff --git a/test/test_formats.py b/test/test_formats.py index 9c6a00965..2d90e922a 100644 --- a/test/test_formats.py +++ b/test/test_formats.py @@ -907,6 +907,18 @@ class TestCoverArt(PicardTestCase): self._tear_down() +class AACTest(PicardTestCase): + filename = os.path.join('test', 'data', 'test.aac') + + def setUp(self): + super().setUp() + config.setting = settings.copy() + + def test_can_open_and_save(self): + metadata = Metadata() + save_and_load_metadata(self.filename, metadata) + + class WAVTest(PicardTestCase): filename = os.path.join('test', 'data', 'test.wav') From 4c01a084ffa7e601790000ca3d289ae7cc781610 Mon Sep 17 00:00:00 2001 From: Philipp Wolfer Date: Tue, 11 Dec 2018 17:01:01 +0100 Subject: [PATCH 2/2] PICARD-490: Support tagging AAC files with APEv2 --- picard/formats/aac.py | 46 +++++++++++++++++++++++---------------- test/data/test-apev2.aac | Bin 0 -> 1896 bytes test/test_formats.py | 5 +++++ 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 test/data/test-apev2.aac diff --git a/picard/formats/aac.py b/picard/formats/aac.py index 29ef2cc7d..bfd949a4a 100644 --- a/picard/formats/aac.py +++ b/picard/formats/aac.py @@ -18,28 +18,36 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. from mutagen.aac import AAC +from mutagen.apev2 import ( + APENoHeaderError, + APEv2, + error as APEError, +) -from picard import log -from picard.file import File -from picard.metadata import Metadata -from picard.util import encode_filename +from picard.formats.apev2 import APEv2File -class AACFile(File): +class AACAPEv2(AAC): + def load(self, filething): + super().load(filething) + try: + self.tags = APEv2(filething) + except APENoHeaderError: + self.tags = None + + def add_tags(self): + if self.tags is None: + self.tags = APEv2() + else: + raise APEError("%r already has tags: %r" % (self, self.tags)) + + +class AACFile(APEv2File): EXTENSIONS = [".aac"] NAME = "AAC" - _File = AAC + _File = AACAPEv2 - def _load(self, filename): - log.debug("Loading file %r", filename) - metadata = Metadata() - file = self._File(encode_filename(filename)) - self._info(metadata, file) - return metadata - - def _save(self, filename, metadata): - log.debug("Saving file %r", filename) - - @classmethod - def supports_tag(cls, name): - return False + def _info(self, metadata, file): + super()._info(metadata, file) + if file.tags: + metadata['~format'] = "%s (APEv2)" % self.NAME diff --git a/test/data/test-apev2.aac b/test/data/test-apev2.aac new file mode 100644 index 0000000000000000000000000000000000000000..2a5926f0f95e33bbc4c97501a89c9d16a45a317f GIT binary patch literal 1896 zcmV-u2bcK&@lb#s-~8SL003-hVrF4sV<0guGBf}HLKT~y`n$jW?8!l}P>c{F1O$Nr zpg_bBAq7I)RhrEz^7D+XZq*k8jZHog@D!e3FCNJ_%H2H^aGqVijhfHD`seZpA1=YE z{QvR*{{Uc)`MN=zqfh`VDu5gSgB2za{0H~|9I$2g{X}?1qnF$5_M6k{uZRFWP*^Ay z5(R{VV4zqk6bl3bgaHshC=i3K>wS3m-nppNX0j1*DAd%_4*_uH_80sN_jNDbyXoU@ zkJB1|kjb*DKON1Kd*=0N8ie}qp>8p#2kY?mH3J+zpN}o*+xGiz71qQ)DuuzH=8-)TvLAYIW#!So}x!s=^*wExsLITDbNJS9TyDjN%VIbr)Yapi{Z0Xa!eS$-+a^fuBWRzblb9 zTDtw*LMvMxu9`%3X^Zz@wO6mfmQy^TtefJbIWZeIK@HF5jWuCX4Xtw#ITmT&#t`3%U{+f|3B=acflPg4Li#?sK{GmVepp6}%mDk=5h{ zTOP=w3xd^U+%6>AeEriuJ>+CUo6IQhE9e~Z%=s@op?$71YU6=B4wi!*_QfFaqMREN zNIe8-#}|B9wZ6C8;Q#SZfIt8IAu7)`?|t9@e1Ndfj1&t60>VMCP%I=91wz3K8Bt5qUF*gI+ce($!;^Zm)RGoD+Jk=HR=Yl+I7H^UwLjW;9 z%g?DqHO2YqBtWRy9zkA~y!x4rcDTMLTmP1>F|dbfqXKAKe!i0)C9l@Ns?zNwPK%uO z)w@!@3b_Th

bZ#`3Ft@E<9lekGqH%|RSO9Y`DHz{H&bAX!w>3DI~L9>MBfKb0$- z{r^56$g0lU=w=->b#uZ(QOa3e$NAs?kRKo{6bXffgHW)LOcVY~s7Irg(VezUQ?~F+3DvH7 z0$I5Rn7{pbcfX+jWTD|Xi`sQ3YU~Au;eE&pmm2E5>YglXjNIk%Qk*k78~EJP5Su*k z`8}dITAJY3Z^5SJXfd=CmwOSP(Bn&2sUvLlTxk?Pp5VLj*w)Um6S}q#%J+@e-b7r_ z(U*e8rE}CjEibC&Q13`6G7uRe!Ug%VixZOdd>AX;ro?Rn?awb#cyq+4}qi@Rr@$)f~B+*Z%< zlBAy-dPxRHaGdQO(FrlDbS#Xrt1EJ9g>Zkx-EuAet#I_CH)AEN2V3AFRp&yK3sK&* zGz!pXG|2%Z6VUT&lGVC`9ePTVfeCG*kdPmw*1K7e-3#xa9cTGD8PH!tr`$yk=cm4{ zxM`kgZ`qDq&}?f0$T3-)M9E2^gDy<>3sFv_1PdZcS5$N2?3i@)x%5%XwtFu;n0zOF zkjJfkn>sby(bu^%J&h6Y$0*3C1j0XWjKu2kmxp@sHKK8xW}1V$#z#t zcjYY^HR6@p)*4L}OjeM(6IL%=4-2xAX+u>_L`I`c^iw0(afFo4sd1ygkRdK?mLd0y zO%DNdizD3-X7&65p68;f!Xw(%X0B^dl{x`R_tT8000000000% iP(@ThM@3lB2LJ#d0000000000004jh0000000020l#pHk literal 0 HcmV?d00001 diff --git a/test/test_formats.py b/test/test_formats.py index 2d90e922a..892e98cc1 100644 --- a/test/test_formats.py +++ b/test/test_formats.py @@ -919,6 +919,11 @@ class AACTest(PicardTestCase): save_and_load_metadata(self.filename, metadata) +class AACWithAPETest(CommonTests.FormatsTest): + testfile = 'test-apev2.aac' + supports_ratings = False + + class WAVTest(PicardTestCase): filename = os.path.join('test', 'data', 'test.wav')