Module musar.accessors
Interface between eyed3 and musar.
Expand source code
"""Interface between eyed3 and musar.
"""
import io
import PIL.Image
import eyed3.id3.frames
from .misc import HashableImage
class Accessor:
"""Placeholder class for accessors.
Parameters
----------
config : musar.config.Config
A reference for the config associated with the accessor.
This is used for accessors that depend on configurable parameters.
Attributes
----------
memory : Dict[str, Union[int, str, musar.misc.HashableImage]]
Memory buffer for the getter. Keys are track fullpaths and values are
possible field values.
config : musar.config.Config
"""
NAME: str = None
"""
Accessor name for identification in the config.
"""
def __init__(self, config):
self.memory = dict()
self.config = config
def _get(self, song):
raise NotImplementedError()
def get(self, song):
"""Basic value getter.
Parameters
----------
song : eyed3.mp3.Mp3AudioFile
Song to read the value from.
Returns
-------
Union[int, str, musar.misc.HashableImage]
Read value.
"""
if song is None:
return None
if song in self.memory:
return self.memory[song]
value = self._get(song)
self.memory[song] = value
return value
def set(self, song, value):
"""Abstract value setter.
Parameters
----------
song : eyed3.mp3.Mp3AudioFile
Track to set the value to.
value : Union[int, str, musar.misc.HashableImage]
Value to set.
"""
raise NotImplementedError()
class TagAccessor(Accessor):
"""Base class for simple accessors reading and setting tags without any
modification.
Parameters
----------
config : musar.config.Config
Accessor config.
tag_name : str
Name of the `eyed3` tag involved.
Attributes
----------
tag_name : str
"""
def __init__(self, config, tag_name):
Accessor.__init__(self, config)
self.tag_name = tag_name
def _get(self, song):
return getattr(song.tag, self.tag_name)
def set(self, song, value):
if song is not None:
setattr(song.tag, self.tag_name, value)
class Title(TagAccessor):
"""Track title accessor.
"""
NAME = "title"
def __init__(self, config):
TagAccessor.__init__(self, config, "title")
class Album(TagAccessor):
"""Track album accessor.
"""
NAME = "album"
def __init__(self, config=None):
TagAccessor.__init__(self, config, "album")
class AlbumArtist(TagAccessor):
"""Track album artist accessor.
"""
NAME = "album_artist"
def __init__(self, config=None):
TagAccessor.__init__(self, config, "album_artist")
class Artist(TagAccessor):
"""Track artist accessor.
"""
NAME = "artist"
def __init__(self, config):
TagAccessor.__init__(self, config, "artist")
class Composer(TagAccessor):
"""Track composer accessor.
"""
NAME = "composer"
def __init__(self, config):
TagAccessor.__init__(self, config, "composer")
class NumberAccessor(TagAccessor):
"""Accessor for numbering fields (track number and disc number). eyed3
outputs value as a tuple: only the first element is considered.
"""
def _get(self, song):
return getattr(song.tag, self.tag_name)[0]
class DiscNumber(NumberAccessor):
"""Track disc number accessor.
"""
NAME = "disc_num"
def __init__(self, config=None):
NumberAccessor.__init__(self, config, "disc_num")
class TrackNumber(NumberAccessor):
"""Track number accessor.
"""
NAME = "track_num"
def __init__(self, config):
NumberAccessor.__init__(self, config, "track_num")
class Genre(Accessor):
"""Track genre accessor. Genre is represented by its surface string.
"""
NAME = "genre"
def _get(self, song):
if song.tag.genre is None:
return None
return song.tag.genre.name
def set(self, song, value):
song.tag.genre = value
class Year(Accessor):
"""Track year accessor. eyed3 uses dates but only the year is extracted.
"""
NAME = "year"
def _get(self, song):
if song.tag.best_release_date is None:
return None
return song.tag.best_release_date.year
def set(self, song, value):
song.tag.recording_date = value
class Cover(Accessor):
"""Track cover accessor.
"""
NAME = "cover"
def _get(self, song):
if len(song.tag.images) == 0:
return None
return HashableImage(PIL.Image.open(io.BytesIO(song.tag.images[0].image_data)))
def set(self, song, value):
if value is None:
return
img_data = io.BytesIO()
value.image\
.convert(self.config.options.cover_target_encoding)\
.save(img_data, format=self.config.options.cover_target_format)
song.tag.images.set(
eyed3.id3.frames.ImageFrame.FRONT_COVER,
img_data.getvalue(),
"image/%s" % self.config.options.cover_target_format
)
class Comment(Accessor):
"""Track comment accessor.
"""
NAME = "comment"
def _get(self, song):
if len(song.tag.comments) == 0:
return None
return song.tag.comments[0].text
def set(self, song, value):
song.tag.comments.set(value)
class Manager(dict):
"""Manager for accessing all the accessors.
Parameters
----------
config : musar.config.Config
Configuration that will be shared to all accessors.
Attributes
----------
Keys are accessor names and values are accessor instances.
"""
def __init__(self, config):
super(Manager, self).__init__()
classes = [Title, Album, AlbumArtist, Artist, Genre, Comment,
Cover, Year, Composer, DiscNumber, TrackNumber]
for cls in classes:
self[cls.NAME] = cls(config)
Classes
class Accessor (config)
-
Placeholder class for accessors.
Parameters
config
:Config
- A reference for the config associated with the accessor. This is used for accessors that depend on configurable parameters.
Attributes
memory
:Dict[str, Union[int, str, HashableImage]]
- Memory buffer for the getter. Keys are track fullpaths and values are possible field values.
config
:Config
Expand source code
class Accessor: """Placeholder class for accessors. Parameters ---------- config : musar.config.Config A reference for the config associated with the accessor. This is used for accessors that depend on configurable parameters. Attributes ---------- memory : Dict[str, Union[int, str, musar.misc.HashableImage]] Memory buffer for the getter. Keys are track fullpaths and values are possible field values. config : musar.config.Config """ NAME: str = None """ Accessor name for identification in the config. """ def __init__(self, config): self.memory = dict() self.config = config def _get(self, song): raise NotImplementedError() def get(self, song): """Basic value getter. Parameters ---------- song : eyed3.mp3.Mp3AudioFile Song to read the value from. Returns ------- Union[int, str, musar.misc.HashableImage] Read value. """ if song is None: return None if song in self.memory: return self.memory[song] value = self._get(song) self.memory[song] = value return value def set(self, song, value): """Abstract value setter. Parameters ---------- song : eyed3.mp3.Mp3AudioFile Track to set the value to. value : Union[int, str, musar.misc.HashableImage] Value to set. """ raise NotImplementedError()
Subclasses
Class variables
var NAME : str
-
Accessor name for identification in the config.
Methods
def get(self, song)
-
Basic value getter.
Parameters
song
:eyed3.mp3.Mp3AudioFile
- Song to read the value from.
Returns
Union[int, str, HashableImage]
- Read value.
Expand source code
def get(self, song): """Basic value getter. Parameters ---------- song : eyed3.mp3.Mp3AudioFile Song to read the value from. Returns ------- Union[int, str, musar.misc.HashableImage] Read value. """ if song is None: return None if song in self.memory: return self.memory[song] value = self._get(song) self.memory[song] = value return value
def set(self, song, value)
-
Abstract value setter.
Parameters
song
:eyed3.mp3.Mp3AudioFile
- Track to set the value to.
value
:Union[int, str, HashableImage]
- Value to set.
Expand source code
def set(self, song, value): """Abstract value setter. Parameters ---------- song : eyed3.mp3.Mp3AudioFile Track to set the value to. value : Union[int, str, musar.misc.HashableImage] Value to set. """ raise NotImplementedError()
class Album (config=None)
-
Track album accessor.
Expand source code
class Album(TagAccessor): """Track album accessor. """ NAME = "album" def __init__(self, config=None): TagAccessor.__init__(self, config, "album")
Ancestors
Inherited members
class AlbumArtist (config=None)
-
Track album artist accessor.
Expand source code
class AlbumArtist(TagAccessor): """Track album artist accessor. """ NAME = "album_artist" def __init__(self, config=None): TagAccessor.__init__(self, config, "album_artist")
Ancestors
Inherited members
class Artist (config)
-
Track artist accessor.
Expand source code
class Artist(TagAccessor): """Track artist accessor. """ NAME = "artist" def __init__(self, config): TagAccessor.__init__(self, config, "artist")
Ancestors
Inherited members
class Comment (config)
-
Track comment accessor.
Expand source code
class Comment(Accessor): """Track comment accessor. """ NAME = "comment" def _get(self, song): if len(song.tag.comments) == 0: return None return song.tag.comments[0].text def set(self, song, value): song.tag.comments.set(value)
Ancestors
Inherited members
class Composer (config)
-
Track composer accessor.
Expand source code
class Composer(TagAccessor): """Track composer accessor. """ NAME = "composer" def __init__(self, config): TagAccessor.__init__(self, config, "composer")
Ancestors
Inherited members
class Cover (config)
-
Track cover accessor.
Expand source code
class Cover(Accessor): """Track cover accessor. """ NAME = "cover" def _get(self, song): if len(song.tag.images) == 0: return None return HashableImage(PIL.Image.open(io.BytesIO(song.tag.images[0].image_data))) def set(self, song, value): if value is None: return img_data = io.BytesIO() value.image\ .convert(self.config.options.cover_target_encoding)\ .save(img_data, format=self.config.options.cover_target_format) song.tag.images.set( eyed3.id3.frames.ImageFrame.FRONT_COVER, img_data.getvalue(), "image/%s" % self.config.options.cover_target_format )
Ancestors
Inherited members
class DiscNumber (config=None)
-
Track disc number accessor.
Expand source code
class DiscNumber(NumberAccessor): """Track disc number accessor. """ NAME = "disc_num" def __init__(self, config=None): NumberAccessor.__init__(self, config, "disc_num")
Ancestors
Inherited members
class Genre (config)
-
Track genre accessor. Genre is represented by its surface string.
Expand source code
class Genre(Accessor): """Track genre accessor. Genre is represented by its surface string. """ NAME = "genre" def _get(self, song): if song.tag.genre is None: return None return song.tag.genre.name def set(self, song, value): song.tag.genre = value
Ancestors
Inherited members
class Manager (config)
-
Manager for accessing all the accessors.
Parameters
config
:Config
- Configuration that will be shared to all accessors.
Attributes
Keys are accessor names and values are accessor instances.
Expand source code
class Manager(dict): """Manager for accessing all the accessors. Parameters ---------- config : musar.config.Config Configuration that will be shared to all accessors. Attributes ---------- Keys are accessor names and values are accessor instances. """ def __init__(self, config): super(Manager, self).__init__() classes = [Title, Album, AlbumArtist, Artist, Genre, Comment, Cover, Year, Composer, DiscNumber, TrackNumber] for cls in classes: self[cls.NAME] = cls(config)
Ancestors
- builtins.dict
class NumberAccessor (config, tag_name)
-
Accessor for numbering fields (track number and disc number). eyed3 outputs value as a tuple: only the first element is considered.
Expand source code
class NumberAccessor(TagAccessor): """Accessor for numbering fields (track number and disc number). eyed3 outputs value as a tuple: only the first element is considered. """ def _get(self, song): return getattr(song.tag, self.tag_name)[0]
Ancestors
Subclasses
Inherited members
class TagAccessor (config, tag_name)
-
Base class for simple accessors reading and setting tags without any modification.
Parameters
config
:Config
- Accessor config.
tag_name
:str
- Name of the
eyed3
tag involved.
Attributes
tag_name
:str
Expand source code
class TagAccessor(Accessor): """Base class for simple accessors reading and setting tags without any modification. Parameters ---------- config : musar.config.Config Accessor config. tag_name : str Name of the `eyed3` tag involved. Attributes ---------- tag_name : str """ def __init__(self, config, tag_name): Accessor.__init__(self, config) self.tag_name = tag_name def _get(self, song): return getattr(song.tag, self.tag_name) def set(self, song, value): if song is not None: setattr(song.tag, self.tag_name, value)
Ancestors
Subclasses
Inherited members
class Title (config)
-
Track title accessor.
Expand source code
class Title(TagAccessor): """Track title accessor. """ NAME = "title" def __init__(self, config): TagAccessor.__init__(self, config, "title")
Ancestors
Inherited members
class TrackNumber (config)
-
Track number accessor.
Expand source code
class TrackNumber(NumberAccessor): """Track number accessor. """ NAME = "track_num" def __init__(self, config): NumberAccessor.__init__(self, config, "track_num")
Ancestors
Inherited members
class Year (config)
-
Track year accessor. eyed3 uses dates but only the year is extracted.
Expand source code
class Year(Accessor): """Track year accessor. eyed3 uses dates but only the year is extracted. """ NAME = "year" def _get(self, song): if song.tag.best_release_date is None: return None return song.tag.best_release_date.year def set(self, song, value): song.tag.recording_date = value
Ancestors
Inherited members