AbhiCalls 2.9.0__py3-none-any.whl → 2.9.9__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.
- AbhiCalls/Start.py +29 -0
- AbhiCalls/__init__.py +10 -0
- AbhiCalls/controller.py +23 -7
- AbhiCalls/models.py +7 -2
- AbhiCalls/plugins/__init__.py +1 -0
- AbhiCalls/plugins/base.py +57 -0
- AbhiCalls/yt.py +30 -14
- {abhicalls-2.9.0.dist-info → abhicalls-2.9.9.dist-info}/METADATA +1 -1
- abhicalls-2.9.9.dist-info/RECORD +17 -0
- abhicalls-2.9.0.dist-info/RECORD +0 -14
- {abhicalls-2.9.0.dist-info → abhicalls-2.9.9.dist-info}/WHEEL +0 -0
- {abhicalls-2.9.0.dist-info → abhicalls-2.9.9.dist-info}/top_level.txt +0 -0
AbhiCalls/Start.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from colorama import init, Fore, Style
|
|
3
|
+
from AbhiCalls import __version__, __author__
|
|
4
|
+
|
|
5
|
+
init(autoreset=True)
|
|
6
|
+
|
|
7
|
+
def check_latest_version(pkg_name="AbhiCalls"):
|
|
8
|
+
try:
|
|
9
|
+
response = requests.get(f"https://pypi.org/pypi/{pkg_name}/json", timeout=3)
|
|
10
|
+
if response.status_code == 200:
|
|
11
|
+
return response.json()["info"]["version"]
|
|
12
|
+
except Exception:
|
|
13
|
+
return None
|
|
14
|
+
|
|
15
|
+
def print_startup_message():
|
|
16
|
+
print(Fore.GREEN + "✅ AbhiCalls started...\n")
|
|
17
|
+
|
|
18
|
+
print(Fore.CYAN + f"Version : {__version__}")
|
|
19
|
+
print(Fore.CYAN + f"Author : {__author__}")
|
|
20
|
+
print(Fore.CYAN + "License : Abhishek Special")
|
|
21
|
+
print(Fore.CYAN + "GitHub : https://github.com/YouTubeMusicAPI/AbhiCalls")
|
|
22
|
+
print(Fore.CYAN + "Telegram : https://t.me/WhyAbhishek")
|
|
23
|
+
|
|
24
|
+
latest = check_latest_version("AbhiCalls")
|
|
25
|
+
if latest and latest != __version__:
|
|
26
|
+
print(Fore.YELLOW + "\nUpdate Available!")
|
|
27
|
+
print(Fore.YELLOW + f"New AbhiCalls v{latest} is now available!")
|
|
28
|
+
else:
|
|
29
|
+
print(Fore.GREEN + "\nYou are using the latest version!")
|
AbhiCalls/__init__.py
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
from AbhiCalls.vc import VoiceEngine
|
|
2
2
|
from AbhiCalls.runtime import idle
|
|
3
3
|
from .player import Player
|
|
4
|
+
from .plugins import Plugin
|
|
4
5
|
|
|
5
6
|
__all__ = ["VoiceEngine", "idle"]
|
|
7
|
+
|
|
8
|
+
__version__ = "2.9.9"
|
|
9
|
+
__author__ = "ABHISHEK THAKUR"
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from .Start import print_startup_message
|
|
13
|
+
print_startup_message()
|
|
14
|
+
except Exception:
|
|
15
|
+
pass
|
AbhiCalls/controller.py
CHANGED
|
@@ -2,6 +2,7 @@ from AbhiCalls.yt import resolve_query
|
|
|
2
2
|
from AbhiCalls.models import Song
|
|
3
3
|
from AbhiCalls.player import Player
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
class VoiceController:
|
|
6
7
|
def __init__(self, engine):
|
|
7
8
|
self.engine = engine
|
|
@@ -19,8 +20,11 @@ class VoiceController:
|
|
|
19
20
|
try:
|
|
20
21
|
await fn(*args)
|
|
21
22
|
except Exception as e:
|
|
22
|
-
print(f"[Plugin:{p
|
|
23
|
+
print(f"[Plugin:{getattr(p, 'name', p)}] {name} error:", e)
|
|
23
24
|
|
|
25
|
+
# =========================
|
|
26
|
+
# PLAY
|
|
27
|
+
# =========================
|
|
24
28
|
async def play(self, chat_id, query, requested_by):
|
|
25
29
|
results = await resolve_query(query)
|
|
26
30
|
if not results:
|
|
@@ -37,6 +41,8 @@ class VoiceController:
|
|
|
37
41
|
views=data["views"],
|
|
38
42
|
stream=data["stream"],
|
|
39
43
|
requested_by=requested_by,
|
|
44
|
+
video_id=data.get("video_id"),
|
|
45
|
+
thumb=data.get("thumb"),
|
|
40
46
|
)
|
|
41
47
|
|
|
42
48
|
pos = await self.player.play(chat_id, song)
|
|
@@ -46,11 +52,15 @@ class VoiceController:
|
|
|
46
52
|
first_pos = pos
|
|
47
53
|
last_song = song
|
|
48
54
|
|
|
49
|
-
|
|
55
|
+
# 🔥 First song actually started
|
|
56
|
+
if first_pos == 1 and last_song:
|
|
50
57
|
await self._hook("on_song_start", chat_id, last_song)
|
|
51
58
|
|
|
52
59
|
return last_song, first_pos
|
|
53
60
|
|
|
61
|
+
# =========================
|
|
62
|
+
# CONTROLS
|
|
63
|
+
# =========================
|
|
54
64
|
async def skip(self, chat_id):
|
|
55
65
|
await self.player.skip(chat_id)
|
|
56
66
|
|
|
@@ -74,7 +84,6 @@ class VoiceController:
|
|
|
74
84
|
|
|
75
85
|
async def volume(self, chat_id, volume: int):
|
|
76
86
|
await self.player.volume(chat_id, volume)
|
|
77
|
-
|
|
78
87
|
|
|
79
88
|
def loop(self, chat_id, count=None):
|
|
80
89
|
return self.player.set_loop(chat_id, count)
|
|
@@ -82,15 +91,22 @@ class VoiceController:
|
|
|
82
91
|
def eta(self, chat_id):
|
|
83
92
|
return self.player.eta(chat_id)
|
|
84
93
|
|
|
94
|
+
# =========================
|
|
95
|
+
# AUTO-SKIP (STREAM END)
|
|
96
|
+
# =========================
|
|
85
97
|
async def _on_end(self, chat_id):
|
|
86
98
|
q = self.player.queues.get(chat_id)
|
|
87
|
-
song = q.current() if q else None
|
|
88
|
-
if song:
|
|
89
|
-
await self._hook("on_song_end", chat_id, song)
|
|
90
99
|
|
|
100
|
+
# old song end hook
|
|
101
|
+
old_song = q.current() if q else None
|
|
102
|
+
if old_song:
|
|
103
|
+
await self._hook("on_song_end", chat_id, old_song)
|
|
104
|
+
|
|
105
|
+
# move to next song
|
|
91
106
|
await self.player.skip(chat_id)
|
|
92
107
|
|
|
108
|
+
q = self.player.queues.get(chat_id)
|
|
93
109
|
next_song = q.current() if q else None
|
|
110
|
+
|
|
94
111
|
if next_song:
|
|
95
112
|
await self._hook("on_song_start", chat_id, next_song)
|
|
96
|
-
|
AbhiCalls/models.py
CHANGED
|
@@ -8,6 +8,8 @@ class Song:
|
|
|
8
8
|
stream,
|
|
9
9
|
requested_by,
|
|
10
10
|
loop_left=0,
|
|
11
|
+
video_id=None,
|
|
12
|
+
thumb=None,
|
|
11
13
|
):
|
|
12
14
|
self.title = title
|
|
13
15
|
self.url = url
|
|
@@ -16,14 +18,17 @@ class Song:
|
|
|
16
18
|
self.stream = stream
|
|
17
19
|
self.requested_by = requested_by
|
|
18
20
|
self.loop_left = loop_left
|
|
21
|
+
|
|
22
|
+
self.video_id = video_id
|
|
23
|
+
self.thumb = thumb
|
|
24
|
+
|
|
19
25
|
self.duration_sec = self._to_seconds(duration)
|
|
20
26
|
|
|
21
27
|
def _to_seconds(self, d):
|
|
22
28
|
try:
|
|
23
|
-
if ":" in d:
|
|
29
|
+
if isinstance(d, str) and ":" in d:
|
|
24
30
|
m, s = map(int, d.split(":"))
|
|
25
31
|
return m * 60 + s
|
|
26
32
|
return int(d)
|
|
27
33
|
except Exception:
|
|
28
34
|
return 0
|
|
29
|
-
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .base import Plugin
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
class Plugin:
|
|
2
|
+
name = "base"
|
|
3
|
+
|
|
4
|
+
def __init__(self, app):
|
|
5
|
+
self.app = app # pyrogram Client
|
|
6
|
+
|
|
7
|
+
# =========================
|
|
8
|
+
# ▶️ NOW PLAYING / AUTO-SKIP
|
|
9
|
+
# =========================
|
|
10
|
+
async def on_song_start(self, chat_id, song):
|
|
11
|
+
caption = (
|
|
12
|
+
"▶️ **Now Playing**\n\n"
|
|
13
|
+
f"🎵 **Title:** {song.title}\n"
|
|
14
|
+
f"⏱ **Duration:** {song.duration}\n"
|
|
15
|
+
f"🙋 **Requested by:** {song.requested_by}"
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
if song.thumb:
|
|
19
|
+
await self.app.send_photo(
|
|
20
|
+
chat_id,
|
|
21
|
+
photo=song.thumb,
|
|
22
|
+
caption=caption
|
|
23
|
+
)
|
|
24
|
+
else:
|
|
25
|
+
await self.app.send_message(chat_id, caption)
|
|
26
|
+
|
|
27
|
+
# =========================
|
|
28
|
+
# ⏹ SONG END (optional hook)
|
|
29
|
+
# =========================
|
|
30
|
+
async def on_song_end(self, chat_id, song):
|
|
31
|
+
# Usually no message needed here
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
# =========================
|
|
35
|
+
# ➕ ADDED TO QUEUE
|
|
36
|
+
# =========================
|
|
37
|
+
async def on_queue_add(self, chat_id, song, position):
|
|
38
|
+
# First song ka message already on_song_start bhej dega
|
|
39
|
+
if position == 1:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
caption = (
|
|
43
|
+
"➕ **Added to Queue**\n\n"
|
|
44
|
+
f"🎵 **Title:** {song.title}\n"
|
|
45
|
+
f"⏱ **Duration:** {song.duration}\n"
|
|
46
|
+
f"🙋 **Requested by:** {song.requested_by}\n"
|
|
47
|
+
f"📍 **Position:** {position}"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if song.thumb:
|
|
51
|
+
await self.app.send_photo(
|
|
52
|
+
chat_id,
|
|
53
|
+
photo=song.thumb,
|
|
54
|
+
caption=caption
|
|
55
|
+
)
|
|
56
|
+
else:
|
|
57
|
+
await self.app.send_message(chat_id, caption)
|
AbhiCalls/yt.py
CHANGED
|
@@ -6,6 +6,7 @@ from YouTubeMusic.Playlist import get_playlist_songs
|
|
|
6
6
|
PLAYLIST_REGEX = re.compile(r"(list=)")
|
|
7
7
|
YOUTUBE_REGEX = re.compile(r"(youtube\.com|youtu\.be|music\.youtube\.com)")
|
|
8
8
|
|
|
9
|
+
|
|
9
10
|
def sec_to_mmss(sec):
|
|
10
11
|
try:
|
|
11
12
|
sec = int(sec)
|
|
@@ -13,18 +14,23 @@ def sec_to_mmss(sec):
|
|
|
13
14
|
except Exception:
|
|
14
15
|
return "Unknown"
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
def extract_video_id(url: str):
|
|
18
19
|
try:
|
|
19
20
|
if "watch?v=" in url:
|
|
20
|
-
|
|
21
|
+
return url.split("watch?v=")[1].split("&")[0]
|
|
21
22
|
elif "youtu.be/" in url:
|
|
22
|
-
|
|
23
|
-
else:
|
|
24
|
-
return None
|
|
25
|
-
return f"https://i.ytimg.com/vi/{vid}/hqdefault.jpg"
|
|
23
|
+
return url.split("youtu.be/")[1].split("?")[0]
|
|
26
24
|
except Exception:
|
|
25
|
+
pass
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def yt_thumbnail(url: str):
|
|
30
|
+
vid = extract_video_id(url)
|
|
31
|
+
if not vid:
|
|
27
32
|
return None
|
|
33
|
+
return f"https://i.ytimg.com/vi/{vid}/hqdefault.jpg"
|
|
28
34
|
|
|
29
35
|
|
|
30
36
|
async def resolve_query(query: str):
|
|
@@ -33,37 +39,45 @@ async def resolve_query(query: str):
|
|
|
33
39
|
# 🎵 PLAYLIST
|
|
34
40
|
if PLAYLIST_REGEX.search(query):
|
|
35
41
|
playlist = await get_playlist_songs(query)
|
|
42
|
+
|
|
36
43
|
for item in playlist:
|
|
37
44
|
stream = get_stream(item["url"])
|
|
38
45
|
if not stream:
|
|
39
46
|
continue
|
|
40
47
|
|
|
48
|
+
vid = extract_video_id(item["url"])
|
|
49
|
+
|
|
41
50
|
songs.append({
|
|
42
51
|
"title": item.get("title", "Unknown"),
|
|
43
52
|
"url": item["url"],
|
|
44
53
|
"duration": sec_to_mmss(item.get("duration", "0")),
|
|
45
|
-
"views": "Unknown",
|
|
46
|
-
"
|
|
54
|
+
"views": item.get("views", "Unknown"),
|
|
55
|
+
"video_id": vid,
|
|
56
|
+
"thumb": yt_thumbnail(item["url"]),
|
|
47
57
|
"stream": stream,
|
|
48
58
|
})
|
|
59
|
+
|
|
49
60
|
return songs or None
|
|
50
61
|
|
|
51
|
-
# 🔗 DIRECT
|
|
62
|
+
# 🔗 DIRECT YOUTUBE LINK
|
|
52
63
|
if YOUTUBE_REGEX.search(query):
|
|
53
64
|
stream = get_stream(query)
|
|
54
65
|
if not stream:
|
|
55
66
|
return None
|
|
56
67
|
|
|
68
|
+
vid = extract_video_id(query)
|
|
69
|
+
|
|
57
70
|
return [{
|
|
58
71
|
"title": "YouTube Audio",
|
|
59
72
|
"url": query,
|
|
60
73
|
"duration": "Unknown",
|
|
61
74
|
"views": "Unknown",
|
|
62
|
-
"
|
|
75
|
+
"video_id": vid,
|
|
76
|
+
"thumb": yt_thumbnail(query),
|
|
63
77
|
"stream": stream,
|
|
64
78
|
}]
|
|
65
79
|
|
|
66
|
-
# 🔍 SEARCH
|
|
80
|
+
# 🔍 SEARCH QUERY
|
|
67
81
|
res = await Search(query, limit=1)
|
|
68
82
|
if not res or not res.get("main_results"):
|
|
69
83
|
return None
|
|
@@ -73,12 +87,14 @@ async def resolve_query(query: str):
|
|
|
73
87
|
if not stream:
|
|
74
88
|
return None
|
|
75
89
|
|
|
90
|
+
vid = extract_video_id(i["url"])
|
|
91
|
+
|
|
76
92
|
return [{
|
|
77
93
|
"title": i["title"],
|
|
78
94
|
"url": i["url"],
|
|
79
95
|
"duration": i.get("duration", "Unknown"),
|
|
80
96
|
"views": i.get("views", "Unknown"),
|
|
81
|
-
|
|
82
|
-
"
|
|
97
|
+
"video_id": vid,
|
|
98
|
+
"thumb": i.get("thumbnail") or yt_thumbnail(i["url"]),
|
|
83
99
|
"stream": stream,
|
|
84
100
|
}]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
AbhiCalls/Start.py,sha256=Z4Kn3p8elM9Sgo3H_7EBP8dfHknsjgiaUaEs1GEqcnY,1068
|
|
2
|
+
AbhiCalls/__init__.py,sha256=uoXjElr_JmTjFdMHzNKBQbNzwGz4m1j9r2ChxrXouAE,322
|
|
3
|
+
AbhiCalls/controller.py,sha256=KYppQPpWhTpWj-gwmZqyGgX5liZHAaWRIMqksZPzXzU,3241
|
|
4
|
+
AbhiCalls/models.py,sha256=fwMdHKE0z6qB98nHJ8E1uYU3JSk25LGxaaeAz1JkAH0,791
|
|
5
|
+
AbhiCalls/player.py,sha256=UlAWmhZqHFjtAplA9-6lXFkVAu4pyEWDGbF8Wj9KYkM,2286
|
|
6
|
+
AbhiCalls/queue.py,sha256=iRrTvt1rU-diarSBCfxjeY-4uJ97oUsvDqtPpbB4UQY,1212
|
|
7
|
+
AbhiCalls/runtime.py,sha256=4_WmHirGwNOyn1Iuzbhecb_ao7qMDh1erFzp0ZaLze0,966
|
|
8
|
+
AbhiCalls/vc.py,sha256=ld3C4-QNDrHBQPrNzIuNTcu7zk1pVOo9rvrQBUsTI8s,309
|
|
9
|
+
AbhiCalls/yt.py,sha256=h0QRNK9sy-5wIDueiy-uMUxruV7z5m3xjUyRPoFT6_s,2594
|
|
10
|
+
AbhiCalls/_engine/__init__.py,sha256=pTqDs11-vYr-wuwtd7h3EkspDquGu84jWfN54ajl0kM,34
|
|
11
|
+
AbhiCalls/_engine/native.py,sha256=KJajnL9urwrx0PaOEJj4-pGGnhz4X9FDI6rTGrbCLoI,1272
|
|
12
|
+
AbhiCalls/plugins/__init__.py,sha256=rSCdGAjFfrzz-XQIFRjOcl629mPCo17n77Fn9lxLcPI,25
|
|
13
|
+
AbhiCalls/plugins/base.py,sha256=wanPA2h4dHvR-YXGIsAgkAGGtGMd6acT0Gg8q35RTgI,1696
|
|
14
|
+
abhicalls-2.9.9.dist-info/METADATA,sha256=3iVxiggOeLOrWg6msDJOCW3DCI8kmfuYRITyb9fKdhI,1209
|
|
15
|
+
abhicalls-2.9.9.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
16
|
+
abhicalls-2.9.9.dist-info/top_level.txt,sha256=3_ZgJEaE0rS9jpmEMi6oIXEtMzIagrn70XtK7H6w2gA,10
|
|
17
|
+
abhicalls-2.9.9.dist-info/RECORD,,
|
abhicalls-2.9.0.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
AbhiCalls/__init__.py,sha256=8Bgye84bSUJVFLhm2HPc2piO3YHZb67EihvJlGZxvDs,134
|
|
2
|
-
AbhiCalls/controller.py,sha256=mdowoTCc6jpDsdljuUWdgbsCMR5NObaw3Jh6LYb-O8I,2739
|
|
3
|
-
AbhiCalls/models.py,sha256=ybRrFbVmlpLyfmmn7lG2DpDz_Z9qcq3g9AD5Krc-UP0,664
|
|
4
|
-
AbhiCalls/player.py,sha256=UlAWmhZqHFjtAplA9-6lXFkVAu4pyEWDGbF8Wj9KYkM,2286
|
|
5
|
-
AbhiCalls/queue.py,sha256=iRrTvt1rU-diarSBCfxjeY-4uJ97oUsvDqtPpbB4UQY,1212
|
|
6
|
-
AbhiCalls/runtime.py,sha256=4_WmHirGwNOyn1Iuzbhecb_ao7qMDh1erFzp0ZaLze0,966
|
|
7
|
-
AbhiCalls/vc.py,sha256=ld3C4-QNDrHBQPrNzIuNTcu7zk1pVOo9rvrQBUsTI8s,309
|
|
8
|
-
AbhiCalls/yt.py,sha256=QnO2LdtgVbEi8XqKEY9ZSp6a6x1AjBYVCFNB2sXFcPU,2386
|
|
9
|
-
AbhiCalls/_engine/__init__.py,sha256=pTqDs11-vYr-wuwtd7h3EkspDquGu84jWfN54ajl0kM,34
|
|
10
|
-
AbhiCalls/_engine/native.py,sha256=KJajnL9urwrx0PaOEJj4-pGGnhz4X9FDI6rTGrbCLoI,1272
|
|
11
|
-
abhicalls-2.9.0.dist-info/METADATA,sha256=NY86xNzR3cQEQgMw3B_nlg6UA4qn7lki3r2L0MguvdY,1209
|
|
12
|
-
abhicalls-2.9.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
13
|
-
abhicalls-2.9.0.dist-info/top_level.txt,sha256=3_ZgJEaE0rS9jpmEMi6oIXEtMzIagrn70XtK7H6w2gA,10
|
|
14
|
-
abhicalls-2.9.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|