Source code for lyricsfandom.music.album

"""
Extract lyrics and songs from ``https://lyrics.fandom.com/`` website.

Examples:

    .. code-block:: python

        # 1. Generate an album from scratch
        album = Album('Bon Iver', 'For Emma, Forever Ago')
        # Scrape songs.
        songs = album.get_songs()
        # Be careful as this album was created from scratch it is not linked to any ``Artist`` instance.
        # However, there is still the artist's name saved.
        album.get_artist()  # None
        album.artist_name  # 'Bon Iver'

        # 2. Use an album from an artist
        artist = Artist('Bon Iver')
        album = Album.from_artist(artist, 'For Emmma, Forever Ago')
        album.get_artist()  # Artist: 'Bon Iver'
        # Or search it from the artist class.
        album = artist.search_album('For Emma, Forever Ago')

"""

import warnings

from lyricsfandom.utils import *
from lyricsfandom import scrape
from lyricsfandom.meta import AlbumMeta
from .song import Song
from .artist import Artist


[docs]class Album(AlbumMeta): """Defines an Album from ``https://lyrics.fandom.com/wiki/``. * :attr:`album_name`: album of the artist. * :attr:`album_type`: type of album. * :attr:`album_year`: released of the album. * :attr:`songs`: songs of the album. """ def __init__(self, artist_name, album_name, album_type=None, album_year=None): super().__init__(artist_name, album_name, album_type=album_type, album_year=album_year) # TODO: deprecate this
[docs] @classmethod def from_url(cls, url): """Construct an Album from an url. Args: url (string): url. Returns: Album Examples:: >>> album = Album.from_url('https://lyrics.fandom.com/wiki/Daughter:His_Young_Heart_(2011)') >>> album """ # Return nothing if the connection is incorrect pass
[docs] @classmethod def from_artist(cls, artist, album_name): """Construct an Album from an Artist. Args: artist (Artist): Artist to extract the album from. album_name (string): name of the album. Returns: Album """ for album in artist.albums(): if name_to_wiki_id(album_name) == name_to_wiki_id(album.album_name): return album warn_msg = f'\nNot Found: No albums named "{album_name}" found in "{artist.artist_name}" discography. ' \ f'`None` was returned.' warnings.warn(warn_msg, RuntimeWarning) return None
[docs] def items(self): """Connect to ``LyricWiki`` server and scrape songs. Returns: yield Song """ # TODO: get the album from the album page album = Artist(self.artist_name).search_album(self.album_name) for song in album.songs(): song.unregister() self.add_song(song) yield song
[docs] def add_song(self, song, force=None): """Add a song to the album. When adding, the song artist's name / album names can be changed to match the parent album, using ``force=True``. If the provided song is the name of a song (a string), it will automatically create an (empty) song and add it to the album. Args: song (Song or string): song (or song name) to add to the current album. force (bool): if ``True``, change the song's ``artist_name, album_name, album_year, album_type`` attribute to match its parent. Examples:: >>> album = Album('daughter', 'the wild youth') >>> song = Song('daughter', 'youth') >>> album.add_song(song) >>> artist.get_albums() >>> album Daughter: "The Wild Youth", Songs: 5 """ if isinstance(song, Song): if name_to_wiki_id(song.album_name) != name_to_wiki_id(self.album_name): if force is None: warn_msg = f'\nInvalid Names: Album name from "{song.album_name}" does not match ' \ f'parent album {self.album_name}. The song has been added, but you can change ' \ f'this behavior by setting the parameter `force=True` to update ' \ f'song\'s album information to its parent.' warnings.warn(warn_msg, RuntimeWarning) elif force: song.album_name = self.artist_name song.album_type = self.album_type song.album_year = self.album_year elif isinstance(song, str): song = Song(self.artist_name, song, album_name=self.album_name, album_type=self.album_type, album_year=self.album_year) song.register_artist(self.get_artist()) song.register_album(self) self._items.append(song)
[docs] def songs(self): """Iterate through all songs within the current album. Returns: yield Song """ if len(self._items) >= 1: yield from self._items else: yield from self.items()
[docs] def get_songs(self): """Get a list of all songs made from an album. Returns: list """ songs = [] for song in self.songs(): songs.append(song) return songs
[docs] def search_song(self, song_name): """Search a song from an album's playlist. Args: song_name (string): name of the song to look for Returns: Song """ for song in self.songs(): if name_to_wiki_id(song_name) == song.song_id: return song # WARNING: no song found warn_msg = f'\nNot Found: No songs named "{song_name}" found in "{self.album_name}" playlist. ' \ f'`None` was returned.' warnings.warn(warn_msg, RuntimeWarning) return None
[docs] def set_album_type(self): """Shortcut to retrieve the type (Single, EP, Album) from an album's playlist.""" size = len(self._items) if size == 1: album_type = 'Single' elif size < 6: album_type = 'EP' else: album_type = 'Album' self.album_type = album_type
[docs] def to_json(self, encode='ascii'): """Encode a song in a JSON format, with full description. Args: encode (string): format style. Recommended: ``ASCII``. Returns: dict """ data = { 'artist': self.artist_name, 'album': self.album_name, 'type': self.album_type, 'year': self.album_year, 'url': self.url, 'links': self.get_links(), 'songs': [] } for song in self.songs(): data['songs'].append(song.to_json()) if encode is None: return data else: return serialize_dict(data)
def __getitem__(self, item): return self._items[item]