Skip to content

Commit 2158d38

Browse files
authored
Merge branch 'master' into async-dynamic-cooldown
2 parents cac5213 + 4392105 commit 2158d38

File tree

511 files changed

+51136
-12395
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

511 files changed

+51136
-12395
lines changed

.github/workflows/docs-localization-download.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
working-directory: ./docs
4141
- name: "Crowdin"
4242
id: crowdin
43-
uses: crowdin/github-action@v2.7.1
43+
uses: crowdin/github-action@v2.9.1
4444
with:
4545
upload_sources: false
4646
upload_translations: false

.github/workflows/docs-localization-upload.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
sphinx-intl update -p ./build/locales ${{ vars.SPHINX_LANGUAGES }}
4545
working-directory: ./docs
4646
- name: "Crowdin"
47-
uses: crowdin/github-action@v2.7.1
47+
uses: crowdin/github-action@v2.9.1
4848
with:
4949
upload_sources: true
5050
upload_translations: false

.github/workflows/todo-checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
- name: "Checkout Repository"
2424
uses: actions/checkout@v4
2525
- name: "Track TODO Action"
26-
uses: ribtoks/[email protected].14-beta
26+
uses: ribtoks/[email protected].15-beta
2727
with:
2828
TOKEN: ${{ secrets.GITHUB_TOKEN }}
2929
REPO: ${{ github.repository }}

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,16 @@ These changes are available on the `master` branch, but have not yet been releas
5151
([#2564](https://github.com/Pycord-Development/pycord/pull/2564))
5252
- Added `Message.forward_to`, `Message.snapshots`, and other related attributes.
5353
([#2598](https://github.com/Pycord-Development/pycord/pull/2598))
54+
- Add missing `Guild` feature flags and `Guild.edit` parameters.
55+
([#2672](https://github.com/Pycord-Development/pycord/pull/2672))
5456
- Added the ability to change the API's base URL with `Route.API_BASE_URL`.
5557
([#2714](https://github.com/Pycord-Development/pycord/pull/2714))
5658
- Added the ability to pass a `datetime.time` object to `format_dt`.
5759
([#2747](https://github.com/Pycord-Development/pycord/pull/2747))
60+
- Added support for type hinting slash command options with `typing.Annotated`.
61+
([#2782](https://github.com/Pycord-Development/pycord/pull/2782))
62+
- Added conversion to `Member` in `MentionableConverter`.
63+
([#2775](https://github.com/Pycord-Development/pycord/pull/2775))
5864
- Added `discord.Interaction.created_at`.
5965
([#2801](https://github.com/Pycord-Development/pycord/pull/2801))
6066
- Added support for asynchronous functions in dynamic cooldowns.
@@ -121,6 +127,12 @@ These changes are available on the `master` branch, but have not yet been releas
121127
([#2781](https://github.com/Pycord-Development/pycord/pull/2781))
122128
- Fixed `VoiceClient` crashing randomly while receiving audio
123129
([#2800](https://github.com/Pycord-Development/pycord/pull/2800))
130+
- Fixed `VoiceClient.connect` failing to do initial connection.
131+
([#2812](https://github.com/Pycord-Development/pycord/pull/2812))
132+
- Fixed `AttributeError` when printing a File component's `__repr__`.
133+
([#2843](https://github.com/Pycord-Development/pycord/pull/2843))
134+
- Fixed `TypeError` when using `@option` with certain annotations and along with
135+
`channel_types`. ([#2835](https://github.com/Pycord-Development/pycord/pull/2835))
124136

125137
### Changed
126138

@@ -140,6 +152,8 @@ These changes are available on the `master` branch, but have not yet been releas
140152
([#2564](https://github.com/Pycord-Development/pycord/pull/2564))
141153
- Changed the default value of `ApplicationCommand.nsfw` to `False`.
142154
([#2797](https://github.com/Pycord-Development/pycord/pull/2797))
155+
- Upgraded voice websocket version to v8.
156+
([#2812](https://github.com/Pycord-Development/pycord/pull/2812))
143157

144158
### Deprecated
145159

crowdin.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ preserve_hierarchy: true
55

66
commit_message: "docs: Update translations"
77

8-
export_languages: ["de", "ja", "fr", "it", "hi", "ko", "pt-BR", "es-ES", "zh-CN"]
8+
export_languages: ["de", "ja", "fr", "it", "hi", "ko", "pt-BR", "es-ES", "zh-CN", "tr"]
99

1010
bundles:
1111
- 1

discord/asset.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,9 @@ class Asset(AssetMixin):
144144
145145
.. describe:: hash(x)
146146
147-
Returns the hash of the asset.
147+
Returns the asset's url's hash.
148+
149+
This is equivalent to hash(:attr:`url`).
148150
"""
149151

150152
__slots__: tuple[str, ...] = (

discord/commands/core.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@
7373
from .options import Option, OptionChoice
7474

7575
if sys.version_info >= (3, 11):
76-
from typing import Annotated, get_args, get_origin
76+
from typing import Annotated, Literal, get_args, get_origin
7777
else:
78-
from typing_extensions import Annotated, get_args, get_origin
78+
from typing_extensions import Annotated, Literal, get_args, get_origin
7979

8080
__all__ = (
8181
"_BaseCommand",
@@ -804,6 +804,26 @@ def _parse_options(self, params, *, check_params: bool = True) -> list[Option]:
804804
if option == inspect.Parameter.empty:
805805
option = str
806806

807+
if self._is_typing_literal(option):
808+
literal_values = get_args(option)
809+
if not all(isinstance(v, (str, int, float)) for v in literal_values):
810+
raise TypeError(
811+
"Literal values for choices must be str, int, or float."
812+
)
813+
814+
value_type = type(literal_values[0])
815+
if not all(isinstance(v, value_type) for v in literal_values):
816+
raise TypeError(
817+
"All Literal values for choices must be of the same type."
818+
)
819+
820+
option = Option(
821+
value_type,
822+
choices=[
823+
OptionChoice(name=str(v), value=v) for v in literal_values
824+
],
825+
)
826+
807827
if self._is_typing_annotated(option):
808828
type_hint = get_args(option)[0]
809829
metadata = option.__metadata__
@@ -906,6 +926,9 @@ def _is_typing_union(self, annotation):
906926
def _is_typing_optional(self, annotation):
907927
return self._is_typing_union(annotation) and type(None) in annotation.__args__ # type: ignore
908928

929+
def _is_typing_literal(self, annotation):
930+
return get_origin(annotation) is Literal
931+
909932
def _is_typing_annotated(self, annotation):
910933
return get_origin(annotation) is Annotated
911934

discord/commands/options.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,9 @@ def __init__(
225225
self.description = description or "No description provided"
226226
self.channel_types: list[ChannelType] = kwargs.pop("channel_types", [])
227227

228-
if isinstance(input_type, SlashCommandOptionType):
228+
if self.channel_types:
229+
self.input_type = SlashCommandOptionType.channel
230+
elif isinstance(input_type, SlashCommandOptionType):
229231
self.input_type = input_type
230232
else:
231233
from ..ext.commands import Converter

discord/ext/bridge/core.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
Converter,
5252
Group,
5353
GuildChannelConverter,
54+
MemberConverter,
5455
RoleConverter,
5556
UserConverter,
5657
)
@@ -566,13 +567,21 @@ def predicate(func: Callable | ApplicationCommand):
566567

567568

568569
class MentionableConverter(Converter):
569-
"""A converter that can convert a mention to a user or a role."""
570+
"""A converter that can convert a mention to a member, a user or a role."""
570571

571572
async def convert(self, ctx, argument):
572573
try:
573574
return await RoleConverter().convert(ctx, argument)
574575
except BadArgument:
575-
return await UserConverter().convert(ctx, argument)
576+
pass
577+
578+
if ctx.guild:
579+
try:
580+
return await MemberConverter().convert(ctx, argument)
581+
except BadArgument:
582+
pass
583+
584+
return await UserConverter().convert(ctx, argument)
576585

577586

578587
class AttachmentConverter(Converter):
@@ -600,6 +609,7 @@ async def convert(self, ctx, arg: bool):
600609
SlashCommandOptionType.mentionable: MentionableConverter,
601610
SlashCommandOptionType.number: float,
602611
SlashCommandOptionType.attachment: AttachmentConverter,
612+
discord.Member: MemberConverter,
603613
}
604614

605615

@@ -608,16 +618,24 @@ class BridgeOption(Option, Converter):
608618
command option and a prefixed command argument for bridge commands.
609619
"""
610620

621+
def __init__(self, input_type, *args, **kwargs):
622+
self.converter = kwargs.pop("converter", None)
623+
super().__init__(input_type, *args, **kwargs)
624+
625+
self.converter = self.converter or BRIDGE_CONVERTER_MAPPING.get(input_type)
626+
611627
async def convert(self, ctx, argument: str) -> Any:
612628
try:
613629
if self.converter is not None:
614-
converted = await self.converter.convert(ctx, argument)
630+
converted = await self.converter().convert(ctx, argument)
615631
else:
616-
converter = BRIDGE_CONVERTER_MAPPING[self.input_type]
617-
if issubclass(converter, Converter):
632+
converter = BRIDGE_CONVERTER_MAPPING.get(self.input_type)
633+
if isinstance(converter, type) and issubclass(converter, Converter):
618634
converted = await converter().convert(ctx, argument) # type: ignore # protocol class
619-
else:
635+
elif callable(converter):
620636
converted = converter(argument)
637+
else:
638+
raise TypeError(f"Invalid converter: {converter}")
621639

622640
if self.choices:
623641
choices_names: list[str | int | float] = [

discord/gateway.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import traceback
3636
import zlib
3737
from collections import deque, namedtuple
38+
from typing import TYPE_CHECKING
3839

3940
import aiohttp
4041

@@ -208,6 +209,9 @@ def ack(self):
208209

209210

210211
class VoiceKeepAliveHandler(KeepAliveHandler):
212+
if TYPE_CHECKING:
213+
ws: DiscordVoiceWebSocket
214+
211215
def __init__(self, *args, **kwargs):
212216
super().__init__(*args, **kwargs)
213217
self.recent_ack_latencies = deque(maxlen=20)
@@ -216,7 +220,10 @@ def __init__(self, *args, **kwargs):
216220
self.behind_msg = "High socket latency, shard ID %s heartbeat is %.1fs behind"
217221

218222
def get_payload(self):
219-
return {"op": self.ws.HEARTBEAT, "d": int(time.time() * 1000)}
223+
return {
224+
"op": self.ws.HEARTBEAT,
225+
"d": {"t": int(time.time() * 1000), "seq_ack": self.ws.seq_ack},
226+
}
220227

221228
def ack(self):
222229
ack_time = time.perf_counter()
@@ -784,6 +791,7 @@ def __init__(self, socket, loop, *, hook=None):
784791
self._close_code = None
785792
self.secret_key = None
786793
self.ssrc_map = {}
794+
self.seq_ack: int = -1
787795
if hook:
788796
self._hook = hook
789797

@@ -804,6 +812,9 @@ async def resume(self):
804812
"token": state.token,
805813
"server_id": str(state.server_id),
806814
"session_id": state.session_id,
815+
# this seq_ack will allow for us to do buffered resume, which is, receive the
816+
# lost voice packets while trying to resume the reconnection
817+
"seq_ack": self.seq_ack,
807818
},
808819
}
809820
await self.send_as_json(payload)
@@ -824,7 +835,7 @@ async def identify(self):
824835
@classmethod
825836
async def from_client(cls, client, *, resume=False, hook=None):
826837
"""Creates a voice websocket for the :class:`VoiceClient`."""
827-
gateway = f"wss://{client.endpoint}/?v=4"
838+
gateway = f"wss://{client.endpoint}/?v=8"
828839
http = client._state.http
829840
socket = await http.ws_connect(gateway, compress=15)
830841
ws = cls(socket, loop=client.loop, hook=hook)
@@ -860,14 +871,21 @@ async def client_connect(self):
860871
await self.send_as_json(payload)
861872

862873
async def speak(self, state=SpeakingState.voice):
863-
payload = {"op": self.SPEAKING, "d": {"speaking": int(state), "delay": 0}}
874+
payload = {
875+
"op": self.SPEAKING,
876+
"d": {
877+
"speaking": int(state),
878+
"delay": 0,
879+
},
880+
}
864881

865882
await self.send_as_json(payload)
866883

867884
async def received_message(self, msg):
868885
_log.debug("Voice websocket frame received: %s", msg)
869886
op = msg["op"]
870887
data = msg.get("d")
888+
self.seq_ack = data.get("seq", self.seq_ack)
871889

872890
if op == self.READY:
873891
await self.initial_connection(data)

0 commit comments

Comments
 (0)