PandaAPI 1.0.5__tar.gz → 1.0.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PandaAPI
3
- Version: 1.0.5
3
+ Version: 1.0.7
4
4
  Summary: Python utility hub by @ll_PANDA_BBY_ll
5
5
  Author: PANDA
6
6
  Author-email:
@@ -1,7 +1,5 @@
1
1
  import requests
2
- import random
3
- import string
4
- import time
2
+ import re
5
3
 
6
4
 
7
5
  def fake_identity(country: str = "US") -> dict:
@@ -29,7 +27,6 @@ def fake_identity(country: str = "US") -> dict:
29
27
 
30
28
  def temp_mail_create() -> dict:
31
29
  try:
32
- # create session with Guerrilla Mail
33
30
  r = requests.get(
34
31
  "https://api.guerrillamail.com/ajax.php?f=get_email_address&lang=en",
35
32
  timeout=10,
@@ -74,10 +71,7 @@ def temp_mail_read(sid_token: str, mail_id: str) -> dict:
74
71
  timeout=10,
75
72
  ).json()
76
73
  body = r.get("mail_body", "")
77
- # extract OTP - look for 4-8 digit codes
78
- import re
79
74
  otp_patterns = re.findall(r'\b\d{4,8}\b', body)
80
- # extract verification links
81
75
  links = re.findall(r'https?://[^\s<>"]+', body)
82
76
  verify_links = [l for l in links if any(k in l.lower() for k in ['verify', 'confirm', 'activate', 'token', 'otp', 'code', 'click'])]
