# http://id3.org/ID3v1
__all__ = [
'ID3v1',
'ID3v1AlbumField',
'ID3v1ArtistField',
'ID3v1CommentField',
'ID3v1Field',
'ID3v1Fields',
'ID3v1GenreField',
'ID3v1TitleField',
'ID3v1TrackNumberField',
'ID3v1YearField',
]
from attr import (
attrib,
attrs,
)
from tbm_utils import (
AttrMapping,
datareader,
)
from .tables import ID3v1Genres
from ..exceptions import FormatError
from ..models import (
Tag,
Tags,
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1Field(Tag):
pass
@attrs(
repr=False,
kw_only=True,
)
class ID3v1AlbumField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='album',
value=data.read(30).strip(b'\x00').decode('iso-8859-1'),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1ArtistField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='artist',
value=data.read(30).strip(b'\x00').decode('iso-8859-1'),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1CommentField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='comment',
value=data.read(29).strip(b'\x00').decode('iso-8859-1'),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1GenreField(Tag):
value = attrib(converter=lambda v: ID3v1Genres[v])
@datareader
@classmethod
def parse(cls, data):
return cls(
name='genre',
value=int.from_bytes(data.read(1), byteorder='big'),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1TitleField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='title',
value=data.read(30).strip(b'\x00').decode('iso-8859-1'),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1TrackNumberField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='tracknumber',
value=str(data.read(1)[0]),
)
@attrs(
repr=False,
kw_only=True,
)
class ID3v1YearField(Tag):
@datareader
@classmethod
def parse(cls, data):
return cls(
name='year',
value=data.read(4).strip(b'\x00').decode('iso-8859-1'),
)
[docs]class ID3v1Fields(Tags):
@datareader
@classmethod
def parse(cls, data):
self = cls()
title = ID3v1TitleField.parse(data).value
artist = ID3v1ArtistField.parse(data).value
album = ID3v1AlbumField.parse(data).value
year = ID3v1YearField.parse(data).value
comment = ID3v1CommentField.parse(data).value
tracknumber = ID3v1TrackNumberField.parse(data).value
try:
genre = ID3v1GenreField.parse(data).value
except IndexError:
pass
else:
self.genre = [genre]
if title:
self.title = [title]
if artist:
self.artist = [artist]
if album:
self.album = [album]
if year:
self.year = [year]
if comment:
self.comment = [comment]
if tracknumber != '0':
self.tracknumber = [tracknumber]
return self
[docs]class ID3v1(AttrMapping):
@datareader
@classmethod
def parse(cls, data):
if data.read(3) != b"TAG":
raise FormatError("Valid ID3v1 header not found.")
self = cls()
self.tags = ID3v1Fields.parse(data)
return self