yutipy 1.2.1__tar.gz → 1.3.0__tar.gz

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.

Files changed (53) hide show
  1. {yutipy-1.2.1 → yutipy-1.3.0}/PKG-INFO +1 -1
  2. {yutipy-1.2.1 → yutipy-1.3.0}/docs/api_reference.rst +16 -0
  3. {yutipy-1.2.1 → yutipy-1.3.0}/docs/usage_examples.rst +12 -1
  4. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/__init__.py +2 -0
  5. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/deezer.py +2 -2
  6. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/itunes.py +1 -1
  7. yutipy-1.3.0/yutipy/models.py +68 -0
  8. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/utils/cheap_utils.py +44 -2
  9. yutipy-1.3.0/yutipy/yutipy_music.py +122 -0
  10. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy.egg-info/PKG-INFO +1 -1
  11. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy.egg-info/SOURCES.txt +1 -0
  12. yutipy-1.2.1/yutipy/models.py +0 -55
  13. {yutipy-1.2.1 → yutipy-1.3.0}/.gitattributes +0 -0
  14. {yutipy-1.2.1 → yutipy-1.3.0}/.github/FUNDING.yml +0 -0
  15. {yutipy-1.2.1 → yutipy-1.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  16. {yutipy-1.2.1 → yutipy-1.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  17. {yutipy-1.2.1 → yutipy-1.3.0}/.github/workflows/pytest-unit-testing.yml +0 -0
  18. {yutipy-1.2.1 → yutipy-1.3.0}/.github/workflows/release.yml +0 -0
  19. {yutipy-1.2.1 → yutipy-1.3.0}/.gitignore +0 -0
  20. {yutipy-1.2.1 → yutipy-1.3.0}/.readthedocs.yaml +0 -0
  21. {yutipy-1.2.1 → yutipy-1.3.0}/LICENSE +0 -0
  22. {yutipy-1.2.1 → yutipy-1.3.0}/MANIFEST.in +0 -0
  23. {yutipy-1.2.1 → yutipy-1.3.0}/README.md +0 -0
  24. {yutipy-1.2.1 → yutipy-1.3.0}/docs/Makefile +0 -0
  25. {yutipy-1.2.1 → yutipy-1.3.0}/docs/_static/yutipy_header.png +0 -0
  26. {yutipy-1.2.1 → yutipy-1.3.0}/docs/_static/yutipy_logo.png +0 -0
  27. {yutipy-1.2.1 → yutipy-1.3.0}/docs/available_platforms.rst +0 -0
  28. {yutipy-1.2.1 → yutipy-1.3.0}/docs/conf.py +0 -0
  29. {yutipy-1.2.1 → yutipy-1.3.0}/docs/faq.rst +0 -0
  30. {yutipy-1.2.1 → yutipy-1.3.0}/docs/index.rst +0 -0
  31. {yutipy-1.2.1 → yutipy-1.3.0}/docs/installation.rst +0 -0
  32. {yutipy-1.2.1 → yutipy-1.3.0}/docs/make.bat +0 -0
  33. {yutipy-1.2.1 → yutipy-1.3.0}/docs/requirements.txt +0 -0
  34. {yutipy-1.2.1 → yutipy-1.3.0}/pyproject.toml +0 -0
  35. {yutipy-1.2.1 → yutipy-1.3.0}/requirements-dev.txt +0 -0
  36. {yutipy-1.2.1 → yutipy-1.3.0}/requirements.txt +0 -0
  37. {yutipy-1.2.1 → yutipy-1.3.0}/setup.cfg +0 -0
  38. {yutipy-1.2.1 → yutipy-1.3.0}/tests/__init__.py +0 -0
  39. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_deezer.py +0 -0
  40. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_itunes.py +0 -0
  41. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_kkbox.py +0 -0
  42. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_models.py +0 -0
  43. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_musicyt.py +0 -0
  44. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_spotify.py +0 -0
  45. {yutipy-1.2.1 → yutipy-1.3.0}/tests/test_utils.py +0 -0
  46. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/exceptions.py +0 -0
  47. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/kkbox.py +0 -0
  48. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/musicyt.py +0 -0
  49. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/spotify.py +0 -0
  50. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy/utils/__init__.py +0 -0
  51. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy.egg-info/dependency_links.txt +0 -0
  52. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy.egg-info/requires.txt +0 -0
  53. {yutipy-1.2.1 → yutipy-1.3.0}/yutipy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 1.2.1
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>
@@ -49,6 +49,14 @@ YouTube Music
49
49
  :inherited-members:
50
50
  :noindex:
51
51
 
52
+ Yutipy Music
53
+ ------------
54
+
55
+ .. autoclass:: yutipy.yutipy_music.YutipyMusic
56
+ :members:
57
+ :inherited-members:
58
+ :noindex:
59
+
52
60
  Data Classes
53
61
  =============
54
62
 
@@ -60,6 +68,14 @@ MusicInfo
60
68
  :noindex:
61
69
  :exclude-members: album_art, album_title, album_type, artists, genre, id, isrc, lyrics, release_date, tempo, title, type, upc, url
62
70
 
71
+ MusicInfos
72
+ ----------
73
+
74
+ .. autoclass:: yutipy.models.MusicInfos
75
+ :members:
76
+ :noindex:
77
+ :exclude-members: album_art, album_art_source, album_title, album_type, artists, genre, id, isrc, lyrics, release_date, tempo, title, type, upc, url
78
+
63
79
  Exceptions
64
80
  =============
65
81
 
@@ -5,7 +5,7 @@ Usage Examples
5
5
  Here's a quick example of how to use the **yutipy** package to search for a song:
6
6
 
7
7
  .. important::
8
- All examples here—except for the `YouTube Music`_—use the ``with`` context manager to initialize an instance of the respective class,
8
+ All examples here—except for the `YouTube Music`_ & `Yutipy Music`_—use the ``with`` context manager to initialize an instance of the respective class,
9
9
  as those classes internally use ``requests.Session()`` for making requests to APIs.
10
10
  This approach ensures that the session is automatically closed once you exit the context. Although using ``with`` is not mandatory,
11
11
  if you instantiate an object without it, you are responsible for closing the session after use by calling the ``close_session()`` method on that object.
@@ -110,3 +110,14 @@ YouTube Music
110
110
  music_yt = MusicYT()
111
111
  result = music_yt.search("Artist Name", "Song Title")
112
112
  print(result)
113
+
114
+ Yutipy Music
115
+ ------------
116
+
117
+ .. code-block:: python
118
+
119
+ from yutipy.yutify_music import YutipyMusic
120
+
121
+ yutipy_music = YutipyMusic()
122
+ result = yutify_music.search("Artist Name", "Song Title")
123
+ print(result)
@@ -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
  ]
@@ -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()
@@ -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()
@@ -0,0 +1,68 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, Dict, Union
3
+
4
+
5
+ @dataclass
6
+ class MusicInfo:
7
+ """
8
+ A data class to store music information.
9
+
10
+ Attributes
11
+ ----------
12
+ album_art : Optional[str]
13
+ URL to the album art.
14
+ album_title : Optional[str]
15
+ Title of the album.
16
+ album_type : Optional[str]
17
+ Type of the album (e.g., album, single).
18
+ artists : str
19
+ Name(s) of the artist(s).
20
+ genre : Optional[str]
21
+ Genre of the music.
22
+ id : Union[int, str, Dict[str, str]]
23
+ Unique identifier(s) for the music from different platforms.
24
+ isrc : Optional[str]
25
+ International Standard Recording Code.
26
+ lyrics : Optional[str]
27
+ Lyrics of the song.
28
+ release_date : Optional[str]
29
+ Release date of the music.
30
+ tempo : Optional[float]
31
+ Tempo of the music in BPM.
32
+ title : str
33
+ Title of the music.
34
+ type : Optional[str]
35
+ Type of the music (e.g., track, album).
36
+ upc : Optional[str]
37
+ Universal Product Code.
38
+ url : Union[str, Dict[str, str]]
39
+ URL(s) to the music on different platforms.
40
+ """
41
+
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
@@ -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
@@ -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
1
  Metadata-Version: 2.4
2
2
  Name: yutipy
3
- Version: 1.2.1
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>
@@ -40,6 +40,7 @@ yutipy/kkbox.py
40
40
  yutipy/models.py
41
41
  yutipy/musicyt.py
42
42
  yutipy/spotify.py
43
+ yutipy/yutipy_music.py
43
44
  yutipy.egg-info/PKG-INFO
44
45
  yutipy.egg-info/SOURCES.txt
45
46
  yutipy.egg-info/dependency_links.txt
@@ -1,55 +0,0 @@
1
- from dataclasses import dataclass
2
- from typing import Optional
3
-
4
-
5
- @dataclass
6
- class MusicInfo:
7
- """
8
- A data class to store music information.
9
-
10
- Attributes
11
- ----------
12
- album_art : Optional[str]
13
- URL to the album art.
14
- album_title : Optional[str]
15
- Title of the album.
16
- album_type : Optional[str]
17
- Type of the album (e.g., album, single).
18
- artists : str
19
- Name(s) of the artist(s).
20
- genre : Optional[str]
21
- Genre of the music.
22
- id : str
23
- Unique identifier for the music.
24
- isrc : Optional[str]
25
- International Standard Recording Code.
26
- lyrics : Optional[str]
27
- Lyrics of the song.
28
- release_date : Optional[str]
29
- Release date of the music.
30
- tempo : Optional[float]
31
- Tempo of the music in BPM.
32
- title : str
33
- Title of the music.
34
- type : Optional[str]
35
- Type of the music (e.g., track, album).
36
- upc : Optional[str]
37
- Universal Product Code.
38
- url : str
39
- URL to the music on the platform.
40
- """
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes