completed track search
This commit is contained in:
25
poetry.lock
generated
25
poetry.lock
generated
@@ -1,3 +1,11 @@
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Addict is a dictionary whose items can be set using both attribute and item syntax."
|
||||
name = "addict"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "2.2.1"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
@@ -202,6 +210,14 @@ version = ">=0.12"
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
|
||||
[[package]]
|
||||
category = "main"
|
||||
description = "Easy to use progress bars"
|
||||
name = "progress"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.5"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "A full-screen, console-based Python debugger"
|
||||
@@ -477,10 +493,14 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["jaraco.itertools", "func-timeout"]
|
||||
|
||||
[metadata]
|
||||
content-hash = "40cc154211436945480756e120f8b39bb419e373bc51da5c6bb4d1ab72db47c5"
|
||||
content-hash = "50cff0758d9f4bfa77596b28f6f5f0c7f1db897b7c0d615071379c288b1d110d"
|
||||
python-versions = "^3.7"
|
||||
|
||||
[metadata.files]
|
||||
addict = [
|
||||
{file = "addict-2.2.1-py3-none-any.whl", hash = "sha256:1948c2a5d93ba6026eb91aef2c971234aaf72488a9c07ab8a7950f82ae30eea7"},
|
||||
{file = "addict-2.2.1.tar.gz", hash = "sha256:f22493f056032f50e4931a82444fcba8ef74c8fc994c5d06aa546a1433c2b8b0"},
|
||||
]
|
||||
appdirs = [
|
||||
{file = "appdirs-1.4.3-py2.py3-none-any.whl", hash = "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e"},
|
||||
{file = "appdirs-1.4.3.tar.gz", hash = "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92"},
|
||||
@@ -556,6 +576,9 @@ pluggy = [
|
||||
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
|
||||
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
|
||||
]
|
||||
progress = [
|
||||
{file = "progress-1.5.tar.gz", hash = "sha256:69ecedd1d1bbe71bf6313d88d1e6c4d2957b7f1d4f71312c211257f7dae64372"},
|
||||
]
|
||||
pudb = [
|
||||
{file = "pudb-2019.2.tar.gz", hash = "sha256:e8f0ea01b134d802872184b05bffc82af29a1eb2f9374a277434b932d68f58dc"},
|
||||
]
|
||||
|
||||
@@ -8,6 +8,8 @@ authors = ["dtomlinson <dtomlinson@williamhill.co.uk>"]
|
||||
python = "^3.7"
|
||||
requests = "^2.23.0"
|
||||
musicbrainzngs = "^0.7.1"
|
||||
addict = "^2.2.1"
|
||||
progress = "^1.5"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = "^5.2"
|
||||
@@ -25,3 +27,6 @@ pyls-black = "^0.4.4"
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
||||
|
||||
[tool.poetry.plugins."console_scripts"]
|
||||
"musicbrainzapi" = "musicbrainzapi.cli.cli:cli"
|
||||
|
||||
@@ -2,13 +2,16 @@ from __future__ import annotations
|
||||
from abc import ABC, abstractmethod, abstractstaticmethod
|
||||
from dataclasses import dataclass
|
||||
from pprint import pprint
|
||||
from typing import Union
|
||||
from typing import Union, List
|
||||
import contextlib
|
||||
import itertools
|
||||
from progress.spinner import PieSpinner
|
||||
|
||||
# from pprint import pprint
|
||||
|
||||
import musicbrainzngs
|
||||
import click
|
||||
import addict
|
||||
|
||||
from musicbrainzapi.api import authenticate
|
||||
|
||||
@@ -16,10 +19,6 @@ from musicbrainzapi.api import authenticate
|
||||
class LyricsConcreteBuilder(ABC):
|
||||
"""docstring for Lyrics"""
|
||||
|
||||
@abstractstaticmethod
|
||||
def set_useragent():
|
||||
authenticate.set_useragent()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def product(self) -> None:
|
||||
@@ -55,6 +54,22 @@ class LyricsConcreteBuilder(ABC):
|
||||
def artist_id(self, artist_id: str) -> None:
|
||||
pass
|
||||
|
||||
@abstractstaticmethod
|
||||
def set_useragent():
|
||||
authenticate.set_useragent()
|
||||
|
||||
@abstractstaticmethod
|
||||
def browse_releases(self) -> dict:
|
||||
pass
|
||||
|
||||
@abstractstaticmethod
|
||||
def get_album_info_list(self) -> list:
|
||||
pass
|
||||
|
||||
@abstractstaticmethod
|
||||
def paginate_results(self) -> list:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
@@ -79,14 +94,14 @@ class LyricsConcreteBuilder(ABC):
|
||||
def get_top_five_results(self) -> None:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def do_search_albums(self) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class LyricsBuilder(LyricsConcreteBuilder):
|
||||
"""docstring for LyricsBuilder"""
|
||||
|
||||
@staticmethod
|
||||
def set_useragent() -> None:
|
||||
authenticate.set_useragent()
|
||||
|
||||
@property
|
||||
def product(self) -> Lyrics:
|
||||
product = self._product
|
||||
@@ -119,6 +134,76 @@ class LyricsBuilder(LyricsConcreteBuilder):
|
||||
self._artist_id = artist_id
|
||||
self._product.artist_id = artist_id
|
||||
|
||||
@property
|
||||
def all_tracks(self) -> set:
|
||||
return self._all_tracks
|
||||
|
||||
@all_tracks.setter
|
||||
def all_tracks(self, all_tracks: set) -> None:
|
||||
self._all_tracks = all_tracks
|
||||
self._product.all_tracks = all_tracks
|
||||
|
||||
@property
|
||||
def all_albums_with_tracks(self) -> list:
|
||||
return self._all_albums_with_tracks
|
||||
|
||||
@all_albums_with_tracks.setter
|
||||
def all_albums_with_tracks(self, all_albums_with_tracks: list) -> None:
|
||||
self._all_albums_with_tracks = all_albums_with_tracks
|
||||
self._product.all_albums_with_tracks = all_albums_with_tracks
|
||||
|
||||
@staticmethod
|
||||
def set_useragent() -> None:
|
||||
authenticate.set_useragent()
|
||||
|
||||
@staticmethod
|
||||
def browse_releases(
|
||||
artist_id: str,
|
||||
limit: int,
|
||||
release_type: list,
|
||||
offset: Union[int, None] = None,
|
||||
includes: Union[List[str, None]] = list(),
|
||||
) -> dict:
|
||||
releases = musicbrainzngs.browse_releases(
|
||||
artist=artist_id,
|
||||
limit=limit,
|
||||
release_type=release_type,
|
||||
offset=offset,
|
||||
includes=includes,
|
||||
)
|
||||
return releases
|
||||
|
||||
@staticmethod
|
||||
def get_album_info_list(
|
||||
album_info_list: list, album_tracker: set, releases: addict.Dict
|
||||
) -> list:
|
||||
for i in releases['release-list']:
|
||||
_throwaway_dict = addict.Dict()
|
||||
_throwaway_dict.album = i.title
|
||||
_throwaway_dict.year = i.date.split('-')[0]
|
||||
_throwaway_dict.tracks = [
|
||||
j.recording.title for j in i['medium-list'][0]['track-list']
|
||||
]
|
||||
if i.title not in album_tracker:
|
||||
album_tracker.add(i.title)
|
||||
album_info_list.append(_throwaway_dict)
|
||||
else:
|
||||
pass
|
||||
return album_info_list, album_tracker
|
||||
|
||||
@staticmethod
|
||||
def paginate_results(
|
||||
releases: addict.Dict, duplicated_tracks: list
|
||||
) -> List:
|
||||
tracks = [
|
||||
j.recording.title
|
||||
for i in releases['release-list']
|
||||
for j in i['medium-list'][0]['track-list']
|
||||
]
|
||||
for i in itertools.chain(tracks):
|
||||
duplicated_tracks.append(i)
|
||||
return duplicated_tracks
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.reset()
|
||||
|
||||
@@ -159,95 +244,78 @@ class LyricsBuilder(LyricsConcreteBuilder):
|
||||
)
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def browse_releases(
|
||||
artist_id: str,
|
||||
limit: int,
|
||||
release_type: list,
|
||||
offset: Union[int, None] = None,
|
||||
) -> dict:
|
||||
releases = musicbrainzngs.browse_releases(
|
||||
artist=artist_id,
|
||||
def do_search_albums(self) -> None:
|
||||
album_info_list = list()
|
||||
album_tracker = set()
|
||||
duplicated_tracks = list()
|
||||
limit, offset, page = (100, 0, 1)
|
||||
|
||||
raw_releases = self.browse_releases(
|
||||
artist_id=self.artist_id,
|
||||
limit=limit,
|
||||
release_type=release_type,
|
||||
release_type=['album'],
|
||||
offset=offset,
|
||||
includes=['recordings'],
|
||||
)
|
||||
return releases
|
||||
|
||||
@staticmethod
|
||||
def browse_recordings(
|
||||
release: str, limit: int, offset: Union[int, None]
|
||||
) -> dict:
|
||||
recordings = musicbrainzngs.browse_recordings(
|
||||
release=release, limit=limit, offset=offset
|
||||
releases = addict.Dict(raw_releases)
|
||||
|
||||
duplicated_tracks = self.paginate_results(releases, duplicated_tracks)
|
||||
|
||||
# Get album info list
|
||||
album_info_list, album_tracker = self.get_album_info_list(
|
||||
album_info_list, album_tracker, releases
|
||||
)
|
||||
return recordings
|
||||
|
||||
def do_search_albumns(self) -> None:
|
||||
limit = 100
|
||||
offset = 0
|
||||
page = 1
|
||||
self.releases_list = list()
|
||||
releases = self.browse_releases(self.artist_id, limit, ['album'])
|
||||
total_releases_count = releases['release-count']
|
||||
page_releases_list = releases['release-list']
|
||||
self.releases_list += page_releases_list
|
||||
with click.progressbar(
|
||||
length=total_releases_count - limit,
|
||||
label='Finding all albumns from Musicbrainz',
|
||||
bar_count = len(releases['release-list'])
|
||||
previous_bar_count = 0
|
||||
|
||||
with PieSpinner(
|
||||
f'Finding all tracks in all albums for {self.artist}'
|
||||
'from Musicbrainz '
|
||||
) as bar:
|
||||
while len(self.releases_list) < total_releases_count:
|
||||
while bar_count != previous_bar_count:
|
||||
offset += limit
|
||||
page += 1
|
||||
page_releases = self.browse_releases(
|
||||
self.artist_id, limit, ['album'], offset
|
||||
# Get next page
|
||||
raw_page_releases = self.browse_releases(
|
||||
artist_id=self.artist_id,
|
||||
limit=limit,
|
||||
release_type=['album'],
|
||||
offset=offset,
|
||||
includes=['recordings'],
|
||||
)
|
||||
page_releases_list = page_releases['release-list']
|
||||
self.releases_list += page_releases_list
|
||||
bar.update(limit)
|
||||
click.echo(f'Found {total_releases_count} albums for {self.artist}')
|
||||
return self
|
||||
page_releases = addict.Dict(raw_page_releases)
|
||||
|
||||
def do_filter_albums_official(self) -> None:
|
||||
# Get official albums only
|
||||
_official_albums_list = list()
|
||||
for i in self.releases_list:
|
||||
with contextlib.suppress(KeyError):
|
||||
if i['status'] == 'Official':
|
||||
_official_albums_list.append(i)
|
||||
self.official_albums = dict(
|
||||
(i['id'], i['title']) for i in _official_albums_list
|
||||
)
|
||||
# pprint(self.official_albums)
|
||||
return self
|
||||
# Update list
|
||||
duplicated_tracks = self.paginate_results(
|
||||
page_releases, duplicated_tracks
|
||||
)
|
||||
|
||||
def do_search_album_tracks(self) -> None:
|
||||
# No album is over 100 tracks so we don't need to iterate
|
||||
limit = 100
|
||||
offset = 0
|
||||
recordings_list = list()
|
||||
self.recordings = dict()
|
||||
with click.progressbar(
|
||||
length=len(self.official_albums),
|
||||
label='Finding all tracks in albums from Musicbrainz',
|
||||
) as bar:
|
||||
for i in self.official_albums:
|
||||
_recordings_result = self.browse_recordings(
|
||||
i, limit=limit, offset=offset
|
||||
# Update album info list
|
||||
(
|
||||
album_info_list,
|
||||
album_tracker,
|
||||
) = self.get_album_info_list(
|
||||
album_info_list, album_tracker, releases
|
||||
)
|
||||
album_recordings_list = _recordings_result['recording-list']
|
||||
recordings_list.append(
|
||||
dict((i['id'], i['title']) for i in album_recordings_list)
|
||||
)
|
||||
bar.update(1)
|
||||
for i in recordings_list:
|
||||
self.recordings = {**self.recordings, **i}
|
||||
# pprint(self.recordings)
|
||||
|
||||
previous_bar_count = bar_count
|
||||
bar_count += len(page_releases['release-list'])
|
||||
bar.next()
|
||||
total_releases_count = bar_count
|
||||
|
||||
tracks = set(duplicated_tracks)
|
||||
|
||||
click.echo(
|
||||
f'Found {len(self.recordings)} tracks from '
|
||||
f'{len(self.official_albums)} albums for {self.artist}'
|
||||
f'Musicbrainz found {len(tracks)} unique tracks in '
|
||||
f'{total_releases_count} releases for {self.artist}'
|
||||
)
|
||||
|
||||
# Set properties
|
||||
self.all_tracks = tracks
|
||||
self.all_albums_with_tracks = album_info_list
|
||||
|
||||
return self
|
||||
|
||||
|
||||
@@ -282,8 +350,8 @@ class LyricsClickDirector:
|
||||
if artist_meta == 'Multiple':
|
||||
_position = []
|
||||
click.echo(
|
||||
f'Musicbrainz found several results for {self.builder.artist[0]}'
|
||||
'. Which artist/group do you want?',
|
||||
f'Musicbrainz found several results for '
|
||||
f'{self.builder.artist[0]}. Which artist/group do you want?',
|
||||
)
|
||||
for i, j in zip(self.builder._top_five_results, range(1, 6)):
|
||||
click.echo(
|
||||
@@ -313,29 +381,29 @@ class LyricsClickDirector:
|
||||
)
|
||||
raise SystemExit()
|
||||
|
||||
def _search_for_all_tracks(self) -> None:
|
||||
self.builder.do_search_albums()
|
||||
pprint(self.builder._product.all_tracks)
|
||||
# pprint(self.builder._product.all_albums_with_tracks)
|
||||
|
||||
def _set_artist_id_on_product(self) -> None:
|
||||
self.builder.artist_id = self._artist_id
|
||||
self.builder.artist = self._artist
|
||||
# print(self.builder._product.artist_id)
|
||||
# print(self.builder._product.artist)
|
||||
# print(self.builder._product.__slots__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Lyrics:
|
||||
"""docstring for Lyrics"""
|
||||
|
||||
__slots__ = ['artist_id', 'artist']
|
||||
__slots__ = [
|
||||
'artist_id',
|
||||
'artist',
|
||||
'country',
|
||||
'all_tracks',
|
||||
'all_albums_with_tracks',
|
||||
]
|
||||
artist_id: str
|
||||
artist: str
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# director = LyricsClickDirector()
|
||||
# builder = LyricsBuilder()
|
||||
# director.builder = builder
|
||||
# director._get_initial_artists('One Direction')
|
||||
# director._confirm_final_artist()
|
||||
# director._set_artist_id_on_product()
|
||||
# director.builder._product
|
||||
print(type(Lyrics))
|
||||
country: Union[str, None]
|
||||
all_tracks: set
|
||||
all_albums_with_tracks: list
|
||||
|
||||
@@ -100,16 +100,16 @@ def cli(ctx, artist: str, country: Union[str, None]) -> None:
|
||||
"""
|
||||
Search for lyrics of an Artist/Group.
|
||||
"""
|
||||
print(artist)
|
||||
# print(artist)
|
||||
director = lyrics.LyricsClickDirector()
|
||||
builder = lyrics.LyricsBuilder()
|
||||
director.builder = builder
|
||||
director._get_initial_artists(artist, country)
|
||||
director._confirm_final_artist()
|
||||
director._set_artist_id_on_product()
|
||||
builder.do_search_albumns()
|
||||
builder.do_filter_albums_official()
|
||||
builder.do_search_album_tracks()
|
||||
director._search_for_all_tracks()
|
||||
# builder.do_filter_albums_official()
|
||||
# builder.do_search_album_tracks()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user