edit filters, log level matches handler, other fixes

This commit is contained in:
cloudwithax 2023-05-21 10:42:43 -04:00
parent cbb676e004
commit 02d22f20b5
No known key found for this signature in database
GPG Key ID: 5DBE54E45794983E
4 changed files with 142 additions and 5 deletions

View File

@ -20,7 +20,7 @@ if not discord.version_info.major >= 2:
"using 'pip install discord.py'",
)
__version__ = "2.6.1a"
__version__ = "2.7.0a"
__title__ = "pomice"
__author__ = "cloudwithax"
__license__ = "GPL-3.0"

View File

@ -77,6 +77,12 @@ class Equalizer(Filter):
def __repr__(self) -> str:
return f"<Pomice.EqualizerFilter tag={self.tag} eq={self.eq} raw={self.raw}>"
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Equalizer):
return False
return self.raw == __value.raw
@classmethod
def flat(cls) -> "Equalizer":
"""Equalizer preset which represents a flat EQ board,
@ -231,6 +237,16 @@ class Timescale(Filter):
def __repr__(self) -> str:
return f"<Pomice.TimescaleFilter tag={self.tag} speed={self.speed} pitch={self.pitch} rate={self.rate}>"
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Timescale):
return False
return (
self.speed == __value.speed
and self.pitch == __value.pitch
and self.rate == __value.rate
)
class Karaoke(Filter):
"""Filter which filters the vocal track from any song and leaves the instrumental.
@ -270,6 +286,17 @@ class Karaoke(Filter):
f"filter_band={self.filter_band} filter_width={self.filter_width}>"
)
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Karaoke):
return False
return (
self.level == __value.level
and self.mono_level == __value.mono_level
and self.filter_band == __value.filter_band
and self.filter_width == __value.filter_width
)
class Tremolo(Filter):
"""Filter which produces a wavering tone in the music,
@ -305,6 +332,12 @@ class Tremolo(Filter):
f"<Pomice.TremoloFilter tag={self.tag} frequency={self.frequency} depth={self.depth}>"
)
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Tremolo):
return False
return self.frequency == __value.frequency and self.depth == __value.depth
class Vibrato(Filter):
"""Filter which produces a wavering tone in the music, similar to the Tremolo filter,
@ -340,6 +373,12 @@ class Vibrato(Filter):
f"<Pomice.VibratoFilter tag={self.tag} frequency={self.frequency} depth={self.depth}>"
)
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Vibrato):
return False
return self.frequency == __value.frequency and self.depth == __value.depth
class Rotation(Filter):
"""Filter which produces a stereo-like panning effect, which sounds like
@ -357,6 +396,12 @@ class Rotation(Filter):
def __repr__(self) -> str:
return f"<Pomice.RotationFilter tag={self.tag} rotation_hertz={self.rotation_hertz}>"
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Rotation):
return False
return self.rotation_hertz == __value.rotation_hertz
class ChannelMix(Filter):
"""Filter which manually adjusts the panning of the audio, which can make
@ -418,6 +463,17 @@ class ChannelMix(Filter):
f"right_to_left={self.right_to_left} right_to_right={self.right_to_right}>"
)
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, ChannelMix):
return False
return (
self.left_to_left == __value.left_to_left
and self.left_to_right == __value.left_to_right
and self.right_to_left == __value.right_to_left
and self.right_to_right == __value.right_to_right
)
class Distortion(Filter):
"""Filter which generates a distortion effect. Useful for certain filter implementations where
@ -479,6 +535,21 @@ class Distortion(Filter):
f"tan_scale={self.tan_scale} offset={self.offset} scale={self.scale}"
)
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, Distortion):
return False
return (
self.sin_offset == __value.sin_offset
and self.sin_scale == __value.sin_scale
and self.cos_offset == __value.cos_offset
and self.cos_scale == __value.cos_scale
and self.tan_offset == __value.tan_offset
and self.tan_scale == __value.tan_scale
and self.offset == __value.offset
and self.scale == __value.scale
)
class LowPass(Filter):
"""Filter which supresses higher frequencies and allows lower frequencies to pass.
@ -495,3 +566,9 @@ class LowPass(Filter):
def __repr__(self) -> str:
return f"<Pomice.LowPass tag={self.tag} smoothing={self.smoothing}>"
def __eq__(self, __value: object) -> bool:
if not isinstance(__value, LowPass):
return False
return self.smoothing == __value.smoothing

