PandaAPI 1.0.9__tar.gz → 1.0.10__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.9
3
+ Version: 1.0.10
4
4
  Summary: Python utility hub by @ll_PANDA_BBY_ll
5
5
  Author: PANDA
6
6
  Author-email:
@@ -52,6 +52,9 @@ class PandaAPI:
52
52
  def bhagwatgita(self, chapter: int, shalok: int = 1) -> dict:
53
53
  return tools.bhagwatgita(chapter, shalok)
54
54
 
55
+ def image_generate(self, prompt: str, width: int = 1024, height: int = 1024, model: str = "flux") -> dict:
56
+ return tools.image_generate(prompt, width, height, model)
57
+
55
58
  # ── AI ───────────────────────────────────────────────
56
59
  def gemini(self, prompt: str) -> dict:
57
60
  return ai.gemini(prompt)
@@ -76,6 +79,9 @@ class PandaAPI:
76
79
  def yt_thumb(self, video_id: str) -> str:
77
80
  return media.yt_thumb(video_id)
78
81
 
82
+ def lyrics(self, artist: str, title: str) -> dict:
83
+ return media.lyrics(artist, title)
84
+
79
85
  # ── OSINT ────────────────────────────────────────────
80
86
  def ip_lookup(self, ip: str) -> dict:
81
87
  return osint.ip_lookup(ip)
@@ -173,9 +179,5 @@ class PandaAPI:
173
179
  def dark_joke(self) -> dict:
174
180
  return dark.dark_joke()
175
181
 
176
- def lyrics(self, song: str, artist: str = "") -> dict:
177
- return dark.lyrics(song, artist)
178
-
179
182
 
180
183
  api = PandaAPI()
181
- from .modules.media import lyrics
@@ -0,0 +1,84 @@
1
+ import requests
2
+
3
+
4
+ def yt_search(query: str) -> list:
5
+ """
6
+ Uses yt-dlp ytsearch. Returns list of dicts with title, url, duration, channel.
7
+ """
8
+ try:
9
+ import yt_dlp
10
+
11
+ ydl_opts = {
12
+ "quiet": True,
13
+ "skip_download": True,
14
+ "extract_flat": True,
15
+ }
16
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
17
+ info = ydl.extract_info(f"ytsearch5:{query}", download=False)
18
+ entries = info.get("entries", [])
19
+ return [
20
+ {
21
+ "title": e.get("title"),
22
+ "url": f"https://youtube.com/watch?v={e.get('id')}",
23
+ "duration": e.get("duration"),
24
+ "channel": e.get("channel"),
25
+ "id": e.get("id"),
26
+ }
27
+ for e in entries
28
+ ]
29
+ except ImportError:
30
+ return [{"error": "yt_dlp not installed", "success": False}]
31
+ except Exception as e:
32
+ return [{"error": str(e), "success": False}]
33
+
34
+
35
+ def yt_thumb(video_id: str) -> str:
36
+ return f"https://img.youtube.com/vi/{video_id}/maxresdefault.jpg"
37
+
38
+
39
+ def lyrics(artist: str, title: str) -> dict:
40
+ """
41
+ Fetch lyrics for a song.
42
+ Primary: lyrics.ovh (plain text)
43
+ Fallback: lrclib.net (synced + plain)
44
+ """
45
+ # --- Primary: lyrics.ovh ---
46
+ try:
47
+ url = f"https://api.lyrics.ovh/v1/{artist}/{title}"
48
+ r = requests.get(url, timeout=8)
49
+ if r.status_code == 200:
50
+ data = r.json()
51
+ if data.get("lyrics"):
52
+ return {
53
+ "success": True,
54
+ "artist": artist,
55
+ "title": title,
56
+ "lyrics": data["lyrics"],
57
+ "synced": False,
58
+ "source": "lyrics.ovh",
59
+ }
60
+ except Exception:
61
+ pass
62
+
63
+ # --- Fallback: lrclib.net ---
64
+ try:
65
+ url = "https://lrclib.net/api/get"
66
+ params = {"artist_name": artist, "track_name": title}
67
+ r = requests.get(url, params=params, timeout=8)
68
+ if r.status_code == 200:
69
+ data = r.json()
70
+ synced = data.get("syncedLyrics")
71
+ plain = data.get("plainLyrics")
72
+ if synced or plain:
73
+ return {
74
+ "success": True,
75
+ "artist": artist,
76
+ "title": title,
77
+ "lyrics": synced or plain,
78
+ "synced": bool(synced),
79
+ "source": "lrclib.net",
80
+ }
81
+ except Exception:
82
+ pass
83
+
84
+ return {"success": False, "error": "Lyrics not found on any source"}
@@ -75,7 +75,6 @@ def pypi(package: str) -> dict:
75
75
 
