updating documentation
This commit is contained in:
13
README.rst
13
README.rst
@@ -0,0 +1,13 @@
|
|||||||
|
musicbrainzapi
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/readthedocs/panaetius?style=for-the-badge :target: https://panaetius.readthedocs.io/en/latest/?badge=latest
|
||||||
|
:alt: Documentation Status
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/github/v/tag/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub tag (latest by date)
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/github/commit-activity/m/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub commit activity
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/github/issues/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub issues
|
||||||
|
|
||||||
|
.. image:: https://img.shields.io/github/license/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHubtbc
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ autodoc_member_order = 'bysource'
|
|||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
|
|
||||||
# The master toctree document.
|
# The master toctree document.
|
||||||
master_doc = 'index'
|
master_doc = 'introduction'
|
||||||
|
|
||||||
# List of patterns, relative to source directory, that match files and
|
# List of patterns, relative to source directory, that match files and
|
||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
|
|||||||
@@ -1,13 +1 @@
|
|||||||
musicbrainzapi
|
.. include:: ../../toc.rst
|
||||||
===============
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/readthedocs/panaetius?style=for-the-badge :target: https://panaetius.readthedocs.io/en/latest/?badge=latest
|
|
||||||
:alt: Documentation Status
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/github/v/tag/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub tag (latest by date)
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/github/commit-activity/m/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub commit activity
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/github/issues/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHub issues
|
|
||||||
|
|
||||||
.. image:: https://img.shields.io/github/license/dtomlinson91/musicbrainzapi-cv-airelogic?style=for-the-badge :alt: GitHubtbc
|
|
||||||
|
|||||||
15024
lyrics_count.json
Normal file
15024
lyrics_count.json
Normal file
File diff suppressed because it is too large
Load Diff
4
poetry.lock
generated
4
poetry.lock
generated
@@ -112,7 +112,7 @@ python-versions = "*"
|
|||||||
version = "3.0.4"
|
version = "3.0.4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
category = "main"
|
||||||
description = "Composable command line interface toolkit"
|
description = "Composable command line interface toolkit"
|
||||||
name = "click"
|
name = "click"
|
||||||
optional = false
|
optional = false
|
||||||
@@ -784,7 +784,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
|
|||||||
testing = ["jaraco.itertools", "func-timeout"]
|
testing = ["jaraco.itertools", "func-timeout"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "1c24bb1bd4e00a1d1278ef7adde7fa1629ac0e02ed5ecc4e79a1f753365372fc"
|
content-hash = "c39a5b0162f2941acee38685feb99d3b417a277744f8b74339775ee621d81872"
|
||||||
python-versions = "^3.7"
|
python-versions = "^3.7"
|
||||||
|
|
||||||
[metadata.files]
|
[metadata.files]
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ numpy = "^1.18.1"
|
|||||||
beautifultable = "^0.8.0"
|
beautifultable = "^0.8.0"
|
||||||
wordcloud = "^1.6.0"
|
wordcloud = "^1.6.0"
|
||||||
multidict = "^4.7.5"
|
multidict = "^4.7.5"
|
||||||
|
click = "^7.0"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = "^5.2"
|
pytest = "^5.2"
|
||||||
|
|||||||
1
setup.py
1
setup.py
@@ -19,6 +19,7 @@ package_data = \
|
|||||||
install_requires = \
|
install_requires = \
|
||||||
['addict>=2.2.1,<3.0.0',
|
['addict>=2.2.1,<3.0.0',
|
||||||
'beautifultable>=0.8.0,<0.9.0',
|
'beautifultable>=0.8.0,<0.9.0',
|
||||||
|
'click>=7.0,<8.0',
|
||||||
'multidict>=4.7.5,<5.0.0',
|
'multidict>=4.7.5,<5.0.0',
|
||||||
'musicbrainzngs>=0.7.1,<0.8.0',
|
'musicbrainzngs>=0.7.1,<0.8.0',
|
||||||
'numpy>=1.18.1,<2.0.0',
|
'numpy>=1.18.1,<2.0.0',
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ from collections import Counter
|
|||||||
import html
|
import html
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
import os
|
|
||||||
import string
|
import string
|
||||||
from typing import Union, Dict
|
from typing import Union, Dict
|
||||||
|
|
||||||
@@ -88,8 +87,110 @@ class LyricsBuilder(LyricsConcreteBuilder):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_useragent() -> None:
|
def set_useragent() -> None:
|
||||||
|
"""Sets the useragent for the Musicbrainz api.
|
||||||
|
"""
|
||||||
authenticate.set_useragent()
|
authenticate.set_useragent()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def construct_lyrics_url(artist: str, song: str) -> str:
|
||||||
|
"""Builds the URL for the lyrics api.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
artist : str
|
||||||
|
Artist
|
||||||
|
song : str
|
||||||
|
Track title
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
URL for lyrics from the lyrics api.
|
||||||
|
"""
|
||||||
|
lyrics_api_base = 'https://api.lyrics.ovh/v1'
|
||||||
|
lyrics_api_url = html.escape(f'{lyrics_api_base}/{artist}/{song}')
|
||||||
|
return lyrics_api_url
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def request_lyrics_from_url(url: str) -> str:
|
||||||
|
"""Gets lyrics from the lyrics api.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
url : str
|
||||||
|
URL of the track for the lyrics api.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
Lyrics of the trakc
|
||||||
|
"""
|
||||||
|
resp = requests.get(url)
|
||||||
|
|
||||||
|
# No lyrics for a song will return a key of 'error', we pass on this.
|
||||||
|
try:
|
||||||
|
lyrics = LyricsBuilder.strip_punctuation(resp.json()['lyrics'])
|
||||||
|
return lyrics
|
||||||
|
except (KeyError, json.decoder.JSONDecodeError):
|
||||||
|
return
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def strip_punctuation(word: str) -> str:
|
||||||
|
"""Removes punctuation from lyrics.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
word : str
|
||||||
|
Word to remove punctuation from.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
str
|
||||||
|
Same word without any punctuation.
|
||||||
|
"""
|
||||||
|
_strip = word.translate(str.maketrans('', '', string.punctuation))
|
||||||
|
return _strip
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_descriptive_statistics(nums: list) -> Dict[str, int]:
|
||||||
|
"""Calculates descriptive statistics.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
nums : list
|
||||||
|
A list containing total number of words from a track.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Dict[str, int]
|
||||||
|
Dictionary of statistic and value.
|
||||||
|
"""
|
||||||
|
if len(nums) == 0:
|
||||||
|
return
|
||||||
|
avg = math.ceil(np.mean(nums))
|
||||||
|
median = math.ceil(np.median(nums))
|
||||||
|
std = math.ceil(np.std(nums))
|
||||||
|
max = math.ceil(np.max(nums))
|
||||||
|
min = math.ceil(np.min(nums))
|
||||||
|
p_10 = math.ceil(np.percentile(nums, 10))
|
||||||
|
p_25 = math.ceil(np.percentile(nums, 25))
|
||||||
|
p_75 = math.ceil(np.percentile(nums, 75))
|
||||||
|
p_90 = math.ceil(np.percentile(nums, 90))
|
||||||
|
count = len(nums)
|
||||||
|
_d = addict.Dict(
|
||||||
|
('avg', avg),
|
||||||
|
('median', median),
|
||||||
|
('std', std),
|
||||||
|
('max', max),
|
||||||
|
('min', min),
|
||||||
|
('p_10', p_10),
|
||||||
|
('p_25', p_25),
|
||||||
|
('p_75', p_75),
|
||||||
|
('p_90', p_90),
|
||||||
|
('count', count),
|
||||||
|
)
|
||||||
|
return _d
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
@@ -303,9 +404,6 @@ class LyricsBuilder(LyricsConcreteBuilder):
|
|||||||
)
|
)
|
||||||
self.all_albums_lyrics.append(lyrics)
|
self.all_albums_lyrics.append(lyrics)
|
||||||
bar.update(update)
|
bar.update(update)
|
||||||
|
|
||||||
with open(f'{os.getcwd()}/all_albums_lyrics.json', 'w') as f:
|
|
||||||
json.dump(self.all_albums_lyrics, f, indent=2)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def count_words_in_lyrics(self) -> None:
|
def count_words_in_lyrics(self) -> None:
|
||||||
@@ -420,104 +518,3 @@ class LyricsBuilder(LyricsConcreteBuilder):
|
|||||||
self.year_statistics = addict.Dict(
|
self.year_statistics = addict.Dict(
|
||||||
**self.year_statistics, **addict.Dict((year, _d))
|
**self.year_statistics, **addict.Dict((year, _d))
|
||||||
)
|
)
|
||||||
# pprint(self.year_statistics)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def construct_lyrics_url(artist: str, song: str) -> str:
|
|
||||||
"""Builds the URL for the lyrics api.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
artist : str
|
|
||||||
Artist
|
|
||||||
song : str
|
|
||||||
Track title
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
str
|
|
||||||
URL for lyrics from the lyrics api.
|
|
||||||
"""
|
|
||||||
lyrics_api_base = 'https://api.lyrics.ovh/v1'
|
|
||||||
lyrics_api_url = html.escape(f'{lyrics_api_base}/{artist}/{song}')
|
|
||||||
return lyrics_api_url
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def request_lyrics_from_url(url: str) -> str:
|
|
||||||
"""Gets lyrics from the lyrics api.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
url : str
|
|
||||||
URL of the track for the lyrics api.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
str
|
|
||||||
Lyrics of the trakc
|
|
||||||
"""
|
|
||||||
resp = requests.get(url)
|
|
||||||
|
|
||||||
# No lyrics for a song will return a key of 'error', we pass on this.
|
|
||||||
try:
|
|
||||||
lyrics = LyricsBuilder.strip_punctuation(resp.json()['lyrics'])
|
|
||||||
return lyrics
|
|
||||||
except (KeyError, json.decoder.JSONDecodeError):
|
|
||||||
return
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def strip_punctuation(word: str) -> str:
|
|
||||||
"""Removes punctuation from lyrics.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
word : str
|
|
||||||
Word to remove punctuation from.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
str
|
|
||||||
Same word without any punctuation.
|
|
||||||
"""
|
|
||||||
_strip = word.translate(str.maketrans('', '', string.punctuation))
|
|
||||||
return _strip
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_descriptive_statistics(nums: list) -> Dict[str, int]:
|
|
||||||
"""Calculates descriptive statistics.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
nums : list
|
|
||||||
A list containing total number of words from a track.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
Dict[str, int]
|
|
||||||
Dictionary of statistic and value.
|
|
||||||
"""
|
|
||||||
if len(nums) == 0:
|
|
||||||
return
|
|
||||||
avg = math.ceil(np.mean(nums))
|
|
||||||
median = math.ceil(np.median(nums))
|
|
||||||
std = math.ceil(np.std(nums))
|
|
||||||
max = math.ceil(np.max(nums))
|
|
||||||
min = math.ceil(np.min(nums))
|
|
||||||
p_10 = math.ceil(np.percentile(nums, 10))
|
|
||||||
p_25 = math.ceil(np.percentile(nums, 25))
|
|
||||||
p_75 = math.ceil(np.percentile(nums, 75))
|
|
||||||
p_90 = math.ceil(np.percentile(nums, 90))
|
|
||||||
count = len(nums)
|
|
||||||
_d = addict.Dict(
|
|
||||||
('avg', avg),
|
|
||||||
('median', median),
|
|
||||||
('std', std),
|
|
||||||
('max', max),
|
|
||||||
('min', min),
|
|
||||||
('p_10', p_10),
|
|
||||||
('p_25', p_25),
|
|
||||||
('p_75', p_75),
|
|
||||||
('p_90', p_90),
|
|
||||||
('count', count),
|
|
||||||
)
|
|
||||||
return _d
|
|
||||||
|
|||||||
@@ -114,13 +114,13 @@ class LyricsClickDirector:
|
|||||||
self.builder.all_albums_lyrics
|
self.builder.all_albums_lyrics
|
||||||
)
|
)
|
||||||
self.builder.count_words_in_lyrics()
|
self.builder.count_words_in_lyrics()
|
||||||
with open(f'{os.getcwd()}/lyrics_count.json', 'w+') as file:
|
# with open(f'{os.getcwd()}/lyrics_count.json', 'w+') as file:
|
||||||
json.dump(
|
# json.dump(
|
||||||
self.builder.all_albums_lyrics_count,
|
# self.builder.all_albums_lyrics_count,
|
||||||
file,
|
# file,
|
||||||
indent=2,
|
# indent=2,
|
||||||
sort_keys=True,
|
# sort_keys=True,
|
||||||
)
|
# )
|
||||||
self.builder._product.all_albums_lyrics_count = (
|
self.builder._product.all_albums_lyrics_count = (
|
||||||
self.builder.all_albums_lyrics_count
|
self.builder.all_albums_lyrics_count
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,12 +70,20 @@ class LyricsWordcloud:
|
|||||||
|
|
||||||
return cls(mic_img, all_albums_lyrics_count)
|
return cls(mic_img, all_albums_lyrics_count)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_grey_colours(
|
||||||
|
# word: str,
|
||||||
|
# font_size: str,
|
||||||
|
# random_state: typing.Union[None, bool] = None,
|
||||||
|
*args,
|
||||||
|
**kwargs,
|
||||||
|
) -> str:
|
||||||
|
"""Static method to generate a random grey colour"""
|
||||||
|
colour = f'hsl(0, 0%, {random.randint(60, 100)}%)'
|
||||||
|
return colour
|
||||||
|
|
||||||
def _get_lyrics_list(self) -> None:
|
def _get_lyrics_list(self) -> None:
|
||||||
"""Gets all words from lyrics in a single list + cleans them.
|
"""Gets all words from lyrics in a single list + cleans them.
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
self.lyrics_list = list()
|
self.lyrics_list = list()
|
||||||
for i in self.all_albums_lyrics_count:
|
for i in self.all_albums_lyrics_count:
|
||||||
@@ -109,23 +117,8 @@ class LyricsWordcloud:
|
|||||||
"""
|
"""
|
||||||
self.char_mask = np.array(self.pillow_img)
|
self.char_mask = np.array(self.pillow_img)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def generate_grey_colours(
|
|
||||||
word: str,
|
|
||||||
font_size: str,
|
|
||||||
random_state: typing.Union[None, bool] = None,
|
|
||||||
*args,
|
|
||||||
**kwargs,
|
|
||||||
) -> str:
|
|
||||||
colour = f'hsl(0, 0%, {random.randint(60, 100)}%)'
|
|
||||||
return colour
|
|
||||||
|
|
||||||
def _generate_word_cloud(self) -> None:
|
def _generate_word_cloud(self) -> None:
|
||||||
"""Generates a word cloud
|
"""Generates a word cloud
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
self.wc = WordCloud(
|
self.wc = WordCloud(
|
||||||
max_words=150,
|
max_words=150,
|
||||||
@@ -138,10 +131,6 @@ class LyricsWordcloud:
|
|||||||
|
|
||||||
def _generate_plot(self) -> None:
|
def _generate_plot(self) -> None:
|
||||||
"""Plots the wordcloud and sets matplotlib options.
|
"""Plots the wordcloud and sets matplotlib options.
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
plt.imshow(
|
plt.imshow(
|
||||||
self.wc.recolor(
|
self.wc.recolor(
|
||||||
@@ -159,10 +148,6 @@ class LyricsWordcloud:
|
|||||||
|
|
||||||
def create_word_cloud(self) -> None:
|
def create_word_cloud(self) -> None:
|
||||||
"""Creates a word cloud
|
"""Creates a word cloud
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None
|
|
||||||
"""
|
"""
|
||||||
self._get_lyrics_list()
|
self._get_lyrics_list()
|
||||||
self._get_frequencies()
|
self._get_frequencies()
|
||||||
|
|||||||
BIN
src/musicbrainzapi/wordcloud/resources/.DS_Store
vendored
BIN
src/musicbrainzapi/wordcloud/resources/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 186 KiB |
Reference in New Issue
Block a user