View File

@ -79,6 +79,27 @@ class Filters:
if filter.tag == filter_tag:
del self._filters[index]
def edit_filter(self, *, filter_tag: str, to_apply: Filter) -> None:
"""Edits a filter in the list of filters applied using its filter tag and replaces it with the new filter."""
if not any(f for f in self._filters if f.tag == filter_tag):
raise FilterTagInvalid("A filter with that tag was not found.")
for index, filter in enumerate(self._filters):
if filter.tag == filter_tag:
if not type(filter) == type(to_apply):
raise FilterInvalidArgument(
"Edited filter is not the same type as the current filter.",
)
if self._filters[index] == to_apply:
raise FilterInvalidArgument("Edited filter is the same as the current filter.")
if to_apply.tag != filter_tag:
raise FilterInvalidArgument(
"Edited filter tag is not the same as the current filter tag.",
)
self._filters[index] = to_apply
def has_filter(self, *, filter_tag: str) -> bool:
"""Checks if a filter exists in the list of filters using its filter tag"""
return any(f for f in self._filters if f.tag == filter_tag)
@ -382,6 +403,16 @@ class Player(VoiceProtocol):
"""
return await self._node.get_tracks(query, ctx=ctx, search_type=search_type, filters=filters)
async def build_track(self, identifier: str, ctx: Optional[commands.Context] = None) -> Track:
"""
Builds a track using a valid track identifier
You can also pass in a discord.py Context object to get a
Context object on the track it builds.
"""
return await self._node.build_track(identifier, ctx=ctx)
async def get_recommendations(
self, *, track: Track, ctx: Optional[commands.Context] = None
) -> Optional[Union[List[Track], Playlist]]:
@ -431,7 +462,7 @@ class Player(VoiceProtocol):
except AttributeError:
# 'NoneType' has no attribute '_get_voice_client_key' raised by self.cleanup() ->
# assume we're already disconnected and cleaned up
assert not self.is_connected and not self.channel
assert self.channel is None and not self.is_connected
self._node._players.pop(self.guild.id)
if self.node.is_connected:
@ -637,6 +668,33 @@ class Player(VoiceProtocol):
return self._filters
async def edit_filter(
self, *, filter_tag: str, edited_filter: Filter, fast_apply: bool = False
) -> Filters:
"""Edits a filter from the player using its filter tag and a new filter of the same type.
The filter to be replaced must have the same tag as the one you are replacing it with.
This will only work if you are using a version of Lavalink that supports filters.
If you would like for the filter to apply instantly, set the `fast_apply` arg to `True`.
(You must have a song playing in order for `fast_apply` to work.)
"""
self._filters.edit_filter(filter_tag=filter_tag, to_apply=edited_filter)
payload = self._filters.get_all_payloads()
await self._node.send(
method="PATCH",
path=self._player_endpoint_uri,
guild_id=self._guild.id,
data={"filters": payload},
)
self._log.debug(f"Filter with tag {filter_tag} has been edited to {edited_filter!r}")
if fast_apply:
self._log.debug(f"Fast apply passed, now editing filter instantly.")
await self.seek(self.position)
return self._filters
async def reset_filters(self, *, fast_apply: bool = False) -> None:
"""Resets all currently applied filters to their default parameters.
You must have filters applied in order for this to work.

View File

@ -112,7 +112,7 @@ class Node:
password: str,
identifier: str,
secure: bool = False,
heartbeat: int = 60,
heartbeat: int = 120,
resume_key: Optional[str] = None,
resume_timeout: int = 60,
loop: Optional[asyncio.AbstractEventLoop] = None,
@ -234,13 +234,15 @@ class Node:
def _setup_logging(self, level: LogLevel) -> logging.Logger:
logger = logging.getLogger("pomice")
logger.setLevel(level)
handler = None
if self._log_handler:
handler = self._log_handler
logger.setLevel(handler.level)
else:
handler = logging.StreamHandler()
logger.setLevel(level)
dt_fmt = "%Y-%m-%d %H:%M:%S"
formatter = logging.Formatter(
"[{asctime}] [{levelname:<8}] {name}: {message}",
@ -960,7 +962,7 @@ class NodePool:
password: str,
identifier: str,
secure: bool = False,
heartbeat: int = 30,
heartbeat: int = 120,
resume_key: Optional[str] = None,
resume_timeout: int = 60,
loop: Optional[asyncio.AbstractEventLoop] = None,