mirror of
https://github.com/rembo10/headphones.git
synced 2026-07-19 23:44:01 +01:00
InRough update of the beets lib to 1.0b15
This commit is contained in:
+299
-247
@@ -1,5 +1,5 @@
|
||||
# This file is part of beets.
|
||||
# Copyright 2011, Adrian Sampson.
|
||||
# Copyright 2012, Adrian Sampson.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
@@ -8,7 +8,7 @@
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
@@ -106,7 +106,7 @@ def _safe_cast(out_type, val):
|
||||
else:
|
||||
try:
|
||||
# Should work for strings, bools, ints:
|
||||
return bool(int(val))
|
||||
return bool(int(val))
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
@@ -181,7 +181,6 @@ class Packed(object):
|
||||
"""Makes a packed list of values subscriptable. To access the packed
|
||||
output after making changes, use packed_thing.items.
|
||||
"""
|
||||
|
||||
def __init__(self, items, packstyle, none_val=0, out_type=int):
|
||||
"""Create a Packed object for subscripting the packed values in
|
||||
items. The items are packed using packstyle, which is a value
|
||||
@@ -193,11 +192,11 @@ class Packed(object):
|
||||
self.packstyle = packstyle
|
||||
self.none_val = none_val
|
||||
self.out_type = out_type
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
if not isinstance(index, int):
|
||||
raise TypeError('index must be an integer')
|
||||
|
||||
|
||||
if self.items is None:
|
||||
return self.none_val
|
||||
|
||||
@@ -206,7 +205,7 @@ class Packed(object):
|
||||
# Remove time information from dates. Usually delimited by
|
||||
# a "T" or a space.
|
||||
items = re.sub(r'[Tt ].*$', '', unicode(items))
|
||||
|
||||
|
||||
# transform from a string packing into a list we can index into
|
||||
if self.packstyle == packing.SLASHED:
|
||||
seq = unicode(items).split('/')
|
||||
@@ -214,17 +213,17 @@ class Packed(object):
|
||||
seq = unicode(items).split('-')
|
||||
elif self.packstyle == packing.TUPLE:
|
||||
seq = items # tuple: items is already indexable
|
||||
|
||||
|
||||
try:
|
||||
out = seq[index]
|
||||
except:
|
||||
out = None
|
||||
|
||||
|
||||
if out is None or out == self.none_val or out == '':
|
||||
return _safe_cast(self.out_type, self.none_val)
|
||||
else:
|
||||
return _safe_cast(self.out_type, out)
|
||||
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
if self.packstyle in (packing.SLASHED, packing.TUPLE):
|
||||
# SLASHED and TUPLE are always two-item packings
|
||||
@@ -232,7 +231,7 @@ class Packed(object):
|
||||
else:
|
||||
# DATE can have up to three fields
|
||||
length = 3
|
||||
|
||||
|
||||
# make a list of the items we'll pack
|
||||
new_items = []
|
||||
for i in range(length):
|
||||
@@ -241,7 +240,7 @@ class Packed(object):
|
||||
else:
|
||||
next_item = self[i]
|
||||
new_items.append(next_item)
|
||||
|
||||
|
||||
if self.packstyle == packing.DATE:
|
||||
# Truncate the items wherever we reach an invalid (none)
|
||||
# entry. This prevents dates like 2008-00-05.
|
||||
@@ -249,7 +248,7 @@ class Packed(object):
|
||||
if item == self.none_val or item is None:
|
||||
del(new_items[i:]) # truncate
|
||||
break
|
||||
|
||||
|
||||
if self.packstyle == packing.SLASHED:
|
||||
self.items = '/'.join(map(unicode, new_items))
|
||||
elif self.packstyle == packing.DATE:
|
||||
@@ -260,7 +259,7 @@ class Packed(object):
|
||||
self.items = '-'.join(elems)
|
||||
elif self.packstyle == packing.TUPLE:
|
||||
self.items = new_items
|
||||
|
||||
|
||||
|
||||
# The field itself.
|
||||
|
||||
@@ -270,7 +269,6 @@ class MediaField(object):
|
||||
can be unicode, int, or bool. id3, mp4, and flac are StorageStyle
|
||||
instances parameterizing the field's storage for each type.
|
||||
"""
|
||||
|
||||
def __init__(self, out_type = unicode, **kwargs):
|
||||
"""Creates a new MediaField.
|
||||
- out_type: The field's semantic (exterior) type.
|
||||
@@ -283,7 +281,7 @@ class MediaField(object):
|
||||
raise TypeError('MediaField constructor must have keyword '
|
||||
'arguments mp3, mp4, and etc')
|
||||
self.styles = kwargs
|
||||
|
||||
|
||||
def _fetchdata(self, obj, style):
|
||||
"""Get the value associated with this descriptor's field stored
|
||||
with the given StorageStyle. Unwraps from a list if necessary.
|
||||
@@ -305,18 +303,18 @@ class MediaField(object):
|
||||
frame = obj.mgfile[style.key]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
entry = getattr(frame, style.id3_frame_field)
|
||||
|
||||
else: # Not MP3.
|
||||
|
||||
else: # Not MP3.
|
||||
try:
|
||||
entry = obj.mgfile[style.key]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
# possibly index the list
|
||||
|
||||
# Possibly index the list.
|
||||
if style.list_elem:
|
||||
if entry: # List must have at least one value.
|
||||
if entry: # List must have at least one value.
|
||||
# Handle Mutagen bugs when reading values (#356).
|
||||
try:
|
||||
return entry[0]
|
||||
@@ -328,21 +326,23 @@ class MediaField(object):
|
||||
return None
|
||||
else:
|
||||
return entry
|
||||
|
||||
|
||||
def _storedata(self, obj, val, style):
|
||||
"""Store val for this descriptor's field in the tag dictionary
|
||||
according to the provided StorageStyle. Store it as a
|
||||
single-item list if necessary.
|
||||
"""
|
||||
# wrap as a list if necessary
|
||||
if style.list_elem: out = [val]
|
||||
else: out = val
|
||||
|
||||
# Wrap as a list if necessary.
|
||||
if style.list_elem:
|
||||
out = [val]
|
||||
else:
|
||||
out = val
|
||||
|
||||
if obj.type == 'mp3':
|
||||
# Try to match on "desc" field.
|
||||
if style.id3_desc is not None:
|
||||
frames = obj.mgfile.tags.getall(style.key)
|
||||
|
||||
|
||||
# try modifying in place
|
||||
found = False
|
||||
for frame in frames:
|
||||
@@ -350,56 +350,56 @@ class MediaField(object):
|
||||
setattr(frame, style.id3_frame_field, out)
|
||||
found = True
|
||||
break
|
||||
|
||||
|
||||
# need to make a new frame?
|
||||
if not found:
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
frame = lib.mutagen.id3.Frames[style.key](
|
||||
encoding=3,
|
||||
desc=style.id3_desc,
|
||||
**{style.id3_frame_field: val}
|
||||
)
|
||||
obj.mgfile.tags.add(frame)
|
||||
|
||||
|
||||
# Try to match on "owner" field.
|
||||
elif style.key.startswith('UFID:'):
|
||||
owner = style.key.split(':', 1)[1]
|
||||
frames = obj.mgfile.tags.getall(style.key)
|
||||
|
||||
|
||||
for frame in frames:
|
||||
# Replace existing frame data.
|
||||
if frame.owner == owner:
|
||||
setattr(frame, style.id3_frame_field, val)
|
||||
else:
|
||||
# New frame.
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
frame = lib.mutagen.id3.UFID(owner=owner,
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
frame = lib.mutagen.id3.UFID(owner=owner,
|
||||
**{style.id3_frame_field: val})
|
||||
obj.mgfile.tags.setall('UFID', [frame])
|
||||
|
||||
|
||||
# Just replace based on key.
|
||||
else:
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
assert isinstance(style.id3_frame_field, str) # Keyword.
|
||||
frame = lib.mutagen.id3.Frames[style.key](encoding = 3,
|
||||
**{style.id3_frame_field: val})
|
||||
obj.mgfile.tags.setall(style.key, [frame])
|
||||
|
||||
|
||||
else: # Not MP3.
|
||||
obj.mgfile[style.key] = out
|
||||
|
||||
|
||||
def _styles(self, obj):
|
||||
if obj.type in ('mp3', 'mp4'):
|
||||
styles = self.styles[obj.type]
|
||||
else:
|
||||
styles = self.styles['etc'] # sane styles
|
||||
|
||||
styles = self.styles['etc'] # Sane styles.
|
||||
|
||||
# Make sure we always return a list of styles, even when given
|
||||
# a single style for convenience.
|
||||
if isinstance(styles, StorageStyle):
|
||||
return [styles]
|
||||
else:
|
||||
return styles
|
||||
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
"""Retrieve the value of this metadata field.
|
||||
"""
|
||||
@@ -413,7 +413,7 @@ class MediaField(object):
|
||||
out = self._fetchdata(obj, style)
|
||||
if out:
|
||||
break
|
||||
|
||||
|
||||
if style.packing:
|
||||
out = Packed(out, style.packing)[style.pack_pos]
|
||||
|
||||
@@ -421,9 +421,9 @@ class MediaField(object):
|
||||
if obj.type == 'mp4' and style.key.startswith('----:') and \
|
||||
isinstance(out, str):
|
||||
out = out.decode('utf8')
|
||||
|
||||
|
||||
return _safe_cast(self.out_type, out)
|
||||
|
||||
|
||||
def __set__(self, obj, val):
|
||||
"""Set the value of this metadata field.
|
||||
"""
|
||||
@@ -433,15 +433,15 @@ class MediaField(object):
|
||||
return
|
||||
|
||||
for style in styles:
|
||||
|
||||
|
||||
if style.packing:
|
||||
p = Packed(self._fetchdata(obj, style), style.packing)
|
||||
p[style.pack_pos] = val
|
||||
out = p.items
|
||||
|
||||
|
||||
else: # unicode, integer, or boolean scalar
|
||||
out = val
|
||||
|
||||
|
||||
# deal with Nones according to abstract type if present
|
||||
if out is None:
|
||||
if self.out_type == int:
|
||||
@@ -451,7 +451,7 @@ class MediaField(object):
|
||||
elif self.out_type == unicode:
|
||||
out = u''
|
||||
# We trust that packed values are handled above.
|
||||
|
||||
|
||||
# Convert to correct storage type (irrelevant for
|
||||
# packed values).
|
||||
if style.as_type == unicode:
|
||||
@@ -472,7 +472,7 @@ class MediaField(object):
|
||||
out = int(out)
|
||||
elif style.as_type in (bool, str):
|
||||
out = style.as_type(out)
|
||||
|
||||
|
||||
# MPEG-4 "freeform" (----) frames must be encoded as UTF-8
|
||||
# byte strings.
|
||||
if obj.type == 'mp4' and style.key.startswith('----:') and \
|
||||
@@ -494,7 +494,7 @@ class CompositeDateField(object):
|
||||
self.year_field = year_field
|
||||
self.month_field = month_field
|
||||
self.day_field = day_field
|
||||
|
||||
|
||||
def __get__(self, obj, owner):
|
||||
"""Return a datetime.date object whose components indicating the
|
||||
smallest valid date whose components are at least as large as
|
||||
@@ -509,9 +509,9 @@ class CompositeDateField(object):
|
||||
max(self.month_field.__get__(obj, owner), 1),
|
||||
max(self.day_field.__get__(obj, owner), 1)
|
||||
)
|
||||
except ValueError: # Out of range values.
|
||||
except ValueError: # Out of range values.
|
||||
return datetime.date.min
|
||||
|
||||
|
||||
def __set__(self, obj, val):
|
||||
"""Set the year, month, and day fields to match the components of
|
||||
the provided datetime.date object.
|
||||
@@ -676,13 +676,12 @@ class MediaFile(object):
|
||||
"""Represents a multimedia file on disk and provides access to its
|
||||
metadata.
|
||||
"""
|
||||
|
||||
def __init__(self, path):
|
||||
"""Constructs a new MediaFile reflecting the file at path. May
|
||||
throw UnreadableFileError.
|
||||
"""
|
||||
self.path = path
|
||||
|
||||
|
||||
unreadable_exc = (
|
||||
lib.mutagen.mp3.HeaderNotFoundError,
|
||||
lib.mutagen.flac.FLACNoHeaderError,
|
||||
@@ -697,9 +696,10 @@ class MediaFile(object):
|
||||
raise UnreadableFileError('Mutagen could not read file')
|
||||
except IOError:
|
||||
raise UnreadableFileError('could not read file')
|
||||
except:
|
||||
except Exception as exc:
|
||||
# Hide bugs in Mutagen.
|
||||
log.error('uncaught Mutagen exception:\n' + traceback.format_exc())
|
||||
log.debug(traceback.format_exc())
|
||||
log.error('uncaught Mutagen exception: {0}'.format(exc))
|
||||
raise UnreadableFileError('Mutagen raised an exception')
|
||||
|
||||
if self.mgfile is None: # Mutagen couldn't guess the type
|
||||
@@ -723,230 +723,282 @@ class MediaFile(object):
|
||||
else:
|
||||
raise FileTypeError('file type %s unsupported by MediaFile' %
|
||||
type(self.mgfile).__name__)
|
||||
|
||||
|
||||
# add a set of tags if it's missing
|
||||
if self.mgfile.tags is None:
|
||||
self.mgfile.add_tags()
|
||||
|
||||
|
||||
def save(self):
|
||||
self.mgfile.save()
|
||||
|
||||
|
||||
#### field definitions ####
|
||||
|
||||
|
||||
|
||||
# Field definitions.
|
||||
|
||||
title = MediaField(
|
||||
mp3 = StorageStyle('TIT2'),
|
||||
mp4 = StorageStyle("\xa9nam"),
|
||||
etc = StorageStyle('title'),
|
||||
)
|
||||
mp3 = StorageStyle('TIT2'),
|
||||
mp4 = StorageStyle("\xa9nam"),
|
||||
etc = StorageStyle('TITLE'),
|
||||
)
|
||||
artist = MediaField(
|
||||
mp3 = StorageStyle('TPE1'),
|
||||
mp4 = StorageStyle("\xa9ART"),
|
||||
etc = StorageStyle('artist'),
|
||||
)
|
||||
mp3 = StorageStyle('TPE1'),
|
||||
mp4 = StorageStyle("\xa9ART"),
|
||||
etc = StorageStyle('ARTIST'),
|
||||
)
|
||||
album = MediaField(
|
||||
mp3 = StorageStyle('TALB'),
|
||||
mp4 = StorageStyle("\xa9alb"),
|
||||
etc = StorageStyle('album'),
|
||||
)
|
||||
mp3 = StorageStyle('TALB'),
|
||||
mp4 = StorageStyle("\xa9alb"),
|
||||
etc = StorageStyle('ALBUM'),
|
||||
)
|
||||
genre = MediaField(
|
||||
mp3 = StorageStyle('TCON'),
|
||||
mp4 = StorageStyle("\xa9gen"),
|
||||
etc = StorageStyle('genre'),
|
||||
)
|
||||
mp3 = StorageStyle('TCON'),
|
||||
mp4 = StorageStyle("\xa9gen"),
|
||||
etc = StorageStyle('GENRE'),
|
||||
)
|
||||
composer = MediaField(
|
||||
mp3 = StorageStyle('TCOM'),
|
||||
mp4 = StorageStyle("\xa9wrt"),
|
||||
etc = StorageStyle('composer'),
|
||||
)
|
||||
mp3 = StorageStyle('TCOM'),
|
||||
mp4 = StorageStyle("\xa9wrt"),
|
||||
etc = StorageStyle('COMPOSER'),
|
||||
)
|
||||
grouping = MediaField(
|
||||
mp3 = StorageStyle('TIT1'),
|
||||
mp4 = StorageStyle("\xa9grp"),
|
||||
etc = StorageStyle('grouping'),
|
||||
)
|
||||
mp3 = StorageStyle('TIT1'),
|
||||
mp4 = StorageStyle("\xa9grp"),
|
||||
etc = StorageStyle('GROUPING'),
|
||||
)
|
||||
year = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TDRC',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 0),
|
||||
mp4 = StorageStyle("\xa9day",
|
||||
packing = packing.DATE,
|
||||
pack_pos = 0),
|
||||
etc = [StorageStyle('date',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 0),
|
||||
StorageStyle('year')]
|
||||
)
|
||||
mp3 = StorageStyle('TDRC', packing=packing.DATE, pack_pos=0),
|
||||
mp4 = StorageStyle("\xa9day", packing=packing.DATE, pack_pos=0),
|
||||
etc = [StorageStyle('DATE', packing=packing.DATE, pack_pos=0),
|
||||
StorageStyle('YEAR')]
|
||||
)
|
||||
month = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TDRC',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 1),
|
||||
mp4 = StorageStyle("\xa9day",
|
||||
packing = packing.DATE,
|
||||
pack_pos = 1),
|
||||
etc = StorageStyle('date',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 1)
|
||||
)
|
||||
mp3 = StorageStyle('TDRC', packing=packing.DATE, pack_pos=1),
|
||||
mp4 = StorageStyle("\xa9day", packing=packing.DATE, pack_pos=1),
|
||||
etc = StorageStyle('DATE', packing=packing.DATE, pack_pos=1),
|
||||
)
|
||||
day = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TDRC',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 2),
|
||||
mp4 = StorageStyle("\xa9day",
|
||||
packing = packing.DATE,
|
||||
pack_pos = 2),
|
||||
etc = StorageStyle('date',
|
||||
packing = packing.DATE,
|
||||
pack_pos = 2)
|
||||
)
|
||||
mp3 = StorageStyle('TDRC', packing=packing.DATE, pack_pos=2),
|
||||
mp4 = StorageStyle("\xa9day", packing=packing.DATE, pack_pos=2),
|
||||
etc = StorageStyle('DATE', packing=packing.DATE, pack_pos=2),
|
||||
)
|
||||
date = CompositeDateField(year, month, day)
|
||||
track = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TRCK',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4 = StorageStyle('trkn',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
etc = [StorageStyle('track'),
|
||||
StorageStyle('tracknumber')]
|
||||
)
|
||||
tracktotal = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TRCK',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4 = StorageStyle('trkn',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
etc = [StorageStyle('tracktotal'),
|
||||
StorageStyle('trackc'),
|
||||
StorageStyle('totaltracks')]
|
||||
)
|
||||
disc = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TPOS',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 0),
|
||||
mp4 = StorageStyle('disk',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 0),
|
||||
etc = [StorageStyle('disc'),
|
||||
StorageStyle('discnumber')]
|
||||
)
|
||||
disctotal = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TPOS',
|
||||
packing = packing.SLASHED,
|
||||
pack_pos = 1),
|
||||
mp4 = StorageStyle('disk',
|
||||
packing = packing.TUPLE,
|
||||
pack_pos = 1),
|
||||
etc = [StorageStyle('disctotal'),
|
||||
StorageStyle('discc'),
|
||||
StorageStyle('totaldiscs')]
|
||||
)
|
||||
track = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TRCK', packing=packing.SLASHED, pack_pos=0),
|
||||
mp4 = StorageStyle('trkn', packing=packing.TUPLE, pack_pos=0),
|
||||
etc = [StorageStyle('TRACK'),
|
||||
StorageStyle('TRACKNUMBER')]
|
||||
)
|
||||
tracktotal = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TRCK', packing=packing.SLASHED, pack_pos=1),
|
||||
mp4 = StorageStyle('trkn', packing=packing.TUPLE, pack_pos=1),
|
||||
etc = [StorageStyle('TRACKTOTAL'),
|
||||
StorageStyle('TRACKC'),
|
||||
StorageStyle('TOTALTRACKS')]
|
||||
)
|
||||
disc = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TPOS', packing=packing.SLASHED, pack_pos=0),
|
||||
mp4 = StorageStyle('disk', packing=packing.TUPLE, pack_pos=0),
|
||||
etc = [StorageStyle('DISC'),
|
||||
StorageStyle('DISCNUMBER')]
|
||||
)
|
||||
disctotal = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TPOS', packing=packing.SLASHED, pack_pos=1),
|
||||
mp4 = StorageStyle('disk', packing=packing.TUPLE, pack_pos=1),
|
||||
etc = [StorageStyle('DISCTOTAL'),
|
||||
StorageStyle('DISCC'),
|
||||
StorageStyle('TOTALDISCS')]
|
||||
)
|
||||
lyrics = MediaField(
|
||||
mp3 = StorageStyle('USLT',
|
||||
list_elem = False,
|
||||
id3_desc = u''),
|
||||
mp4 = StorageStyle("\xa9lyr"),
|
||||
etc = StorageStyle('lyrics')
|
||||
)
|
||||
mp3 = StorageStyle('USLT', list_elem=False, id3_desc=u''),
|
||||
mp4 = StorageStyle("\xa9lyr"),
|
||||
etc = StorageStyle('LYRICS')
|
||||
)
|
||||
comments = MediaField(
|
||||
mp3 = StorageStyle('COMM', id3_desc = u''),
|
||||
mp4 = StorageStyle("\xa9cmt"),
|
||||
etc = [StorageStyle('description'),
|
||||
StorageStyle('comment')]
|
||||
)
|
||||
bpm = MediaField(out_type = int,
|
||||
mp3 = StorageStyle('TBPM'),
|
||||
mp4 = StorageStyle('tmpo', as_type = int),
|
||||
etc = StorageStyle('bpm')
|
||||
)
|
||||
comp = MediaField(out_type = bool,
|
||||
mp3 = StorageStyle('TCMP'),
|
||||
mp4 = StorageStyle('cpil',
|
||||
list_elem = False,
|
||||
as_type = bool),
|
||||
etc = StorageStyle('compilation')
|
||||
)
|
||||
mp3 = StorageStyle('COMM', id3_desc=u''),
|
||||
mp4 = StorageStyle("\xa9cmt"),
|
||||
etc = [StorageStyle('DESCRIPTION'),
|
||||
StorageStyle('COMMENT')]
|
||||
)
|
||||
bpm = MediaField(out_type=int,
|
||||
mp3 = StorageStyle('TBPM'),
|
||||
mp4 = StorageStyle('tmpo', as_type=int),
|
||||
etc = StorageStyle('BPM'),
|
||||
)
|
||||
comp = MediaField(out_type=bool,
|
||||
mp3 = StorageStyle('TCMP'),
|
||||
mp4 = StorageStyle('cpil', list_elem=False, as_type=bool),
|
||||
etc = StorageStyle('COMPILATION'),
|
||||
)
|
||||
albumartist = MediaField(
|
||||
mp3 = StorageStyle('TPE2'),
|
||||
mp4 = StorageStyle('aART'),
|
||||
etc = [StorageStyle('album artist'),
|
||||
StorageStyle('albumartist')]
|
||||
)
|
||||
mp3 = StorageStyle('TPE2'),
|
||||
mp4 = StorageStyle('aART'),
|
||||
etc = [StorageStyle('ALBUM ARTIST'),
|
||||
StorageStyle('ALBUMARTIST')]
|
||||
)
|
||||
albumtype = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Type'),
|
||||
mp4 = StorageStyle(
|
||||
'----:com.apple.iTunes:MusicBrainz Album Type'),
|
||||
etc = StorageStyle('musicbrainz_albumtype')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Type'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Album Type'),
|
||||
etc = StorageStyle('MUSICBRAINZ_ALBUMTYPE'),
|
||||
)
|
||||
label = MediaField(
|
||||
mp3 = StorageStyle('TPUB'),
|
||||
mp4 = [StorageStyle('----:com.apple.iTunes:Label'),
|
||||
StorageStyle('----:com.apple.iTunes:publisher')],
|
||||
etc = [StorageStyle('label'),
|
||||
StorageStyle('publisher')] # Traktor
|
||||
)
|
||||
mp3 = StorageStyle('TPUB'),
|
||||
mp4 = [StorageStyle('----:com.apple.iTunes:Label'),
|
||||
StorageStyle('----:com.apple.iTunes:publisher')],
|
||||
etc = [StorageStyle('LABEL'),
|
||||
StorageStyle('PUBLISHER')] # Traktor
|
||||
)
|
||||
artist_sort = MediaField(
|
||||
mp3 = StorageStyle('TSOP'),
|
||||
mp4 = StorageStyle("soar"),
|
||||
etc = StorageStyle('ARTISTSORT'),
|
||||
)
|
||||
albumartist_sort = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'ALBUMARTISTSORT'),
|
||||
mp4 = StorageStyle("soaa"),
|
||||
etc = StorageStyle('ALBUMARTISTSORT'),
|
||||
)
|
||||
asin = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'ASIN'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:ASIN"),
|
||||
etc = StorageStyle('ASIN'),
|
||||
)
|
||||
catalognum = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'CATALOGNUMBER'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:CATALOGNUMBER"),
|
||||
etc = StorageStyle('CATALOGNUMBER'),
|
||||
)
|
||||
disctitle = MediaField(
|
||||
mp3 = StorageStyle('TSST'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:DISCSUBTITLE"),
|
||||
etc = StorageStyle('DISCSUBTITLE'),
|
||||
)
|
||||
encoder = MediaField(
|
||||
mp3 = StorageStyle('TENC'),
|
||||
mp4 = StorageStyle("\xa9too"),
|
||||
etc = [StorageStyle('ENCODEDBY'),
|
||||
StorageStyle('ENCODER')]
|
||||
)
|
||||
script = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'Script'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:SCRIPT"),
|
||||
etc = StorageStyle('SCRIPT'),
|
||||
)
|
||||
language = MediaField(
|
||||
mp3 = StorageStyle('TLAN'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:LANGUAGE"),
|
||||
etc = StorageStyle('LANGUAGE'),
|
||||
)
|
||||
country = MediaField(
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'MusicBrainz Album Release Country'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:MusicBrainz Album "
|
||||
"Release Country"),
|
||||
etc = StorageStyle('RELEASECOUNTRY'),
|
||||
)
|
||||
albumstatus = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Status'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:MusicBrainz Album Status"),
|
||||
etc = StorageStyle('MUSICBRAINZ_ALBUMSTATUS'),
|
||||
)
|
||||
media = MediaField(
|
||||
mp3 = StorageStyle('TMED'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:MEDIA"),
|
||||
etc = StorageStyle('MEDIA'),
|
||||
)
|
||||
albumdisambig = MediaField(
|
||||
# This tag mapping was invented for beets (not used by Picard, etc).
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Comment'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:MusicBrainz Album Comment"),
|
||||
etc = StorageStyle('MUSICBRAINZ_ALBUMCOMMENT'),
|
||||
)
|
||||
|
||||
# Nonstandard metadata.
|
||||
artist_credit = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'Artist Credit'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:Artist Credit"),
|
||||
etc = StorageStyle('ARTIST_CREDIT'),
|
||||
)
|
||||
albumartist_credit = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'Album Artist Credit'),
|
||||
mp4 = StorageStyle("----:com.apple.iTunes:Album Artist Credit"),
|
||||
etc = StorageStyle('ALBUMARTIST_CREDIT'),
|
||||
)
|
||||
|
||||
# Album art.
|
||||
art = ImageField()
|
||||
|
||||
# MusicBrainz IDs.
|
||||
mb_trackid = MediaField(
|
||||
mp3 = StorageStyle('UFID:http://musicbrainz.org',
|
||||
list_elem = False,
|
||||
id3_frame_field = 'data'),
|
||||
mp4 = StorageStyle(
|
||||
'----:com.apple.iTunes:MusicBrainz Track Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('musicbrainz_trackid')
|
||||
)
|
||||
mp3 = StorageStyle('UFID:http://musicbrainz.org',
|
||||
list_elem = False,
|
||||
id3_frame_field = 'data'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Track Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('MUSICBRAINZ_TRACKID')
|
||||
)
|
||||
mb_albumid = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Id'),
|
||||
mp4 = StorageStyle(
|
||||
'----:com.apple.iTunes:MusicBrainz Album Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('musicbrainz_albumid')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Album Id'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Album Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('MUSICBRAINZ_ALBUMID')
|
||||
)
|
||||
mb_artistid = MediaField(
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Artist Id'),
|
||||
mp4 = StorageStyle(
|
||||
'----:com.apple.iTunes:MusicBrainz Artist Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('musicbrainz_artistid')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'MusicBrainz Artist Id'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Artist Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('MUSICBRAINZ_ARTISTID')
|
||||
)
|
||||
mb_albumartistid = MediaField(
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'MusicBrainz Album Artist Id'),
|
||||
mp4 = StorageStyle(
|
||||
'----:com.apple.iTunes:MusicBrainz Album Artist Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('musicbrainz_albumartistid')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'MusicBrainz Album Artist Id'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Album Artist Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('MUSICBRAINZ_ALBUMARTISTID')
|
||||
)
|
||||
mb_releasegroupid = MediaField(
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'MusicBrainz Release Group Id'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:MusicBrainz Release Group Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('MUSICBRAINZ_RELEASEGROUPID')
|
||||
)
|
||||
|
||||
# Acoustid fields.
|
||||
acoustid_fingerprint = MediaField(
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'Acoustid Fingerprint'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:Acoustid Fingerprint',
|
||||
as_type=str),
|
||||
etc = StorageStyle('ACOUSTID_FINGERPRINT')
|
||||
)
|
||||
acoustid_id = MediaField(
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'Acoustid Id'),
|
||||
mp4 = StorageStyle('----:com.apple.iTunes:Acoustid Id',
|
||||
as_type=str),
|
||||
etc = StorageStyle('ACOUSTID_ID')
|
||||
)
|
||||
|
||||
# ReplayGain fields.
|
||||
rg_track_gain = FloatValueField(2, 'dB',
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'REPLAYGAIN_TRACK_GAIN'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_TRACK_GAIN')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'REPLAYGAIN_TRACK_GAIN'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_TRACK_GAIN')
|
||||
)
|
||||
rg_album_gain = FloatValueField(2, 'dB',
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'REPLAYGAIN_ALBUM_GAIN'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_ALBUM_GAIN')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'REPLAYGAIN_ALBUM_GAIN'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_ALBUM_GAIN')
|
||||
)
|
||||
rg_track_peak = FloatValueField(6, None,
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'REPLAYGAIN_TRACK_PEAK'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_TRACK_PEAK')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'REPLAYGAIN_TRACK_PEAK'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_TRACK_PEAK')
|
||||
)
|
||||
rg_album_peak = FloatValueField(6, None,
|
||||
mp3 = StorageStyle('TXXX',
|
||||
id3_desc=u'REPLAYGAIN_ALBUM_PEAK'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_ALBUM_PEAK')
|
||||
)
|
||||
mp3 = StorageStyle('TXXX', id3_desc=u'REPLAYGAIN_ALBUM_PEAK'),
|
||||
mp4 = None,
|
||||
etc = StorageStyle(u'REPLAYGAIN_ALBUM_PEAK')
|
||||
)
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
@@ -959,7 +1011,7 @@ class MediaFile(object):
|
||||
if hasattr(self.mgfile.info, 'sample_rate'):
|
||||
return self.mgfile.info.sample_rate
|
||||
return 0
|
||||
|
||||
|
||||
@property
|
||||
def bitdepth(self):
|
||||
"""The number of bits per sample in the audio encoding (an int).
|
||||
@@ -967,7 +1019,7 @@ class MediaFile(object):
|
||||
unavailable).
|
||||
"""
|
||||
if hasattr(self.mgfile.info, 'bits_per_sample'):
|
||||
return self.mgfile.info.bits_per_sample
|
||||
return self.mgfile.info.bits_per_sample
|
||||
return 0
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user