0.1.3: basic top tags
This commit is contained in:
parent
d3916aa641
commit
dfd9e342bb
79
lfcircle.py
79
lfcircle.py
|
@ -32,6 +32,7 @@ For more information, please refer to <http://unlicense.org/>
|
|||
|
||||
from argparse import ArgumentParser
|
||||
from bisect import insort
|
||||
from collections import Counter
|
||||
from datetime import datetime, timedelta
|
||||
from enum import Enum
|
||||
from functools import wraps
|
||||
|
@ -239,6 +240,7 @@ class ListeningReport(NamedTuple):
|
|||
albums_top_new: ThingWithScrobbles
|
||||
tracks_top_new: ThingWithScrobbles
|
||||
listening_time_hours: int
|
||||
tags: dict[str, tuple[int, ...]]
|
||||
|
||||
def to_str(
|
||||
self,
|
||||
|
@ -262,7 +264,8 @@ class ListeningReport(NamedTuple):
|
|||
+ f"{self.user} — Σ{self.listening_time_hours}h; {self.scrobbles_daily_avg}s/d "
|
||||
)
|
||||
basket.append(
|
||||
indent(f"<{self.url}>", prefix=(prefix := " " * len(_prefix))) + "\n"
|
||||
indent(f"<{self.url}>", prefix=(prefix := " " * len(_prefix)))
|
||||
+ "\n"
|
||||
)
|
||||
|
||||
rmax = len(f"#{leaderboard_n}")
|
||||
|
@ -320,6 +323,29 @@ class ListeningReport(NamedTuple):
|
|||
)
|
||||
basket.append(d4_l + d4_r + d4_url)
|
||||
|
||||
# detail 5: top five tags
|
||||
if len(self.tags) > 0:
|
||||
tag_counter = Counter[str]()
|
||||
|
||||
for tag_name, tag_values in self.tags.items():
|
||||
tag_counter.update({tag_name: sum(tag_values)})
|
||||
|
||||
basket.append(
|
||||
indent(
|
||||
(
|
||||
"Top tags".ljust(len(d4_l) - 6)
|
||||
+ " : "
|
||||
+ ", ".join(
|
||||
[
|
||||
f"{tn} ({tc})"
|
||||
for tn, tc in tag_counter.most_common(5)
|
||||
]
|
||||
)
|
||||
),
|
||||
prefix=prefix,
|
||||
)
|
||||
)
|
||||
|
||||
if not behaviour.lowercase:
|
||||
text = "\n".join(basket)
|
||||
|
||||
|
@ -340,7 +366,7 @@ class ListeningReport(NamedTuple):
|
|||
|
||||
# detail 2: total period artist count
|
||||
basket.append(
|
||||
f"{prefix}{self.artists_count} artists (#{leaderboard_artists_pos}): "
|
||||
f"\n{prefix}{self.artists_count} artists (#{leaderboard_artists_pos}): "
|
||||
+ (
|
||||
f"[{self.artists[0].name}]({self.artists[0].url})"
|
||||
if behaviour.all_the_links
|
||||
|
@ -370,6 +396,21 @@ class ListeningReport(NamedTuple):
|
|||
)
|
||||
)
|
||||
|
||||
# detail 5: top tags
|
||||
if len(self.tags) > 0:
|
||||
tag_counter = Counter[str]()
|
||||
|
||||
for tag_name, tag_values in self.tags.items():
|
||||
tag_counter.update({tag_name: sum(tag_values)})
|
||||
|
||||
basket.append(
|
||||
f"\n{prefix}Top tags"
|
||||
+ ": "
|
||||
+ ", ".join(
|
||||
[f"{tn} ({tc})" for tn, tc in tag_counter.most_common(5)]
|
||||
)
|
||||
)
|
||||
|
||||
if not behaviour.lowercase:
|
||||
text = "\n".join(basket)
|
||||
|
||||
|
@ -392,7 +433,6 @@ def get_listening_report(
|
|||
limiter: Limiter,
|
||||
behaviour: Behaviour,
|
||||
) -> ListeningReport:
|
||||
|
||||
target_url: str = f"https://www.last.fm/user/{target}/listening-report/week"
|
||||
|
||||
page_res: Response = limiter.limit(get)(
|
||||
|
@ -422,6 +462,7 @@ def get_listening_report(
|
|||
albums_top_new=_get_albums_top_new(page),
|
||||
tracks_top_new=_get_tracks_top_new(page),
|
||||
listening_time_hours=_get_listening_time_hours(page),
|
||||
tags=_get_tags(page),
|
||||
)
|
||||
|
||||
|
||||
|
@ -520,7 +561,9 @@ def _get_top_overview(
|
|||
if len(top.select(select_needle)) == 0:
|
||||
continue
|
||||
|
||||
assert (_n := top.select(".listening-report-secondary-top-item-name")) is not None
|
||||
assert (
|
||||
_n := top.select(".listening-report-secondary-top-item-name")
|
||||
) is not None
|
||||
assert (
|
||||
_v := top.select(".listening-report-secondary-top-item-value")
|
||||
) is not None
|
||||
|
@ -597,6 +640,34 @@ def _get_tracks_top_new(page: BeautifulSoup) -> ThingWithScrobbles:
|
|||
return _get_top_new_thing(page=page, select_needle=".top-new-item-type__track")
|
||||
|
||||
|
||||
def _get_tags(page: BeautifulSoup) -> dict[str, tuple[int, ...]]:
|
||||
tags: dict[str, tuple[int, ...]] = {}
|
||||
|
||||
assert (_1 := page.select_one("#top-tags-over-time")) is not None
|
||||
assert (_2 := _1.select_one(".js-top-tags-over-time-table")) is not None
|
||||
assert (_3 := _2.select_one("tbody")) is not None
|
||||
|
||||
for tr in _3.select("tr"):
|
||||
tag_name: str = ""
|
||||
tag_counts: list[int] = []
|
||||
|
||||
for i, td in enumerate(tr.select("td")):
|
||||
if i == 0:
|
||||
tag_name = td.text.strip()
|
||||
|
||||
else:
|
||||
assert (
|
||||
num := td.text.strip()
|
||||
).isnumeric(), (
|
||||
"second tag table td onwards should be numeric, but isn't"
|
||||
)
|
||||
tag_counts.append(int(num))
|
||||
|
||||
tags.update({tag_name: tuple(tag_counts)})
|
||||
|
||||
return tags
|
||||
|
||||
|
||||
def _rank(
|
||||
r: ListeningReport, rs: list[ListeningReport], k: Callable[[ListeningReport], int]
|
||||
):
|
||||
|
|
34
poetry.lock
generated
34
poetry.lock
generated
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
|
@ -330,13 +330,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "platformdirs"
|
||||
version = "4.2.1"
|
||||
version = "4.2.2"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "platformdirs-4.2.1-py3-none-any.whl", hash = "sha256:17d5a1161b3fd67b390023cb2d3b026bbd40abde6fdb052dfbd3a29c3ba22ee1"},
|
||||
{file = "platformdirs-4.2.1.tar.gz", hash = "sha256:031cd18d4ec63ec53e82dceaac0417d218a6863f7745dfcc9efe7793b7039bdf"},
|
||||
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
|
||||
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
@ -346,13 +346,13 @@ type = ["mypy (>=1.8)"]
|
|||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
version = "2.32.2"
|
||||
description = "Python HTTP for Humans."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
{file = "requests-2.32.2-py3-none-any.whl", hash = "sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c"},
|
||||
{file = "requests-2.32.2.tar.gz", hash = "sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -400,13 +400,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "types-beautifulsoup4"
|
||||
version = "4.12.0.20240504"
|
||||
version = "4.12.0.20240511"
|
||||
description = "Typing stubs for beautifulsoup4"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-beautifulsoup4-4.12.0.20240504.tar.gz", hash = "sha256:d7b7af4ccc52fc22784d33a529695e34329a9bdd5db6a649c9b25cb2c3a148d5"},
|
||||
{file = "types_beautifulsoup4-4.12.0.20240504-py3-none-any.whl", hash = "sha256:84e04e4473b3c79da04d9d1f89d20a38e5cc92f9c080a8e1f9d36a287b350465"},
|
||||
{file = "types-beautifulsoup4-4.12.0.20240511.tar.gz", hash = "sha256:004f6096fdd83b19cdbf6cb10e4eae57b10205eccc365d0a69d77da836012e28"},
|
||||
{file = "types_beautifulsoup4-4.12.0.20240511-py3-none-any.whl", hash = "sha256:7ceda66a93ba28d759d5046d7fec9f4cad2f563a77b3a789efc90bcadafeefd1"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -425,13 +425,13 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "types-requests"
|
||||
version = "2.31.0.20240406"
|
||||
version = "2.32.0.20240523"
|
||||
description = "Typing stubs for requests"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "types-requests-2.31.0.20240406.tar.gz", hash = "sha256:4428df33c5503945c74b3f42e82b181e86ec7b724620419a2966e2de604ce1a1"},
|
||||
{file = "types_requests-2.31.0.20240406-py3-none-any.whl", hash = "sha256:6216cdac377c6b9a040ac1c0404f7284bd13199c0e1bb235f4324627e8898cf5"},
|
||||
{file = "types-requests-2.32.0.20240523.tar.gz", hash = "sha256:26b8a6de32d9f561192b9942b41c0ab2d8010df5677ca8aa146289d11d505f57"},
|
||||
{file = "types_requests-2.32.0.20240523-py3-none-any.whl", hash = "sha256:f19ed0e2daa74302069bbbbf9e82902854ffa780bc790742a810a9aaa52f65ec"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
@ -439,13 +439,13 @@ urllib3 = ">=2"
|
|||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.11.0"
|
||||
version = "4.12.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"},
|
||||
{file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"},
|
||||
{file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"},
|
||||
{file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[tool.poetry]
|
||||
name = "lfcircle"
|
||||
version = "0.1.2"
|
||||
version = "0.1.3"
|
||||
description = "last.fm statistics generator for your friend circle!"
|
||||
authors = ["Mark Joshwel <mark@joshwel.co>"]
|
||||
license = "Unlicense"
|
||||
|
|
Loading…
Reference in a new issue