merge track into develop

This commit is contained in:
2020-03-04 21:56:56 +00:00
parent 2af554ffa3
commit 30e1ddf63b
4 changed files with 200 additions and 104 deletions

25
poetry.lock generated
View File

@@ -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"},
]

View File

@@ -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"

View File

@@ -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
# Update list
duplicated_tracks = self.paginate_results(
page_releases, duplicated_tracks
)
# pprint(self.official_albums)
return self
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

View File

@@ -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__':