76
76
  def hashtag(keyword: str) -> dict:
77
77
  try:
78
- # using ritetag API (no auth needed for basic)
79
78
  url = f"https://ritetag.com/best-hashtags-for/{requests.utils.quote(keyword)}"
80
79
  headers = {"User-Agent": "Mozilla/5.0"}
81
80
  r = requests.get(url, headers=headers, timeout=10)
@@ -86,7 +85,6 @@ def hashtag(keyword: str) -> dict:
86
85
  if t.startswith("#"):
87
86
  tags.append(t)
88
87
  if not tags:
89
- # fallback: generate basic hashtags
90
88
  words = keyword.lower().split()
91
89
  tags = [
92
90
  f"#{keyword.replace(' ', '')}",
@@ -128,9 +126,7 @@ def unsplash(query: str) -> dict:
128
126
  try:
129
127
  url = f"https://source.unsplash.com/featured/?{requests.utils.quote(query)}"
130
128
  r = requests.get(url, timeout=10, allow_redirects=True)
131
- # unsplash source redirects to actual image
132
129
  final_url = r.url
133
- # also fetch a few via scraping picsum/unsplash search
134
130
  search_url = f"https://unsplash.com/s/photos/{requests.utils.quote(query)}"
135
131
  headers = {"User-Agent": "Mozilla/5.0"}
136
132
  rs = requests.get(search_url, headers=headers, timeout=10)
@@ -149,13 +145,39 @@ def unsplash(query: str) -> dict:
149
145
  return {"success": False, "error": str(e)}
150
146
 
151
147
 
148
+ def image_generate(prompt: str, width: int = 1024, height: int = 1024, model: str = "flux") -> dict:
149
+ """
150
+ Generate an AI image using Pollinations.ai (free, no API key needed).
151
+ Models: flux, flux-realism, flux-anime, flux-3d, turbo
152
+ Returns direct image URL + base64 bytes.
153
+ """
154
+ try:
155
+ encoded = requests.utils.quote(prompt)
156
+ url = f"https://image.pollinations.ai/prompt/{encoded}?width={width}&height={height}&model={model}&nologo=true"
157
+ r = requests.get(url, timeout=60)
158
+ if r.status_code == 200 and "image" in r.headers.get("Content-Type", ""):
159
+ import base64
160
+ b64 = base64.b64encode(r.content).decode()
161
+ return {
162
+ "prompt": prompt,
163
+ "url": url,
164
+ "model": model,
165
+ "width": width,
166
+ "height": height,
167
+ "base64": b64,
168
+ "success": True,
169
+ }
170
+ return {"success": False, "error": f"Status {r.status_code}"}
171
+ except Exception as e:
172
+ return {"success": False, "error": str(e)}
173
+
174
+
152
175
  def imdb(query: str) -> dict:
153
176
  try:
154
177
  headers = {
155
178
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
156
179
  "Accept-Language": "en-US,en;q=0.9",
157
180
  }
158
- # use OMDB-style scrape via IMDB search JSON endpoint
159
181
  search_url = f"https://v2.sg.media-imdb.com/suggestion/x/{requests.utils.quote(query)}.json"
160
182
  r = requests.get(search_url, headers=headers, timeout=10)
161
183
  data = r.json()
@@ -167,8 +189,6 @@ def imdb(query: str) -> dict:
167
189
  title = top.get("l", "")
168
190
  year = top.get("y", "")
169
191
  image = top.get("i", {}).get("imageUrl", "") if isinstance(top.get("i"), dict) else ""
170
- rank = top.get("rank", "")
171
- # fetch detail page for more info
172
192
  detail_url = f"https://www.imdb.com/title/{imdb_id}/"
173
193
  rd = requests.get(detail_url, headers=headers, timeout=10)
174
194
  soup = BeautifulSoup(rd.text, "html.parser")
@@ -243,9 +263,6 @@ def leetcode(username: str) -> dict:
243
263
 
244
264
  def bhagwatgita(chapter: int, shalok: int = 1) -> dict:
245
265
  try:
246
- # use bhagavad-gita.org API
247
- url = f"https://bhagavad-gita3.p.rapidapi.com/v2/chapters/{chapter}/verses/{shalok}/"
248
- # fallback to free API
249
266
  url = f"https://vedicscriptures.github.io/slok/{chapter}/{shalok}/"
250
267
  r = requests.get(url, timeout=10)
251
268
  data = r.json()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PandaAPI
3
- Version: 1.0.9
3
+ Version: 1.0.10
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.9"
7
+ version = "1.0.10"
8
8
  authors = [
9
9
  { name = "PANDA" }
10
10
  ]
@@ -1,138 +0,0 @@
1
- import requests
2
-
3
-
4
- def yt_search(query: str) -> list:
5
- try:
6
- import yt_dlp
7
- ydl_opts = {
8
- "quiet": True,
9
- "skip_download": True,
10
- "extract_flat": True,
11
- }
12
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
13
- info = ydl.extract_info(f"ytsearch5:{query}", download=False)
14
- entries = info.get("entries", [])
15
- return [
16
- {
17
- "title": e.get("title"),
18
- "url": f"https://youtube.com/watch?v={e.get('id')}",
19
- "duration": e.get("duration"),
20
- "channel": e.get("channel"),
21
- "id": e.get("id"),
22
- }
23
- for e in entries
24
- ]
25
- except ImportError:
26
- return [{"error": "yt_dlp not installed", "success": False}]
27
-
28
-
29
- def yt_thumb(video_id: str) -> str:
30
- return f"https://img.youtube.com/vi/{video_id}/maxresdefault.jpg"
31
-
32
-
33
- def lyrics(artist: str, title: str) -> dict:
34
- try:
35
- url = f"https://api.lyrics.ovh/v1/{artist}/{title}"
36
- r = requests.get(url, timeout=8)
37
- if r.status_code == 200:
38
- data = r.json()
39
- if data.get("lyrics"):
40
- return {
41
- "success": True,
42
- "artist": artist,
43
- "title": title,
44
- "lyrics": data["lyrics"],
45
- "synced": False,
46
- "source": "lyrics.ovh",
47
- }
48
- except Exception:
49
- pass
50
-
51
- try:
52
- url = "https://lrclib.net/api/get"
53
- params = {"artist_name": artist, "track_name": title}
54
- r = requests.get(url, params=params, timeout=8)
55
- if r.status_code == 200:
56
- data = r.json()
57
- synced = data.get("syncedLyrics")
58
- plain = data.get("plainLyrics")
59
- if synced or plain:
60
- return {
61
- "success": True,
62
- "artist": artist,
63
- "title": title,
64
- "lyrics": synced or plain,
65
- "synced": bool(synced),
66
- "source": "lrclib.net",
67
- }
68
- except Exception:
69
- pass
70
-
71
- return {"success": False, "error": "Lyrics not found on any source"}
72
-
73
-
74
- def lyrics(song: str, artist: str = "") -> dict:
75
- import requests
76
- query = f"{artist} {song}".strip()
77
-
78
- # Method 1: lyrics.ovh
79
- try:
80
- if artist:
81
- r = requests.get(
82
- f"https://api.lyrics.ovh/v1/{requests.utils.quote(artist)}/{requests.utils.quote(song)}",
83
- timeout=8
84
- )
85
- if r.status_code == 200:
86
- lyr = r.json().get("lyrics", "")
87
- if lyr:
88
- return {"song": song, "artist": artist, "lyrics": lyr, "source": "lyrics.ovh", "success": True}
89
- except Exception:
90
- pass
91
-
92
- # Method 2: lrclib.net
93
- try:
94
- r = requests.get(
95
- "https://lrclib.net/api/search",
96
- params={"q": query},
97
- timeout=8
98
- )
99
- if r.status_code == 200:
100
- results = r.json()
101
- if results:
102
- best = results[0]
103
- lyr = best.get("syncedLyrics") or best.get("plainLyrics")
104
- if lyr:
105
- return {
106
- "song": best.get("trackName", song),
107
- "artist": best.get("artistName", artist),
108
- "lyrics": lyr,
109
- "synced": bool(best.get("syncedLyrics")),
110
- "source": "lrclib.net",
111
- "success": True
112
- }
113
- except Exception:
114
- pass
115
-
116
- # Method 3: lyrics.ovh suggest fallback
117
- try:
118
- r = requests.get(
119
- f"https://api.lyrics.ovh/suggest/{requests.utils.quote(query)}",
120
- timeout=8
121
- )
122
- if r.status_code == 200:
123
- data = r.json().get("data", [])
124
- if data:
125
- artist_name = data[0]["artist"]["name"]
126
- title = data[0]["title"]
127
- r2 = requests.get(
128
- f"https://api.lyrics.ovh/v1/{requests.utils.quote(artist_name)}/{requests.utils.quote(title)}",
129
- timeout=8
130
- )
131
- if r2.status_code == 200:
132
- lyr = r2.json().get("lyrics", "")
133
- if lyr:
134
- return {"song": title, "artist": artist_name, "lyrics": lyr, "source": "lyrics.ovh", "success": True}
135
- except Exception:
136
- pass
137
-
138
- return {"success": False, "error": "Lyrics not found on any source"}
File without changes
File without changes
File without changes
File without changes