83
77
  return {
@@ -114,34 +108,77 @@ def dark_joke() -> dict:
114
108
  def lyrics(song: str, artist: str = "") -> dict:
115
109
  try:
116
110
  query = f"{artist} {song}".strip()
117
- # search via lyrics.ovh
111
+ headers = {
112
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
113
+ }
114
+
115
+ # Method 1: lyrics.ovh (English songs)
118
116
  if artist:
119
117
  r = requests.get(
120
118
  f"https://api.lyrics.ovh/v1/{requests.utils.quote(artist)}/{requests.utils.quote(song)}",
121
119
  timeout=10,
122
120
  )
123
121
  if r.status_code == 200:
124
- data = r.json()
125
- lyr = data.get("lyrics", "")
126
- return {"song": song, "artist": artist, "lyrics": lyr, "success": True}
127
- # fallback: search first
122
+ lyr = r.json().get("lyrics", "")
123
+ if lyr:
124
+ return {"song": song, "artist": artist, "lyrics": lyr, "source": "lyrics.ovh", "success": True}
125
+
126
+ # Method 2: Genius search scrape
127
+ search_r = requests.get(
128
+ f"https://api.genius.com/search?q={requests.utils.quote(query)}",
129
+ headers={**headers, "Authorization": "Bearer alXE5K2_D2ZJVMWKW7pWAbsOaOFWlEAzHmDNJY3CyGRTMh5z3HKFqSBJaWrHK2T9"},
130
+ timeout=10,
131
+ )
132
+ if search_r.status_code == 200:
133
+ hits = search_r.json().get("response", {}).get("hits", [])
134
+ if hits:
135
+ top = hits[0]["result"]
136
+ song_title = top.get("title", song)
137
+ artist_name = top.get("primary_artist", {}).get("name", artist)
138
+ song_url = top.get("url", "")
139
+ # scrape lyrics from genius page
140
+ page = requests.get(song_url, headers=headers, timeout=10)
141
+ from bs4 import BeautifulSoup
142
+ soup = BeautifulSoup(page.text, "html.parser")
143
+ # remove scripts
144
+ for s in soup.find_all("script"):
145
+ s.decompose()
146
+ containers = soup.find_all("div", attrs={"data-lyrics-container": "true"})
147
+ if containers:
148
+ lyr_parts = []
149
+ for c in containers:
150
+ for br in c.find_all("br"):
151
+ br.replace_with("\n")
152
+ lyr_parts.append(c.get_text())
153
+ lyr = "\n".join(lyr_parts).strip()
154
+ return {
155
+ "song": song_title,
156
+ "artist": artist_name,
157
+ "lyrics": lyr,
158
+ "genius_url": song_url,
159
+ "source": "genius",
160
+ "success": True,
161
+ }
162
+
163
+ # Method 3: lyrics.ovh suggest fallback
128
164
  rs = requests.get(
129
165
  f"https://api.lyrics.ovh/suggest/{requests.utils.quote(query)}",
130
166
  timeout=10,
131
167
  ).json()
132
168
  results = rs.get("data", [])
133
- if not results:
134
- return {"success": False, "error": "Song not found"}
135
- top = results[0]
136
- artist_name = top.get("artist", {}).get("name", "")
137
- title = top.get("title", "")
138
- r2 = requests.get(
139
- f"https://api.lyrics.ovh/v1/{requests.utils.quote(artist_name)}/{requests.utils.quote(title)}",
140
- timeout=10,
141
- )
142
- if r2.status_code == 200:
143
- lyr = r2.json().get("lyrics", "")
144
- return {"song": title, "artist": artist_name, "lyrics": lyr, "success": True}
145
- return {"success": False, "error": "Lyrics not found"}
169
+ if results:
170
+ top = results[0]
171
+ artist_name = top.get("artist", {}).get("name", "")
172
+ title = top.get("title", "")
173
+ r2 = requests.get(
174
+ f"https://api.lyrics.ovh/v1/{requests.utils.quote(artist_name)}/{requests.utils.quote(title)}",
175
+ timeout=10,
176
+ )
177
+ if r2.status_code == 200:
178
+ lyr = r2.json().get("lyrics", "")
179
+ if lyr:
180
+ return {"song": title, "artist": artist_name, "lyrics": lyr, "source": "lyrics.ovh", "success": True}
181
+
182
+ return {"success": False, "error": "Lyrics not found — try English song name or add artist name"}
146
183
  except Exception as e:
147
184
  return {"success": False, "error": str(e)}
@@ -0,0 +1 @@
1
+ aW1wb3J0IHJlcXVlc3RzCgoKZGVmIHl0X3NlYXJjaChxdWVyeTogc3RyKSAtPiBsaXN0OgogICAgdHJ5OgogICAgICAgIGltcG9ydCB5dF9kbHAKICAgICAgICB5ZGxfb3B0cyA9IHsKICAgICAgICAgICAgInF1aWV0IjogVHJ1ZSwKICAgICAgICAgICAgInNraXBfZG93bmxvYWQiOiBUcnVlLAogICAgICAgICAgICAiZXh0cmFjdF9mbGF0IjogVHJ1ZSwKICAgICAgICB9CiAgICAgICAgd2l0aCB5dF9kbHAuWW91dHViZURMKHlkbF9vcHRzKSBhcyB5ZGw6CiAgICAgICAgICAgIGluZm8gPSB5ZGwuZXh0cmFjdF9pbmZvKGYieXRzZWFyY2g1OntxdWVyeX0iLCBkb3dubG9hZD1GYWxzZSkKICAgICAgICAgICAgZW50cmllcyA9IGluZm8uZ2V0KCJlbnRyaWVzIiwgW10pCiAgICAgICAgICAgIHJldHVybiBbCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgInRpdGxlIjogZS5nZXQoInRpdGxlIiksCiAgICAgICAgICAgICAgICAgICAgInVybCI6IGYiaHR0cHM6Ly95b3V0dWJlLmNvbS93YXRjaD92PXtlLmdldCgnaWQnKX0iLAogICAgICAgICAgICAgICAgICAgICJkdXJhdGlvbiI6IGUuZ2V0KCJkdXJhdGlvbiIpLAogICAgICAgICAgICAgICAgICAgICJjaGFubmVsIjogZS5nZXQoImNoYW5uZWwiKSwKICAgICAgICAgICAgICAgICAgICAiaWQiOiBlLmdldCgiaWQiKSwKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgICAgIGZvciBlIGluIGVudHJpZXMKICAgICAgICAgICAgXQogICAgZXhjZXB0IEltcG9ydEVycm9yOgogICAgICAgIHJldHVybiBbeyJlcnJvciI6ICJ5dF9kbHAgbm90IGluc3RhbGxlZCIsICJzdWNjZXNzIjogRmFsc2V9XQoKCmRlZiB5dF90aHVtYih2aWRlb19pZDogc3RyKSAtPiBzdHI6CiAgICByZXR1cm4gZiJodHRwczovL2ltZy55b3V0dWJlLmNvbS92aS97dmlkZW9faWR9L21heHJlc2RlZmF1bHQuanBnIgoKCmRlZiBseXJpY3MoYXJ0aXN0OiBzdHIsIHRpdGxlOiBzdHIpIC0+IGRpY3Q6CiAgICAjIC0tLSBQcmltYXJ5OiBseXJpY3Mub3ZoIC0tLQogICAgdHJ5OgogICAgICAgIHVybCA9IGYiaHR0cHM6Ly9hcGkubHlyaWNzLm92aC92MS97YXJ0aXN0fS97dGl0bGV9IgogICAgICAgIHIgPSByZXF1ZXN0cy5nZXQodXJsLCB0aW1lb3V0PTgpCiAgICAgICAgaWYgci5zdGF0dXNfY29kZSA9PSAyMDA6CiAgICAgICAgICAgIGRhdGEgPSByLmpzb24oKQogICAgICAgICAgICBpZiBkYXRhLmdldCgibHlyaWNzIik6CiAgICAgICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgICAgICJzdWNjZXNzIjogVHJ1ZSwKICAgICAgICAgICAgICAgICAgICAiYXJ0aXN0IjogYXJ0aXN0LAogICAgICAgICAgICAgICAgICAgICJ0aXRsZSI6IHRpdGxlLAogICAgICAgICAgICAgICAgICAgICJseXJpY3MiOiBkYXRhWyJseXJpY3MiXSwKICAgICAgICAgICAgICAgICAgICAic3luY2VkIjogRmFsc2UsCiAgICAgICAgICAgICAgICAgICAgInNvdXJjZSI6ICJseXJpY3Mub3ZoIiwKICAgICAgICAgICAgICAgIH0KICAgIGV4Y2VwdCBFeGNlcHRpb246CiAgICAgICAgcGFzcwoKICAgICMgLS0tIEZhbGxiYWNrOiBscmNsaWIubmV0IC0tLQogICAgdHJ5OgogICAgICAgIHVybCA9ICJodHRwczovL2xyY2xpYi5uZXQvYXBpL2dldCIKICAgICAgICBwYXJhbXMgPSB7ImFydGlzdF9uYW1lIjogYXJ0aXN0LCAidHJhY2tfbmFtZSI6IHRpdGxlfQogICAgICAgIHIgPSByZXF1ZXN0cy5nZXQodXJsLCBwYXJhbXM9cGFyYW1zLCB0aW1lb3V0PTgpCiAgICAgICAgaWYgci5zdGF0dXNfY29kZSA9PSAyMDA6CiAgICAgICAgICAgIGRhdGEgPSByLmpzb24oKQogICAgICAgICAgICBzeW5jZWQgPSBkYXRhLmdldCgic3luY2VkTHlyaWNzIikKICAgICAgICAgICAgcGxhaW4gPSBkYXRhLmdldCgicGxhaW5MeXJpY3MiKQogICAgICAgICAgICBpZiBzeW5jZWQgb3IgcGxhaW46CiAgICAgICAgICAgICAgICByZXR1cm4gewogICAgICAgICAgICAgICAgICAgICJzdWNjZXNzIjogVHJ1ZSwKICAgICAgICAgICAgICAgICAgICAiYXJ0aXN0IjogYXJ0aXN0LAogICAgICAgICAgICAgICAgICAgICJ0aXRsZSI6IHRpdGxlLAogICAgICAgICAgICAgICAgICAgICJseXJpY3MiOiBzeW5jZWQgb3IgcGxhaW4sCiAgICAgICAgICAgICAgICAgICAgInN5bmNlZCI6IGJvb2woc3luY2VkKSwKICAgICAgICAgICAgICAgICAgICAic291cmNlIjogImxyY2xpYi5uZXQiLAogICAgICAgICAgICAgICAgfQogICAgZXhjZXB0IEV4Y2VwdGlvbjoKICAgICAgICBwYXNzCgogICAgcmV0dXJuIHsic3VjY2VzcyI6IEZhbHNlLCAiZXJyb3IiOiAiTHlyaWNzIG5vdCBmb3VuZCBvbiBhbnkgc291cmNlIn0K
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PandaAPI
3
- Version: 1.0.5
3
+ Version: 1.0.7
4
4
  Summary: Python utility hub by @ll_PANDA_BBY_ll
5
5
  Author: PANDA
6
6
  Author-email:
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "PandaAPI"
7
- version = "1.0.5"
7
+ version = "1.0.7"
8
8
  authors = [
9
9
  { name = "PANDA" }
10
10
  ]
@@ -19,7 +19,7 @@ except FileNotFoundError:
19
19
 
20
20
  setup(
21
21
  name="PandaAPI",
22
- version="1.0.0",
22
+ version="1.0.7",
23
23
  author="PANDA",
24
24
  author_email="",
25
25
  description="Python utility hub by @ll_PANDA_BBY_ll",
@@ -1,35 +0,0 @@
1
- import requests
2
-
3
-
4
- def yt_search(query: str) -> list:
5
- """
6
- Uses yt-dlp's ytsearch via a simple scrape-free approach.
7
- Returns list of dicts with title, url, duration, channel.
8
- """
9
- try:
10
- import yt_dlp
11
-
12
- ydl_opts = {
13
- "quiet": True,
14
- "skip_download": True,
15
- "extract_flat": True,
16
- }
17
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
18
- info = ydl.extract_info(f"ytsearch5:{query}", download=False)
19
- entries = info.get("entries", [])
20
- return [
21
- {
22
- "title": e.get("title"),
23
- "url": f"https://youtube.com/watch?v={e.get('id')}",
24
- "duration": e.get("duration"),
25
- "channel": e.get("channel"),
26
- "id": e.get("id"),
27
- }
28
- for e in entries
29
- ]
30
- except ImportError:
31
- return [{"error": "yt_dlp not installed", "success": False}]
32
-
33
-
34
- def yt_thumb(video_id: str) -> str:
35
- return f"https://img.youtube.com/vi/{video_id}/maxresdefault.jpg"
File without changes
File without changes
File without changes
File without changes