pyyapper 1.6.0__tar.gz → 1.7.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.
Files changed (44) hide show
  1. {pyyapper-1.6.0/src/pyyapper.egg-info → pyyapper-1.7.0}/PKG-INFO +1 -1
  2. {pyyapper-1.6.0 → pyyapper-1.7.0}/pyproject.toml +1 -1
  3. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/__init__.py +2 -1
  4. pyyapper-1.7.0/src/pyyapper/_version.py +1 -0
  5. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/bot.py +43 -1
  6. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/http.py +1 -1
  7. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/models.py +1 -1
  8. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/oauth.py +2 -2
  9. pyyapper-1.7.0/src/pyyapper/voice.py +44 -0
  10. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/webhooks.py +1 -1
  11. {pyyapper-1.6.0 → pyyapper-1.7.0/src/pyyapper.egg-info}/PKG-INFO +1 -1
  12. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper.egg-info/SOURCES.txt +1 -0
  13. pyyapper-1.6.0/src/pyyapper/_version.py +0 -1
  14. {pyyapper-1.6.0 → pyyapper-1.7.0}/LICENSE +0 -0
  15. {pyyapper-1.6.0 → pyyapper-1.7.0}/README.md +0 -0
  16. {pyyapper-1.6.0 → pyyapper-1.7.0}/setup.cfg +0 -0
  17. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/buttons.py +0 -0
  18. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/cache.py +0 -0
  19. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/commands.py +0 -0
  20. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/components_v2.py +0 -0
  21. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/config.py +0 -0
  22. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/embeds.py +0 -0
  23. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/errors.py +0 -0
  24. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/__init__.py +0 -0
  25. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/commands/__init__.py +0 -0
  26. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/commands/checks.py +0 -0
  27. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/commands/converters.py +0 -0
  28. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/commands/core.py +0 -0
  29. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/commands/errors.py +0 -0
  30. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/ext/tasks.py +0 -0
  31. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/i18n.py +0 -0
  32. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/metrics.py +0 -0
  33. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/pagination.py +0 -0
  34. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/presence.py +0 -0
  35. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/py.typed +0 -0
  36. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper/wait_for.py +0 -0
  37. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper.egg-info/dependency_links.txt +0 -0
  38. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper.egg-info/requires.txt +0 -0
  39. {pyyapper-1.6.0 → pyyapper-1.7.0}/src/pyyapper.egg-info/top_level.txt +0 -0
  40. {pyyapper-1.6.0 → pyyapper-1.7.0}/tests/test_ext_commands.py +0 -0
  41. {pyyapper-1.6.0 → pyyapper-1.7.0}/tests/test_oauth.py +0 -0
  42. {pyyapper-1.6.0 → pyyapper-1.7.0}/tests/test_smoke.py +0 -0
  43. {pyyapper-1.6.0 → pyyapper-1.7.0}/tests/test_tasks.py +0 -0
  44. {pyyapper-1.6.0 → pyyapper-1.7.0}/tests/test_webhooks.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyyapper
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: An intuitive, async Python library for the Yapper bot API.
5
5
  Author: PyYapper contributors
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyyapper"
7
- version = "1.6.0"
7
+ version = "1.7.0"
8
8
  description = "An intuitive, async Python library for the Yapper bot API."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -19,6 +19,7 @@ from .errors import (
19
19
  from .models import (
20
20
  User, Server, Channel, Category, Member, Message, Role, VoiceChannel, picture_url,
21
21
  )
22
+ from .voice import VoiceCall
22
23
  from .presence import Activity, Presence
23
24
  from .pagination import Paginator
24
25
  from .webhooks import Webhook
@@ -43,7 +44,7 @@ __all__ = [
43
44
  "Embed", "Button", "Row",
44
45
  "YapperError", "ConfigurationError", "HTTPException",
45
46
  "BadRequest", "Unauthorized", "Forbidden", "NotFound", "RateLimited", "ServerError", "ServiceUnavailable",
46
- "User", "Server", "Channel", "Category", "Member", "Message", "Role", "VoiceChannel", "picture_url",
47
+ "User", "Server", "Channel", "Category", "Member", "Message", "Role", "VoiceChannel", "picture_url", "VoiceCall",
47
48
  "Activity", "Presence",
48
49
  "Paginator", "Webhook", "WaiterRegistry", "wait_for",
49
50
  "OAuth2Client", "OAuthError", "generate_state", "generate_pkce",
@@ -0,0 +1 @@
1
+ __version__ = "1.7.0"
@@ -183,7 +183,7 @@ class Bot:
183
183
  self,
184
184
  token: Optional[str] = None,
185
185
  *,
186
- base_url: str = "https://www.yapper.website/api/bot/v1",
186
+ base_url: str = "https://www.yapin.gg/api/bot/v1",
187
187
  prefixes: Optional[list[str]] = None,
188
188
  log: Any = True,
189
189
  ignore_bots: bool = True,
@@ -848,6 +848,44 @@ class Bot:
848
848
  "user_id": user_id,
849
849
  })
