Added support for loading and saving cover art in WMA

This commit is contained in:
Philipp Wolfer
2009-02-26 01:27:07 +01:00
parent 2bced1890c
commit bd6d760d36
2 changed files with 52 additions and 3 deletions

View File

@@ -20,7 +20,45 @@
from picard.file import File
from picard.util import encode_filename
from picard.metadata import Metadata
from mutagen.asf import ASF
from mutagen.asf import ASF, ASFByteArrayAttribute
import struct
def unpack_image(data):
"""
Helper function to unpack image data from a WM/Picture tag.
The data has the following format:
1 byte: Picture type (0-20), see ID3 APIC frame specification at http://www.id3.org/id3v2.4.0-frames
4 bytes: Picture data length in LE format
MIME type, null terminated UTF-16-LE string
Description, null terminated UTF-16-LE string
The image data in the given length
"""
(type, size) = struct.unpack_from("<bi", data)
pos = 5
mime = ""
while data[pos:pos+2] != "\x00\x00":
mime += data[pos:pos+2]
pos += 2
pos += 2
description = ""
while data[pos:pos+2] != "\x00\x00":
description += data[pos:pos+2]
pos += 2
pos += 2
image_data = data[pos:pos+size]
return (mime.decode("utf-16-le"), image_data)
def pack_image(mime, data, type=3, description=""):
"""
Helper function to pack image data for a WM/Picture tag.
See unpack_image for a description of the data format.
"""
tag_data = struct.pack("<bi", type, len(data))
tag_data += mime.encode("utf-16-le") + "\x00\x00"
tag_data += description.encode("utf-16-le") + "\x00\x00"
tag_data += data
return tag_data
class ASFFile(File):
"""ASF (WMA) metadata reader/writer"""
@@ -80,7 +118,12 @@ class ASFFile(File):
file = ASF(encode_filename(filename))
metadata = Metadata()
for name, values in file.tags.items():
if name not in self.__RTRANS:
if name == 'WM/Picture':
for image in values:
(mime, data) = unpack_image(image.value)
metadata.add_image(mime, data)
continue
elif name not in self.__RTRANS:
continue
elif name == 'WM/SharedUserRating':
# Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5
@@ -95,6 +138,12 @@ class ASFFile(File):
def _save(self, filename, metadata, settings):
self.log.debug("Saving file %r", filename)
file = ASF(encode_filename(filename))
if settings['save_images_to_tags']:
for mime, data in metadata.images:
tag_data = pack_image(mime, data, 3)
file.tags['WM/Picture'] = ASFByteArrayAttribute(tag_data)
for name, values in metadata.rawitems():
if name.startswith('lyrics:'):
name = 'lyrics'

View File

@@ -260,7 +260,7 @@ class ID3File(File):
count = frame.count
break
else:
count = 0;
count = 0
# Convert rating to range between 0 and 255
rating = int(values[0]) * 255 / (settings['rating_steps'] - 1)