yutipy 2.3.6__py3-none-any.whl → 2.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yutipy might be problematic. Click here for more details.
- yutipy/lastfm.py +6 -1
- yutipy/listenbrainz.py +141 -0
- yutipy/utils/helpers.py +1 -1
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/METADATA +2 -1
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/RECORD +9 -8
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/WHEEL +0 -0
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/entry_points.txt +0 -0
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {yutipy-2.3.6.dist-info → yutipy-2.4.0.dist-info}/top_level.txt +0 -0
yutipy/lastfm.py
CHANGED
|
@@ -71,6 +71,11 @@ class LastFm:
|
|
|
71
71
|
"""
|
|
72
72
|
Fetches the user profile information for the provided username.
|
|
73
73
|
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
username : str
|
|
77
|
+
The Last.fm username to fetch profile information for.
|
|
78
|
+
|
|
74
79
|
Returns
|
|
75
80
|
-------
|
|
76
81
|
dict
|
|
@@ -109,7 +114,7 @@ class LastFm:
|
|
|
109
114
|
|
|
110
115
|
def get_currently_playing(self, username: str) -> Optional[UserPlaying]:
|
|
111
116
|
"""
|
|
112
|
-
Fetches information about the currently playing
|
|
117
|
+
Fetches information about the currently playing track for a user.
|
|
113
118
|
|
|
114
119
|
Parameters
|
|
115
120
|
----------
|
yutipy/listenbrainz.py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
__all__ = ["ListenBrainz"]
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from time import time
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
|
|
8
|
+
from yutipy.logger import logger
|
|
9
|
+
from yutipy.models import UserPlaying
|
|
10
|
+
from yutipy.utils.helpers import are_strings_similar
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ListenBrainz:
|
|
14
|
+
"""A class to interact with the ListenBrainz API for fetching user music data."""
|
|
15
|
+
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self._is_session_closed = False
|
|
18
|
+
self.__api_url = "https://api.listenbrainz.org"
|
|
19
|
+
self.__session = requests.Session()
|
|
20
|
+
|
|
21
|
+
def __enter__(self):
|
|
22
|
+
return self
|
|
23
|
+
|
|
24
|
+
def __exit__(self, exc_type, exc_value, exc_traceback):
|
|
25
|
+
self.close_session()
|
|
26
|
+
|
|
27
|
+
def close_session(self):
|
|
28
|
+
"""Closes the current session(s)."""
|
|
29
|
+
if not self._is_session_closed:
|
|
30
|
+
self.__session.close()
|
|
31
|
+
self._is_session_closed = True
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def is_session_closed(self) -> bool:
|
|
35
|
+
"""Checks if the session is closed."""
|
|
36
|
+
return self._is_session_closed
|
|
37
|
+
|
|
38
|
+
def find_user(self, username: str) -> Optional[str]:
|
|
39
|
+
"""
|
|
40
|
+
Whether profile with the provided username exists on the ListenBrainz.
|
|
41
|
+
|
|
42
|
+
It searches ListenBrainz for the provided username and fuzzy matches
|
|
43
|
+
the provided username with the username(s) returned from ListenBrainz API.
|
|
44
|
+
|
|
45
|
+
Parameters
|
|
46
|
+
----------
|
|
47
|
+
username : str
|
|
48
|
+
The username to search.
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
Optional[str]
|
|
53
|
+
The username returned by ListenBrainz API if user found,
|
|
54
|
+
or ``None`` if the user with provided username does not exist.
|
|
55
|
+
"""
|
|
56
|
+
endpoint = "/1/search/users/"
|
|
57
|
+
url = self.__api_url + endpoint
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
response = self.__session.get(
|
|
61
|
+
url=url, params={"search_term": username}, timeout=30
|
|
62
|
+
)
|
|
63
|
+
response.raise_for_status()
|
|
64
|
+
except requests.RequestException as e:
|
|
65
|
+
logger.warning(f"Failed to search for the user: {e}")
|
|
66
|
+
return
|
|
67
|
+
|
|
68
|
+
response_json = response.json()
|
|
69
|
+
users = response_json.get("users")
|
|
70
|
+
|
|
71
|
+
if not users:
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
for user in users:
|
|
75
|
+
user_name = user.get("user_name")
|
|
76
|
+
if are_strings_similar(
|
|
77
|
+
username, user_name, threshold=100, use_translation=False
|
|
78
|
+
):
|
|
79
|
+
return user_name
|
|
80
|
+
|
|
81
|
+
def get_currently_playing(self, username: str) -> Optional[UserPlaying]:
|
|
82
|
+
"""
|
|
83
|
+
Fetches information about the currently playing track for a user.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
username : str
|
|
88
|
+
The ListenBrainz username to fetch data for.
|
|
89
|
+
|
|
90
|
+
Returns
|
|
91
|
+
-------
|
|
92
|
+
Optional[UserPlaying_]
|
|
93
|
+
An instance of the ``UserPlaying`` model containing details about the currently
|
|
94
|
+
playing track if available, or ``None`` if the request fails or no data is available.
|
|
95
|
+
"""
|
|
96
|
+
endpoint = f"/1/user/{username}/playing-now"
|
|
97
|
+
url = self.__api_url + endpoint
|
|
98
|
+
|
|
99
|
+
try:
|
|
100
|
+
response = self.__session.get(url=url, timeout=30)
|
|
101
|
+
response.raise_for_status()
|
|
102
|
+
except requests.RequestException as e:
|
|
103
|
+
logger.warning(f"Failed to retrieve listening activity: {e}")
|
|
104
|
+
return
|
|
105
|
+
|
|
106
|
+
response_json = response.json()
|
|
107
|
+
if not response_json:
|
|
108
|
+
logger.info(
|
|
109
|
+
f"It seems no activity found for `{username}`. Might be user does not exist or not no data available."
|
|
110
|
+
)
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
result = response_json.get("payload", {})
|
|
114
|
+
is_playing = result.get("playing_now", False)
|
|
115
|
+
user_id = result.get("user_id", "")
|
|
116
|
+
|
|
117
|
+
if username.lower() != user_id.lower():
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
if result and is_playing:
|
|
121
|
+
track_metadata = result.get("listens", [{}])[0].get("track_metadata", {})
|
|
122
|
+
return UserPlaying(
|
|
123
|
+
artists=track_metadata.get("artist_name"),
|
|
124
|
+
id=None,
|
|
125
|
+
timestamp=time(),
|
|
126
|
+
title=track_metadata.get("track_name"),
|
|
127
|
+
url=track_metadata.get("additional_info", {}).get("origin_url"),
|
|
128
|
+
is_playing=is_playing,
|
|
129
|
+
)
|
|
130
|
+
return None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
if __name__ == "__main__":
|
|
134
|
+
with ListenBrainz() as listenbrainz:
|
|
135
|
+
username = input("Enter ListenBrainz Username: ").strip()
|
|
136
|
+
result = listenbrainz.find_user(username)
|
|
137
|
+
|
|
138
|
+
if result:
|
|
139
|
+
print(f"User found with username: {result}")
|
|
140
|
+
else:
|
|
141
|
+
print(f"No user with username '{username}' found!")
|
yutipy/utils/helpers.py
CHANGED
|
@@ -76,7 +76,7 @@ def are_strings_similar(
|
|
|
76
76
|
Args:
|
|
77
77
|
str1 (str): First string to compare.
|
|
78
78
|
str2 (str): Second string to compare.
|
|
79
|
-
threshold (int, optional): Similarity threshold. Defaults to
|
|
79
|
+
threshold (int, optional): Similarity threshold. Defaults to 95.
|
|
80
80
|
use_translation (bool, optional): Use translations to compare strings. Defaults to ``True``
|
|
81
81
|
translation_session (requests.Session, optional): A `requests.Session` object to use for making the API request. If not provided, a new session will be created and closed within the function.
|
|
82
82
|
Providing your own session can improve performance by reusing the same session for multiple requests. Don't forget to close the session afterwards.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yutipy
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: A simple Python package to interact with various music platforms APIs.
|
|
5
5
|
Author: Cheap Nightbot
|
|
6
6
|
Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
|
|
@@ -92,6 +92,7 @@ Feel free to request any music platform you would like me to add by opening an i
|
|
|
92
92
|
- `iTunes`: https://music.apple.com
|
|
93
93
|
- `KKBOX`: https://www.kkbox.com
|
|
94
94
|
- `Lastfm`: https://last.fm
|
|
95
|
+
- `ListenBrainz`: https://listenbrainz.org
|
|
95
96
|
- `Spotify`: https://spotify.com
|
|
96
97
|
- `YouTube Music`: https://music.youtube.com
|
|
97
98
|
|
|
@@ -4,7 +4,8 @@ yutipy/deezer.py,sha256=WzqC4ylZo7VmbyAfVZarvaqmnlamdEge3ceY_OJ9h4Y,11021
|
|
|
4
4
|
yutipy/exceptions.py,sha256=zz0XyyZr5xRcmRyw3hdTGaVRcwRn_RSYZdmwmuO0sEM,1379
|
|
5
5
|
yutipy/itunes.py,sha256=_iWq1COXNAiLIrUtwfI1jNey9dXe3-gCzoRF0eGgTs8,8038
|
|
6
6
|
yutipy/kkbox.py,sha256=nvclRgGqQHUzIS_zhbJp_PJHiWmkU3nzwLAUhdaPCLI,12103
|
|
7
|
-
yutipy/lastfm.py,sha256=
|
|
7
|
+
yutipy/lastfm.py,sha256=UylKs6yHOvnSguW7KJHx5yzPuOUXP3haqm_5TdOQKLA,5889
|
|
8
|
+
yutipy/listenbrainz.py,sha256=dhTy5sFHmMUGdp6MyDQtNH2xSKMobq7PzQqyWDi7YXw,4518
|
|
8
9
|
yutipy/logger.py,sha256=GyLBlfQZ6pLNJ5MbyQSvcD_PkxmFdX41DPq5aeG1z68,1316
|
|
9
10
|
yutipy/lrclib.py,sha256=7EFoCZ7kF2blbwA81tzyCrmIIvuuWsE2aO3SfNyyWEc,5220
|
|
10
11
|
yutipy/models.py,sha256=45M-bNHusaAan_Ta_E9DyvsWujsT-ivbJqIfy2-i3R8,2343
|
|
@@ -15,10 +16,10 @@ yutipy/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
15
16
|
yutipy/cli/config.py,sha256=e5RIq6RxVxxzx30nKVMa06gwyQ258s7U0WA1xvJuR_0,4543
|
|
16
17
|
yutipy/cli/search.py,sha256=8SQw0bjRzRqAg-FuVz9aWjB2KBZqmCf38SyKAQ3rx5E,3025
|
|
17
18
|
yutipy/utils/__init__.py,sha256=AZaqvs6AJwnqwJuodbGnHu702WSUqc8plVC16SppOcU,239
|
|
18
|
-
yutipy/utils/helpers.py,sha256=
|
|
19
|
-
yutipy-2.
|
|
20
|
-
yutipy-2.
|
|
21
|
-
yutipy-2.
|
|
22
|
-
yutipy-2.
|
|
23
|
-
yutipy-2.
|
|
24
|
-
yutipy-2.
|
|
19
|
+
yutipy/utils/helpers.py,sha256=ia9egDoRfDqUJvVTsuGk08pf6-n4hZITrvPPtXCohIY,7413
|
|
20
|
+
yutipy-2.4.0.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
|
|
21
|
+
yutipy-2.4.0.dist-info/METADATA,sha256=WvofogvK5MjOEevTwdfsXvm81uRw16mSwTeZC_8EfjE,6620
|
|
22
|
+
yutipy-2.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
yutipy-2.4.0.dist-info/entry_points.txt,sha256=BrgmanaPjQqKQ3Ip76JLcsPgGANtrBSURf5CNIxl1HA,106
|
|
24
|
+
yutipy-2.4.0.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
|
|
25
|
+
yutipy-2.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|