850
850
 
851
+ # Voice (music): bot joins a voice channel and plays audio
852
+ async def join_voice(self, server_id: Any, channel_id: Any) -> Any:
853
+ """Join a voice channel. Returns a LiveKit ticket dict."""
854
+ return await self.api("POST", f"/servers/{server_id}/voice/join", {
855
+ "channel_id": channel_id,
856
+ })
857
+
858
+ async def leave_voice(self, server_id: Any) -> Any:
859
+ """Leave voice in a server."""
860
+ return await self.api("POST", f"/servers/{server_id}/voice/leave", {})
861
+
862
+ async def connect_voice(self, server_id: Any, channel_id: Any, livekit_module: Any = None) -> Any:
863
+ """Join voice and return a ticket.
864
+
865
+ If ``livekit_module`` (e.g. ``livekit.rtc``) is provided and installed,
866
+ returns a small helper object exposing ``.source`` (an audio source) and
867
+ ``.leave()``. Otherwise returns the raw ticket dict from the API.
868
+ """
869
+ ticket = await self.join_voice(server_id, channel_id)
870
+ if livekit_module is None:
871
+ return ticket
872
+ # Best-effort LiveKit connection. E2EE key exchange is handled by the
873
+ # caller per the docs; here we just open the room and expose a source.
874
+ try:
875
+ from .voice import VoiceCall
876
+ room = livekit_module.Room()
877
+ source = livekit_module.AudioSource(48000, 2)
878
+ track = livekit_module.LocalAudioTrack.create_audio_track("bot-audio", source)
879
+ await room.connect(ticket["url"], ticket["token"])
880
+ await room.local_participant.publish_track(track)
881
+ obj = VoiceCall(room, source, self, server_id, ticket=ticket)
882
+ return obj
883
+ except Exception as e:
884
+ # Fall back to raw ticket if LiveKit isn't available/compatible.
885
+ if hasattr(self, "logger"):
886
+ self.logger.warning("connect_voice LiveKit setup failed: %s", e)
887
+ return ticket
888
+
851
889
  # ------------------------------------------------------------------ #
852
890
  # Channels management
853
891
  # ------------------------------------------------------------------ #
@@ -1111,6 +1149,10 @@ class Bot:
1111
1149
  if m and m.group(1) in self.prefixes and m.group(2).lower() in self.commands:
1112
1150
  name = m.group(2).lower()
1113
1151
  args = (m.group(3) or "").strip()
1152
+ # If command_for is set and points at another bot, don't handle.
1153
+ command_for = data.get("command_for")
1154
+ if command_for and self.me is not None and command_for != getattr(self.me, "id", None):
1155
+ name = None
1114
1156
  if name and name in self.commands:
1115
1157
  ctx.command = name
1116
1158
  ctx.args = args or ""
@@ -43,7 +43,7 @@ from .errors import (
43
43
  exception_for_status,
44
44
  )
45
45
 
46
- DEFAULT_BASE = "https://www.yapper.website/api/bot/v1"
46
+ DEFAULT_BASE = "https://www.yapin.gg/api/bot/v1"
47
47
  USER_AGENT = "pyyapper/1.0"
