yutipy 1.2.0__py3-none-any.whl → 1.3.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/__init__.py CHANGED
@@ -3,6 +3,7 @@ from .itunes import Itunes
3
3
  from .models import MusicInfo
4
4
  from .musicyt import MusicYT
5
5
  from .spotify import Spotify
6
+ from .yutipy_music import YutipyMusic
6
7
 
7
8
  __all__ = [
8
9
  "Deezer",
@@ -10,4 +11,5 @@ __all__ = [
10
11
  "MusicInfo",
11
12
  "MusicYT",
12
13
  "Spotify",
14
+ "YutipyMusic",
13
15
  ]
yutipy/deezer.py CHANGED
@@ -28,7 +28,7 @@ class Deezer:
28
28
 
29
29
  def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
30
30
  """Exits the runtime context related to this object."""
31
- self._close_session()
31
+ self.close_session()
32
32
 
33
33
  def close_session(self) -> None:
34
34
  """Closes the current session."""
@@ -238,7 +238,7 @@ class Deezer:
238
238
  album_title=(
239
239
  result["album"]["title"] if music_type == "track" else result["title"]
240
240
  ),
241
- album_type=result.get("record_type", music_type),
241
+ album_type=result.get("record_type", music_type.replace("track", "single")),
242
242
  artists=result["artist"]["name"],
243
243
  genre=None,
244
244
  id=result["id"],
@@ -273,4 +273,4 @@ if __name__ == "__main__":
273
273
  song_name = input("Song Name: ")
274
274
  pprint(deezer.search(artist_name, song_name))
275
275
  finally:
276
- deezer._close_session()
276
+ deezer.close_session()
yutipy/itunes.py CHANGED
@@ -29,7 +29,7 @@ class Itunes:
29
29
 
30
30
  def __exit__(self, exc_type, exc_value, exc_traceback) -> None:
31
31
  """Exits the runtime context related to this object."""
32
- self._close_session()
32
+ self.close_session()
33
33
 
34
34
  def close_session(self) -> None:
35
35
  """Closes the current session."""
@@ -186,4 +186,4 @@ if __name__ == "__main__":
186
186
  song_name = input("Song Name: ")
187
187
  pprint(itunes.search(artist_name, song_name))
188
188
  finally:
189
- itunes._close_session()
189
+ itunes.close_session()
yutipy/kkbox.py CHANGED
@@ -64,7 +64,7 @@ class KKBox:
64
64
 
65
65
  def __exit__(self, exc_type, exc_value, exc_traceback):
66
66
  """Exits the runtime context related to this object."""
67
- self._close_session()
67
+ self.close_session()
68
68
 
69
69
  def close_session(self) -> None:
70
70
  """Closes the current session."""
yutipy/models.py CHANGED
@@ -1,5 +1,5 @@
1
- from dataclasses import dataclass
2
- from typing import Optional
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, Dict, Union
3
3
 
4
4
 
5
5
  @dataclass
@@ -19,8 +19,8 @@ class MusicInfo:
19
19
  Name(s) of the artist(s).
20
20
  genre : Optional[str]
21
21
  Genre of the music.
22
- id : str
23
- Unique identifier for the music.
22
+ id : Union[int, str, Dict[str, str]]
23
+ Unique identifier(s) for the music from different platforms.
24
24
  isrc : Optional[str]
25
25
  International Standard Recording Code.
26
26
  lyrics : Optional[str]
@@ -35,21 +35,34 @@ class MusicInfo:
35
35
  Type of the music (e.g., track, album).
36
36
  upc : Optional[str]
37
37
  Universal Product Code.
38
- url : str
39
- URL to the music on the platform.
38
+ url : Union[str, Dict[str, str]]
39
+ URL(s) to the music on different platforms.
40
40
  """
41
41
 
42
- album_art: Optional[str]
43
- album_title: Optional[str]
44
- album_type: Optional[str]
45
- artists: str
46
- genre: Optional[str]
47
- id: str
48
- isrc: Optional[str]
49
- lyrics: Optional[str]
50
- release_date: Optional[str]
51
- tempo: Optional[float]
52
- title: str
53
- type: Optional[str]
54
- upc: Optional[str]
55
- url: str
42
+ album_art: Optional[str] = None
43
+ album_title: Optional[str] = None
44
+ album_type: Optional[str] = None
45
+ artists: str = ""
46
+ genre: Optional[str] = None
47
+ id: Union[int, str, Dict[str, int]] = field(default_factory=dict)
48
+ isrc: Optional[str] = None
49
+ lyrics: Optional[str] = None
50
+ release_date: Optional[str] = None
51
+ tempo: Optional[float] = None
52
+ title: str = ""
53
+ type: Optional[str] = None
54
+ upc: Optional[str] = None
55
+ url: Union[str, Dict[str, str]] = field(default_factory=dict)
56
+
57
+
58
+ @dataclass
59
+ class MusicInfos(MusicInfo):
60
+ """A data class to store music information from different services.
61
+
62
+ Attributes
63
+ ----------
64
+ album_art_source : Optional[str]
65
+ The source of the album art.
66
+ """
67
+
68
+ album_art_source: Optional[str] = None
yutipy/spotify.py CHANGED
@@ -69,7 +69,7 @@ class Spotify:
69
69
 
70
70
  def __exit__(self, exc_type, exc_value, exc_traceback):
71
71
  """Exits the runtime context related to this object."""
72
- self._close_session()
72
+ self.close_session()
73
73
 
74
74
  def close_session(self) -> None:
75
75
  """Closes the current session."""
@@ -1,3 +1,45 @@
1
+ import requests
2
+ from rapidfuzz import fuzz
3
+ from rapidfuzz.utils import default_process
4
+
5
+
6
+ def translate_text(
7
+ text: str,
8
+ sl: str = None,
9
+ dl: str = "en",
10
+ ) -> dict:
11
+ """
12
+ Translate text from one language to another.
13
+
14
+ Args:
15
+ text (str): The text to be translated.
16
+ sl (str, optional): The source language code (e.g., 'en' for English, 'es' for Spanish). If not provided, the API will attempt to detect the source language.
17
+ dl (str, optional): The destination language code (default is 'en' for English).
18
+
19
+
20
+ Returns:
21
+ dict: A dictionary containing the following keys:
22
+ - 'source-text': The original text.
23
+ - 'source-language': The detected or provided source language code.
24
+ - 'destination-text': The translated text.
25
+ - 'destination-language': The destination language code.
26
+ """
27
+ if sl:
28
+ url = f"https://ftapi.pythonanywhere.com/translate?sl={sl}&dl={dl}&text={text}"
29
+ else:
30
+ url = f"https://ftapi.pythonanywhere.com/translate?dl={dl}&text={text}"
31
+
32
+ response = requests.get(url)
33
+ response_json = response.json()
34
+ result = {
35
+ "source-text": response_json["source-text"],
36
+ "source-language": response_json["source-language"],
37
+ "destination-text": response_json["destination-text"],
38
+ "destination-language": response_json["destination-language"],
39
+ }
40
+ return result
41
+
42
+
1
43
  def are_strings_similar(str1: str, str2: str, threshold: int = 80) -> bool:
2
44
  """
3
45
  Determine if two strings are similar based on a given threshold.
@@ -10,8 +52,8 @@ def are_strings_similar(str1: str, str2: str, threshold: int = 80) -> bool:
10
52
  Returns:
11
53
  bool: True if the strings are similar, otherwise False.
12
54
  """
13
- from rapidfuzz import fuzz
14
- from rapidfuzz.utils import default_process
55
+ str1 = translate_text(str1)["destination-text"]
56
+ str2 = translate_text(str2)["destination-text"]
15
57
 
16
58
  similarity_score = fuzz.WRatio(str1, str2, processor=default_process)
17
59
  return similarity_score > threshold
yutipy/yutipy_music.py ADDED
@@ -0,0 +1,122 @@
1
+ from concurrent.futures import ThreadPoolExecutor, as_completed
2
+ from pprint import pprint
3
+ from typing import Optional
4
+
5
+ from yutipy.deezer import Deezer
6
+ from yutipy.exceptions import InvalidValueException
7
+ from yutipy.itunes import Itunes
8
+ from yutipy.kkbox import KKBox
9
+ from yutipy.models import MusicInfo, MusicInfos
10
+ from yutipy.musicyt import MusicYT
11
+ from yutipy.spotify import Spotify
12
+ from yutipy.utils.cheap_utils import is_valid_string
13
+
14
+
15
+ class YutipyMusic:
16
+ """A class that can be used to retrieve music information from all music platforms available in ``yutipy``.
17
+
18
+ This is useful when you want to get music information (especially streaming link) from all available platforms.
19
+ Instead of calling each service separately, you can use this class to get the information from all services at once.
20
+ """
21
+
22
+ def __init__(self) -> None:
23
+ """Initializes the YutipyMusic class."""
24
+ self.music_info = MusicInfos()
25
+ self.album_art_priority = ["deezer", "kkbox", "spotify", "musicyt", "itunes"]
26
+
27
+ def search(self, artist: str, song: str) -> Optional[MusicInfos]:
28
+ """
29
+ Searches for a song by artist and title.
30
+
31
+ Parameters
32
+ ----------
33
+ artist : str
34
+ The name of the artist.
35
+ song : str
36
+ The title of the song.
37
+
38
+ Returns
39
+ -------
40
+ Optional[MusicInfos_]
41
+ The music information if found, otherwise None.
42
+ """
43
+ if not is_valid_string(artist) or not is_valid_string(song):
44
+ raise InvalidValueException(
45
+ "Artist and song names must be valid strings and can't be empty."
46
+ )
47
+
48
+ services = [
49
+ (Deezer, "deezer"),
50
+ (Itunes, "itunes"),
51
+ (KKBox, "kkbox"),
52
+ (MusicYT, "musicyt"),
53
+ (Spotify, "spotify"),
54
+ ]
55
+
56
+ with ThreadPoolExecutor() as executor:
57
+ futures = {
58
+ executor.submit(service().search, artist, song): name
59
+ for service, name in services
60
+ }
61
+
62
+ for future in as_completed(futures):
63
+ service_name = futures[future]
64
+ result = future.result()
65
+ self._combine_results(result, service_name)
66
+
67
+ return self.music_info if self.music_info else None
68
+
69
+ def _combine_results(self, result: Optional[MusicInfo], service_name: str) -> None:
70
+ """
71
+ Combines the results from different services.
72
+
73
+ Parameters
74
+ ----------
75
+ result : Optional[MusicInfo]
76
+ The music information from a service.
77
+ service_name : str
78
+ The name of the streaming service.
79
+ """
80
+ if not result:
81
+ return
82
+
83
+ attributes = [
84
+ "album_title",
85
+ "album_type",
86
+ "artists",
87
+ "genre",
88
+ "isrc",
89
+ "lyrics",
90
+ "release_date",
91
+ "tempo",
92
+ "title",
93
+ "type",
94
+ "upc",
95
+ ]
96
+
97
+ for attr in attributes:
98
+ if getattr(result, attr) and (
99
+ not getattr(self.music_info, attr) or service_name == "spotify"
100
+ ):
101
+ setattr(self.music_info, attr, getattr(result, attr))
102
+
103
+ if result.album_art:
104
+ current_priority = self.album_art_priority.index(service_name)
105
+ existing_priority = (
106
+ self.album_art_priority.index(self.music_info.album_art_source)
107
+ if self.music_info.album_art_source
108
+ else len(self.album_art_priority)
109
+ )
110
+ if current_priority < existing_priority:
111
+ self.music_info.album_art = result.album_art
112
+ self.music_info.album_art_source = service_name
113
+
114
+ self.music_info.id[service_name] = result.id
115
+ self.music_info.url[service_name] = result.url
116
+
117
+
118
+ if __name__ == "__main__":
119
+ yutipy_music = YutipyMusic()
120
+ artist_name = input("Artist Name: ")
121
+ song_name = input("Song Name: ")
122
+ pprint(yutipy_music.search(artist_name, song_name))
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 1.2.0
3
+ Version: 1.3.0
4
4
  Summary: A simple package for retrieving music information from various music platforms APIs.
5
5
  Author: Cheap Nightbot
6
6
  Author-email: Cheap Nightbot <hi@cheapnightbot.slmail.me>
@@ -54,6 +54,7 @@ Requires-Dist: requests==2.32.3
54
54
  Requires-Dist: ytmusicapi==1.10.1
55
55
  Provides-Extra: dev
56
56
  Requires-Dist: pytest; extra == "dev"
57
+ Dynamic: license-file
57
58
 
58
59
  <p align="center">
59
60
  <img src="https://raw.githubusercontent.com/CheapNightbot/yutipy/main/docs/_static/yutipy_header.png" alt="yutipy" />
@@ -0,0 +1,16 @@
1
+ yutipy/__init__.py,sha256=UIymi9iT8s1nGuqcQcFudZYNsJDR4RzXe6LUaN9V8l0,289
2
+ yutipy/deezer.py,sha256=eLaDNBnpdFpvdxEQrgTZiLl-FBjSs1R0CKEgpgRi0Us,8666
3
+ yutipy/exceptions.py,sha256=4L0Oe1PwFP34LoFTy-Fruipk7uB-JkaackRmkjlaZJU,1138
4
+ yutipy/itunes.py,sha256=SmW6bCGKB9ADG2FxggGDmEOvqAIvuRi7aOkBSyHm2HQ,5841
5
+ yutipy/kkbox.py,sha256=9sz8eb-pu-47DTP_4kgackX1ZLijnCnz7q_1M8BqLWo,12185
6
+ yutipy/models.py,sha256=si_qgaApAYDfSyE8cl_Yg4IfWOtxk1I5JCT8bZsmV4U,1931
7
+ yutipy/musicyt.py,sha256=kvRYuhlNVuvy-WahJq895T3JAzmGTTiKB89r_uTMTAI,7155
8
+ yutipy/spotify.py,sha256=Oaktvdz7gLe2_PaktOmjlc8QpfhZWkmQnIZDmwoXlRE,13608
9
+ yutipy/yutipy_music.py,sha256=YZ_5iIjHr_QA3YAm2usR7hUqJMevu2ZVSQ59Q82Axj0,4053
10
+ yutipy/utils/__init__.py,sha256=7UFcFZ7fBtNXOTngjnRD3MeobT3x5UT2Gag94TXVgLk,169
11
+ yutipy/utils/cheap_utils.py,sha256=Yl0ssVbyvrdVeSPF7PqpGJpwTYLVa4CMgLtr6uk67v0,3104
12
+ yutipy-1.3.0.dist-info/licenses/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
13
+ yutipy-1.3.0.dist-info/METADATA,sha256=p76rSDWegRztp7pl8eZ8LQh5FQsYi3aIH2eun9raX-A,6489
14
+ yutipy-1.3.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
15
+ yutipy-1.3.0.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
16
+ yutipy-1.3.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.2)
2
+ Generator: setuptools (78.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,15 +0,0 @@
1
- yutipy/__init__.py,sha256=t0w-pRLjIGD3UtDyd-JpeL-RrMona7YTV_0lZCpGLEc,232
2
- yutipy/deezer.py,sha256=TbPk6f1ytrtk9GHXOoRZ948fcgOi0619-rQC9xfTYu0,8641
3
- yutipy/exceptions.py,sha256=4L0Oe1PwFP34LoFTy-Fruipk7uB-JkaackRmkjlaZJU,1138
4
- yutipy/itunes.py,sha256=NhrllA3U0PUY3dNoMyiG1oZuyvdMQKYRBHzYSkt8ikM,5843
5
- yutipy/kkbox.py,sha256=yuyEanxxOXsiL2ZTtJMraETQxDetWfUu9K8IULSKQrQ,12186
6
- yutipy/models.py,sha256=RnfWjoNO1UoNsRvNRYd-4TpkU-4jHKu5t394vIqOOgw,1360
7
- yutipy/musicyt.py,sha256=kvRYuhlNVuvy-WahJq895T3JAzmGTTiKB89r_uTMTAI,7155
8
- yutipy/spotify.py,sha256=CZA9XF0EV5wSrLrN9cURtiFKSEHsIvqVlXLKkvb4JEM,13609
9
- yutipy/utils/__init__.py,sha256=7UFcFZ7fBtNXOTngjnRD3MeobT3x5UT2Gag94TXVgLk,169
10
- yutipy/utils/cheap_utils.py,sha256=LIuEHib_97NuLahXxdHJUD9v-ccXNUc3NrLYk8EQ52A,1652
11
- yutipy-1.2.0.dist-info/LICENSE,sha256=_89JsS2QnBG8tAb5-VWbJDj_uJ002zPJAYBJJdh3DPY,1071
12
- yutipy-1.2.0.dist-info/METADATA,sha256=GZOfBMev_zfoZ2JWhFM60t85GkOU2rerxowo1CFqR4c,6467
13
- yutipy-1.2.0.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
14
- yutipy-1.2.0.dist-info/top_level.txt,sha256=t2A5V2_mUcfnHkbCy6tAQlb3909jDYU5GQgXtA4756I,7
15
- yutipy-1.2.0.dist-info/RECORD,,