Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add inactive_channel check. #302

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
[![Github License](https://img.shields.io/github/license/PythonistaGuild/Wavelink)](LICENSE)
[![Lavalink Version](https://img.shields.io/badge/Lavalink-v4.0%2B-blue?color=%23FB7713)](https://lavalink.dev)
![Lavalink Plugins](https://img.shields.io/badge/Lavalink_Plugins-Native_Support-blue?color=%2373D673)
[![Discord](https://img.shields.io/discord/490948346773635102?logo=discord&logoColor=%23FFF&label=Pythonista&labelColor=%235865F2&color=%232B2D31)](https://discord.gg/RAKc3HF)


</div>
Expand Down
6 changes: 6 additions & 0 deletions wavelink/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ class Node:
inactive_player_timeout: int | None
Set the default for :attr:`wavelink.Player.inactive_timeout` on every player that connects to this node.
Defaults to ``300``.
inactive_channel_tokens: int | None
Sets the default for :attr:`wavelink.Player.inactive_channel_tokens` on every player that connects to this node.
Defaults to ``3``.

See also: :func:`on_wavelink_inactive_player`.
"""
Expand All @@ -142,6 +145,7 @@ def __init__(
client: discord.Client | None = None,
resume_timeout: int = 60,
inactive_player_timeout: int | None = 300,
inactive_channel_tokens: int | None = 3,
) -> None:
self._identifier = identifier or secrets.token_urlsafe(12)
self._uri = uri.removesuffix("/")
Expand Down Expand Up @@ -170,6 +174,8 @@ def __init__(
inactive_player_timeout if inactive_player_timeout and inactive_player_timeout > 0 else None
)

self._inactive_channel_tokens = inactive_channel_tokens

def __repr__(self) -> str:
return f"Node(identifier={self.identifier}, uri={self.uri}, status={self.status}, players={len(self.players)})"

Expand Down
73 changes: 65 additions & 8 deletions wavelink/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ def __init__(
self._auto_lock: asyncio.Lock = asyncio.Lock()
self._error_count: int = 0

self._inactive_channel_limit: int | None = self._node._inactive_channel_tokens
self._inactive_channel_count: int = self._inactive_channel_limit if self._inactive_channel_limit else 0

self._filters: Filters = Filters()

# Needed for the inactivity checks...
Expand Down Expand Up @@ -216,7 +219,21 @@ async def _track_start(self, payload: TrackStartEventPayload) -> None:
self._inactivity_cancel()

async def _auto_play_event(self, payload: TrackEndEventPayload) -> None:
if self._autoplay is AutoPlayMode.disabled:
if not self.channel:
return

members: int = len([m for m in self.channel.members if not m.bot])
self._inactive_channel_count = (
self._inactive_channel_count - 1 if not members else self._inactive_channel_limit or 0
)

if self._inactive_channel_limit and self._inactive_channel_count <= 0:
self._inactive_channel_count = self._inactive_channel_limit # Reset...

self._inactivity_cancel()
self.client.dispatch("wavelink_inactive_player", self)

elif self._autoplay is AutoPlayMode.disabled:
self._inactivity_start()
return

Expand Down Expand Up @@ -403,6 +420,49 @@ async def _search(query: str | None) -> T_a:
logger.info('Player "%s" could not load any songs via AutoPlay.', self.guild.id)
self._inactivity_start()

@property
def inactive_channel_tokens(self) -> int | None:
"""A settable property which returns the token limit as an ``int`` of the amount of tracks to play before firing
the :func:`on_wavelink_inactive_player` event when a channel is inactive.

This property could return ``None`` if the check has been disabled.

A channel is considered inactive when no real members (Members other than bots) are in the connected voice
channel. On each consecutive track played without a real member in the channel, this token bucket will reduce
by ``1``. After hitting ``0``, the :func:`on_wavelink_inactive_player` event will be fired and the token bucket
will reset to the set value. The default value for this property is ``3``.

This property can be set with any valid ``int`` or ``None``. If this property is set to ``<= 0`` or ``None``,
the check will be disabled.

Setting this property to ``1`` will fire the :func:`on_wavelink_inactive_player` event at the end of every track
if no real members are in the channel and you have not disconnected the player.

If this check successfully fires the :func:`on_wavelink_inactive_player` event, it will cancel any waiting
:attr:`inactive_timeout` checks until a new track is played.

The default for every player can be set on :class:`~wavelink.Node`.

- See: :class:`~wavelink.Node`
- See: :func:`on_wavelink_inactive_player`

.. warning::

Setting this property will reset the bucket.

.. versionadded:: 3.4.0
"""
return self._inactive_channel_limit

@inactive_channel_tokens.setter
def inactive_channel_tokens(self, value: int | None) -> None:
if not value or value <= 0:
self._inactive_channel_limit = None
return

self._inactive_channel_limit = value
self._inactive_channel_count = value

@property
def inactive_timeout(self) -> int | None:
"""A property which returns the time as an ``int`` of seconds to wait before this player dispatches the
Expand Down Expand Up @@ -616,14 +676,11 @@ async def _dispatch_voice_update(self) -> None:
assert self.guild is not None
data: VoiceState = self._voice_state["voice"]

try:
session_id: str = data["session_id"]
token: str = data["token"]
except KeyError:
return

session_id: str | None = data.get("session_id", None)
token: str | None = data.get("token", None)
endpoint: str | None = data.get("endpoint", None)
if not endpoint:

if not session_id or not token or not endpoint:
return

request: RequestPayload = {"voice": {"sessionId": session_id, "token": token, "endpoint": endpoint}}
Expand Down
Loading