48
48
 
49
49
 
@@ -49,7 +49,7 @@ def picture_url(bucket: str, path: Any) -> Optional[str]:
49
49
  return None
50
50
  p = str(path)
51
51
  if p.startswith("/"):
52
- return "https://www.yapper.website" + p
52
+ return "https://www.yapin.gg" + p
53
53
  return f"https://files.yapper.website/{bucket}/{p}"
54
54
 
55
55
 
@@ -36,7 +36,7 @@ class OAuthError(YapperError):
36
36
  super().__init__(f"{error}: {description}".strip(": "))
37
37
 
38
38
 
39
- DEFAULT_BASE = "https://www.yapper.website"
39
+ DEFAULT_BASE = "https://www.yapin.gg"
40
40
  AUTHORIZE_PATH = "/oauth/authorize"
41
41
  TOKEN_PATH = "/api/oauth/token"
42
42
  ME_PATH = "/api/oauth/me"
@@ -72,7 +72,7 @@ class OAuth2Client:
72
72
  redirect_uri:
73
73
  Default redirect URI (must match one registered for the app).
74
74
  base_url:
75
- Yapper base URL. Defaults to ``https://www.yapper.website``.
75
+ Yapper base URL. Defaults to ``https://www.yapin.gg``.
76
76
  session:
77
77
  Optional shared :class:`aiohttp.ClientSession`.
78
78
  """
@@ -0,0 +1,44 @@
1
+ """Voice connection helpers for PyYapper (music bots)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any
6
+
7
+
8
+ class VoiceCall:
9
+ """A handle to an active voice connection.
10
+
11
+ Attributes:
12
+ room: the LiveKit room (if connected).
13
+ source: the audio source to capture frames into.
14
+ ticket: the raw ticket returned by the API.
15
+ """
16
+
17
+ def __init__(self, room: Any, source: Any, bot: Any, server_id: Any, ticket: Any = None) -> None:
18
+ self.room = room
19
+ self.source = source
20
+ self.bot = bot
21
+ self.server_id = server_id
22
+ self.ticket = ticket
23
+
24
+ async def leave(self) -> Any:
25
+ try:
26
+ if self.room is not None:
27
+ await self.room.disconnect()
28
+ except Exception:
29
+ pass
30
+ try:
31
+ await self.bot.leave_voice(self.server_id)
32
+ except Exception:
33
+ pass
34
+ return None
35
+
36
+ async def capture_frame(self, frame: Any) -> Any:
37
+ if self.source is not None and hasattr(self.source, "capture_frame"):
38
+ return await self.source.capture_frame(frame)
39
+ return None
40
+
41
+ async def wait_for_playout(self) -> Any:
42
+ if self.source is not None and hasattr(self.source, "wait_for_playout"):
43
+ return await self.source.wait_for_playout()
44
+ return None
@@ -35,7 +35,7 @@ import aiohttp
35
35
 
36
36
  from .errors import HTTPException, RateLimited, exception_for_status
37
37
 
38
- WEBHOOK_BASE = "https://www.yapper.website/api/webhooks"
38
+ WEBHOOK_BASE = "https://www.yapin.gg/api/webhooks"
39
39
  USER_AGENT = "pyyapper/1.0"
40
40
 
41
41
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyyapper
3
- Version: 1.6.0
3
+ Version: 1.7.0
4
4
  Summary: An intuitive, async Python library for the Yapper bot API.
5
5
  Author: PyYapper contributors
6
6
  License-Expression: MIT
@@ -19,6 +19,7 @@ src/pyyapper/oauth.py
19
19
  src/pyyapper/pagination.py
20
20
  src/pyyapper/presence.py
21
21
  src/pyyapper/py.typed
22
+ src/pyyapper/voice.py
22
23
  src/pyyapper/wait_for.py
23
24
  src/pyyapper/webhooks.py
24
25
  src/pyyapper.egg-info/PKG-INFO
@@ -1 +0,0 @@
1
- __version__ = "1.6.0"
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