From 5fb762fee711c764e6853bbbcdfef860f758dd50 Mon Sep 17 00:00:00 2001 From: Molly Messner Date: Sat, 15 Mar 2025 13:54:19 +0100 Subject: [PATCH] Add salt attribute to APIC frames to allow identical descriptions --- docs/api/id3_frames.rst | 52 +++++++++++++++++++++++++++++++++++++++++ mutagen/id3/_frames.py | 10 ++++---- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/docs/api/id3_frames.rst b/docs/api/id3_frames.rst index 1a6b3982..2b55824f 100644 --- a/docs/api/id3_frames.rst +++ b/docs/api/id3_frames.rst @@ -59,6 +59,58 @@ ID3v2.3/4 Frames :show-inheritance: :members: + ----- + + **Examples:** + + To set the cover image for a file you may, for example, do it this way: + + .. code-block:: python + + import mimetypes + from mutagen.id3 import ID3, APIC, PictureType + + image_filename = 'example.jpeg' + image_mime_type = mimetypes.guess_file_type(image_filename)[0] + with open(image_filename, 'rb') as f: + image_data = f.read() + + tags = ID3('example.mp3') + tags.setall('APIC', [APIC( + mime=image_mime_type, + type=PictureType.COVER_FRONT + data=image_data + )]) + + Setting multiple cover images is a tad more complicated. Since tags in Mutagen are identified by their `HashKey`, each APIC needs to have a unique `HashKey`. Usually, `HashKey`\ s in Mutagen are set as ``:``, but this would mean that `APIC`\ s couldn't have the same description. To that end, the `APIC` class has the ``salt`` attribute, which exists only to be added to the `HashKey`\  – that is to say, `APIC`\ s' `HashKey`\ s are set as ``APIC:``. + + Thus, to add multiple cover images, you can either ensure that each `APIC` has a unique description, or you can add to ``salt``: + + .. code-block:: python + + import mimetypes + from mutagen.id3 import ID3, APIC, PictureType + + tags = ID3('example.mp3') + + image_filenames = ['example.jpeg', 'example.png'] + for image_filename in image_filenames: + image_mime_type = mimetypes.guess_file_type(image_filename)[0] + with open(image_filename, 'rb') as f: + image_data = f.read() + + apic = APIC( + mime=image_mime_type, + type=PictureType.COVER_FRONT + data=image_data + ) + + while apic.HashKey in tags: + apic.salt += ' ' + + tags.add(apic) + + ----- .. autoclass:: mutagen.id3.ASPI(S=0, L=0, N=0, b=0, Fi=[]) :show-inheritance: diff --git a/mutagen/id3/_frames.py b/mutagen/id3/_frames.py index bee693bd..03f05c0c 100644 --- a/mutagen/id3/_frames.py +++ b/mutagen/id3/_frames.py @@ -1253,8 +1253,8 @@ class APIC(Frame): * type -- the source of the image (3 is the album front cover) * desc -- a text description of the image * data -- raw image data, as a byte string - - Mutagen will automatically compress large images when saving tags. + * salt -- will be added to the `HashKey`; this allows for + multiple `APIC` frames with the same description """ _framespec = [ @@ -1265,6 +1265,8 @@ class APIC(Frame): BinaryDataSpec('data'), ] + salt = u'' + def __eq__(self, other): return self.data == other @@ -1272,10 +1274,10 @@ def __eq__(self, other): @property def HashKey(self): - return '%s:%s' % (self.FrameID, self.desc) + return '%s:%s%s' % (self.FrameID, self.desc, self.salt) def _merge_frame(self, other): - other.desc += u" " + other.salt += u' ' return other def _pprint(self):