Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
66 changes: 66 additions & 0 deletions mafic/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
"TrackStartEvent",
"TrackStuckEvent",
"WebSocketClosedEvent",
"LyricsLineEvent",
"LyricsFoundEvent",
"LyricsNotFoundEvent",
)


Expand Down Expand Up @@ -89,6 +92,69 @@ def __repr__(self) -> str:
)


class LyricsLineEvent(Generic[PlayerT]):
"""Represents a lyrics line event.

Attributes
----------
guildId: :class:`str`
The guild ID that received the lyrics line.
line: :class:`dict`

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this dict instead be a TypedDict containing the fields (timestamp, duration, etc) as with the other events here. Same with the other events you've added.

Information about the lyrics line.
"""

__slots__ = ("guildId", "line")

def __init__(self, *, guildId: str, line: dict) -> None:
self.guildId: str = guildId
self.line: dict = line

def __repr__(self) -> str:
"""Get a string representation of the event."""
return f"<LyricsLineEvent guildId={self.guildId} line={self.line!r}>"


class LyricsFoundEvent(Generic[PlayerT]):
"""Represents a lyrics found event.

Attributes
----------
guildId: :class:`str`
The guild ID that received lyrics.
lyrics: :class:`dict`
Information about all lyrics, including provider and platform.
"""

__slots__ = ("guildId", "lyrics")

def __init__(self, *, guildId: str, lyrics: dict) -> None:
self.guildId: str = guildId
self.lyrics: dict = lyrics

def __repr__(self) -> str:
"""Get a string representation of the event."""
return f"<LyricsFoundEvent guildId={self.guildId} lyrics={self.lyrics!r}>"


class LyricsNotFoundEvent(Generic[PlayerT]):
"""Represents a lyrics not found event.

Attributes
----------
guildId: :class:`str`
The guild ID that received event.
"""

__slots__ = "guildId"

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
__slots__ = "guildId"
__slots__ = ("guildId",)

__slots__ must be a tuple, and a trailing comma is needed for a single element tuple.


def __init__(self, *, guildId: str) -> None:
self.guildId: str = guildId

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe a better solution is to continue to use the player in both of these events, as it is available in node.py's event handling, and also contains this guild id if required. Users can use that player to add any data they need - say to return the error to the user more efficiently.


def __repr__(self) -> str:
"""Get a string representation of the event."""
return f"<LyricsNotFoundEvent guildId={self.guildId}>"


class TrackStartEvent(Generic[PlayerT]):
"""Represents an event when a track starts playing.

Expand Down
18 changes: 18 additions & 0 deletions mafic/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -1397,3 +1397,21 @@ async def sync_players(
for player_id in expected_player_ids - actual_player_ids
),
)

async def subscribe_to_lyrics(self, guild_id: int, skip_track_source: bool) -> None:
"""
Subscribe to Lyrics events. Requires Lavalyrics plugin to be installed.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
Subscribe to Lyrics events. Requires Lavalyrics plugin to be installed.
"""Subscribe to lyrics-related events.
This requires the `LavaLyrics`_ plugin to be installed.
.. _LavaLyrics: https://github.com/topi314/LavaLyrics/


Parameters
----------
guild_id:
The guild that will receive lyrics events
skip_track_source:
Skip the current track source and fetch from highest priority source
"""
data = await self.__request(

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no data here as it returns HTTP 204 No Content.

"POST",
f"sessions/{self._session_id}/players/{guild_id}/lyrics/subscribe",
params={"skipTrackSource": str(skip_track_source)},
)
_log.debug("Subscribe data: %s", data)
12 changes: 12 additions & 0 deletions mafic/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,18 @@ def dispatch_event(self, data: EventPayload) -> None:
event = TrackStuckEvent(player=self, track=track, payload=data)
self.client.dispatch("track_stuck", event)
_log.debug("Received track stuck event: %s", event)
elif data["type"] == "LyricsLineEvent":
event = LyricsLineEvent(guildId=data["guildId"], line=data["line"])
self.client.dispatch("lyrics_line", event)
_log.debug("Received lyrics line event: %s", event)
elif data["type"] == "LyricsFoundEvent":
event = LyricsFoundEvent(guildId=data["guildId"], lyrics=data["lyrics"])
self.client.dispatch("lyrics_found", event)
_log.debug("Received lyrics found event: %s", event)
elif data["type"] == "LyricsNotFoundEvent":
event = LyricsNotFoundEvent(guildId=data["guildId"])
self.client.dispatch("lyrics_not_found", event)
_log.debug("Received lyrics not found event: %s", event)
else:
# Pyright expects this to never happen, so do I, I really hope.
# Nobody expects the Spanish Inquisition, neither does pyright.
Expand Down