Skip to content

Add salt attribute to APIC frames to avoid mangling descriptions and to allow identical descriptions #675

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/api/id3_frames.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 ``<frame ID>:<desc>``, 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:<desc><salt>``.

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:
Expand Down
10 changes: 6 additions & 4 deletions mutagen/id3/_frames.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -1265,17 +1265,19 @@ class APIC(Frame):
BinaryDataSpec('data'),
]

salt = u''

def __eq__(self, other):
return self.data == other

__hash__ = Frame.__hash__

@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):
Expand Down