Added new reset_filter() helper function, fixed bug with Spotify tracks not retaining thumbnails and some other QoL features
This commit is contained in:
parent
fcbca4e8e1
commit
d1d2463680
|
|
@ -11,7 +11,7 @@ if discord.__version__ != "2.0.0a":
|
||||||
"using 'pip install git+https://github.com/Rapptz/discord.py@master'"
|
"using 'pip install git+https://github.com/Rapptz/discord.py@master'"
|
||||||
)
|
)
|
||||||
|
|
||||||
__version__ = "1.1.5.1"
|
__version__ = "1.1.6"
|
||||||
__title__ = "pomice"
|
__title__ = "pomice"
|
||||||
__author__ = "cloudwithax"
|
__author__ = "cloudwithax"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,16 @@ class Equalizer(Filter):
|
||||||
|
|
||||||
return _dict
|
return _dict
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.raw = [(0, .0), (1, .0), (2, .0), (3, .0), (4, .0),
|
||||||
|
(5, .0), (6, .0), (7, .0), (8, .0), (9, .0),
|
||||||
|
(10, .0), (11, .0), (12, .0), (13, .0), (14, .0)]
|
||||||
|
|
||||||
|
self.eq = self._factory(levels=self.raw)
|
||||||
|
self.payload = {"equalizer": self.eq}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Pomice.EqualizerFilter eq={self.eq} raw={self.raw}>"
|
return f"<Pomice.EqualizerFilter eq={self.eq} raw={self.raw}>"
|
||||||
|
|
||||||
|
|
@ -72,6 +82,18 @@ class Timescale(Filter):
|
||||||
"pitch": self.pitch,
|
"pitch": self.pitch,
|
||||||
"rate": self.rate}}
|
"rate": self.rate}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.speed = 1.0
|
||||||
|
self.pitch = 1.0
|
||||||
|
self.rate = 1.0
|
||||||
|
|
||||||
|
self.payload = {"timescale": {"speed": self.speed,
|
||||||
|
"pitch": self.pitch,
|
||||||
|
"rate": self.rate}}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Pomice.TimescaleFilter speed={self.speed} pitch={self.pitch} rate={self.rate}>"
|
return f"<Pomice.TimescaleFilter speed={self.speed} pitch={self.pitch} rate={self.rate}>"
|
||||||
|
|
||||||
|
|
@ -101,6 +123,20 @@ class Karaoke(Filter):
|
||||||
"filterBand": self.filter_band,
|
"filterBand": self.filter_band,
|
||||||
"filterWidth": self.filter_width}}
|
"filterWidth": self.filter_width}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.level: float = 1.0
|
||||||
|
self.mono_level: float = 1.0
|
||||||
|
self.filter_band: float = 220.0
|
||||||
|
self.filter_width: float = 100.0
|
||||||
|
|
||||||
|
self.payload = {"karaoke": {"level": self.level,
|
||||||
|
"monoLevel": self.mono_level,
|
||||||
|
"filterBand": self.filter_band,
|
||||||
|
"filterWidth": self.filter_width}}
|
||||||
|
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (
|
return (
|
||||||
f"<Pomice.KaraokeFilter level={self.level} mono_level={self.mono_level} "
|
f"<Pomice.KaraokeFilter level={self.level} mono_level={self.mono_level} "
|
||||||
|
|
@ -134,6 +170,16 @@ class Tremolo(Filter):
|
||||||
self.payload = {"tremolo": {"frequency": self.frequency,
|
self.payload = {"tremolo": {"frequency": self.frequency,
|
||||||
"depth": self.depth}}
|
"depth": self.depth}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.frequency: float = 2.0
|
||||||
|
self.depth: float = 0.5
|
||||||
|
|
||||||
|
self.payload = {"tremolo": {"frequency": self.frequency,
|
||||||
|
"depth": self.depth}}
|
||||||
|
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Pomice.TremoloFilter frequency={self.frequency} depth={self.depth}>"
|
return f"<Pomice.TremoloFilter frequency={self.frequency} depth={self.depth}>"
|
||||||
|
|
||||||
|
|
@ -164,6 +210,15 @@ class Vibrato(Filter):
|
||||||
self.payload = {"vibrato": {"frequency": self.frequency,
|
self.payload = {"vibrato": {"frequency": self.frequency,
|
||||||
"depth": self.depth}}
|
"depth": self.depth}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.frequency: float = 2.0
|
||||||
|
self.depth: float = 0.5
|
||||||
|
|
||||||
|
self.payload = {"vibrato": {"frequency": self.frequency,
|
||||||
|
"depth": self.depth}}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"<Pomice.VibratoFilter frequency={self.frequency} depth={self.depth}>"
|
return f"<Pomice.VibratoFilter frequency={self.frequency} depth={self.depth}>"
|
||||||
|
|
||||||
|
|
@ -179,6 +234,12 @@ class Rotation(Filter):
|
||||||
self.rotation_hertz = rotation_hertz
|
self.rotation_hertz = rotation_hertz
|
||||||
self.payload = {"rotation": {"rotationHz": self.rotation_hertz}}
|
self.payload = {"rotation": {"rotationHz": self.rotation_hertz}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.rotation_hertz = 5
|
||||||
|
self.payload = {"rotation": {"rotationHz": self.rotation_hertz}}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Pomice.RotationFilter rotation_hertz={self.rotation_hertz}>"
|
return f"<Pomice.RotationFilter rotation_hertz={self.rotation_hertz}>"
|
||||||
|
|
||||||
|
|
@ -222,6 +283,20 @@ class ChannelMix(Filter):
|
||||||
"rightToRight": self.right_to_right}
|
"rightToRight": self.right_to_right}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.left_to_left: float = 1
|
||||||
|
self.right_to_right: float = 1
|
||||||
|
self.left_to_right: float = 0
|
||||||
|
self.right_to_left: float = 0
|
||||||
|
|
||||||
|
self.payload = {"channelMix": {"leftToLeft": self.left_to_left,
|
||||||
|
"leftToRight": self.left_to_right,
|
||||||
|
"rightToLeft": self.right_to_left,
|
||||||
|
"rightToRight": self.right_to_right}
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"<Pomice.ChannelMix left_to_left={self.left_to_left} left_to_right={self.left_to_right} "
|
f"<Pomice.ChannelMix left_to_left={self.left_to_left} left_to_right={self.left_to_right} "
|
||||||
|
|
@ -267,6 +342,30 @@ class Distortion(Filter):
|
||||||
"scale": self.scale
|
"scale": self.scale
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.sin_offset: float = 0
|
||||||
|
self.sin_scale: float = 1
|
||||||
|
self.cos_offset: float = 0
|
||||||
|
self.cos_scale: float = 1
|
||||||
|
self.tan_offset: float = 0
|
||||||
|
self.tan_scale: float = 1
|
||||||
|
self.offset: float = 0
|
||||||
|
self.scale: float = 1
|
||||||
|
|
||||||
|
self.payload = {"distortion": {
|
||||||
|
"sinOffset": self.sin_offset,
|
||||||
|
"sinScale": self.sin_scale,
|
||||||
|
"cosOffset": self.cos_offset,
|
||||||
|
"cosScale": self.cos_scale,
|
||||||
|
"tanOffset": self.tan_offset,
|
||||||
|
"tanScale": self.tan_scale,
|
||||||
|
"offset": self.offset,
|
||||||
|
"scale": self.scale
|
||||||
|
}}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return (
|
return (
|
||||||
f"<Pomice.Distortion sin_offset={self.sin_offset} sin_scale={self.sin_scale}> "
|
f"<Pomice.Distortion sin_offset={self.sin_offset} sin_scale={self.sin_scale}> "
|
||||||
|
|
@ -286,6 +385,12 @@ class LowPass(Filter):
|
||||||
self.smoothing = smoothing
|
self.smoothing = smoothing
|
||||||
self.payload = {"lowPass": {"smoothing": self.smoothing}}
|
self.payload = {"lowPass": {"smoothing": self.smoothing}}
|
||||||
|
|
||||||
|
def _reset(self):
|
||||||
|
self.smoothing = 20
|
||||||
|
self.payload = {"lowPass": {"smoothing": self.smoothing}}
|
||||||
|
|
||||||
|
return self.payload
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<Pomice.LowPass smoothing={self.smoothing}>"
|
return f"<Pomice.LowPass smoothing={self.smoothing}>"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,15 +37,16 @@ class Track:
|
||||||
self.author = info.get("author")
|
self.author = info.get("author")
|
||||||
self.uri = info.get("uri")
|
self.uri = info.get("uri")
|
||||||
self.identifier = info.get("identifier")
|
self.identifier = info.get("identifier")
|
||||||
|
|
||||||
if info.get("thumbnail"):
|
if info.get("thumbnail"):
|
||||||
self.thumbnail = info.get("thumbnail")
|
self.thumbnail = info.get("thumbnail")
|
||||||
|
elif SOUNDCLOUD_URL_REGEX.match(self.uri):
|
||||||
|
# ok so theres no feasible way of getting a Soundcloud image URL
|
||||||
|
# so we're just gonna leave it blank for brevity
|
||||||
|
self.thumbnail = None
|
||||||
else:
|
else:
|
||||||
if SOUNDCLOUD_URL_REGEX.match(self.uri):
|
self.thumbnail = f"https://img.youtube.com/vi/{self.identifier}/mqdefault.jpg"
|
||||||
# ok so theres no feasible way of getting a Soundcloud image URL
|
|
||||||
# so we're just gonna leave it blank for brevity
|
|
||||||
self.thumbnail = None
|
|
||||||
else:
|
|
||||||
self.thumbnail = f"https://img.youtube.com/vi/{self.identifier}/mqdefault.jpg"
|
|
||||||
self.length = info.get("length")
|
self.length = info.get("length")
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
self.requester = self.ctx.author if ctx else None
|
self.requester = self.ctx.author if ctx else None
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from discord.ext import commands
|
||||||
from . import events
|
from . import events
|
||||||
from .enums import SearchType
|
from .enums import SearchType
|
||||||
from .events import PomiceEvent, TrackEndEvent, TrackStartEvent
|
from .events import PomiceEvent, TrackEndEvent, TrackStartEvent
|
||||||
from .exceptions import TrackInvalidPosition
|
from .exceptions import FilterInvalidArgument, TrackInvalidPosition
|
||||||
from .filters import Filter
|
from .filters import Filter
|
||||||
from .objects import Track
|
from .objects import Track
|
||||||
from .pool import Node, NodePool
|
from .pool import Node, NodePool
|
||||||
|
|
@ -279,7 +279,7 @@ class Player(VoiceProtocol):
|
||||||
"""Seeks to a position in the currently playing track milliseconds"""
|
"""Seeks to a position in the currently playing track milliseconds"""
|
||||||
if position < 0 or position > self._current.original.length:
|
if position < 0 or position > self._current.original.length:
|
||||||
raise TrackInvalidPosition(
|
raise TrackInvalidPosition(
|
||||||
f"Seek position must be between 0 and the track length"
|
"Seek position must be between 0 and the track length"
|
||||||
)
|
)
|
||||||
|
|
||||||
await self._node.send(op="seek", guildId=str(self.guild.id), position=position)
|
await self._node.send(op="seek", guildId=str(self.guild.id), position=position)
|
||||||
|
|
@ -299,9 +299,29 @@ class Player(VoiceProtocol):
|
||||||
|
|
||||||
async def set_filter(self, filter: Filter) -> Filter:
|
async def set_filter(self, filter: Filter) -> Filter:
|
||||||
"""Sets a filter of the player. Takes a pomice.Filter object.
|
"""Sets a filter of the player. Takes a pomice.Filter object.
|
||||||
This will only work if you are using the development version of Lavalink.
|
This will only work if you are using a version of Lavalink that supports filters.
|
||||||
"""
|
"""
|
||||||
await self._node.send(op="filters", guildId=str(self.guild.id), **filter.payload)
|
await self._node.send(op="filters", guildId=str(self.guild.id), **filter.payload)
|
||||||
await self.seek(self.position)
|
await self.seek(self.position)
|
||||||
self._filter = filter
|
self._filter = filter
|
||||||
return filter
|
return filter
|
||||||
|
|
||||||
|
async def reset_filter(self):
|
||||||
|
"""Resets a currently applied filter to its default parameters.
|
||||||
|
You must have a filter applied in order for this to work
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not self._filter:
|
||||||
|
raise FilterInvalidArgument(
|
||||||
|
"You must have a filter applied first in order to use this method."
|
||||||
|
)
|
||||||
|
|
||||||
|
_payload: dict = self._filter._reset()
|
||||||
|
await self._node.send(op="filters", guildId=str(self.guild.id), **_payload)
|
||||||
|
await self.seek(self.position)
|
||||||
|
self._filter = None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import json
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
import socket
|
|
||||||
from typing import Dict, Optional, TYPE_CHECKING
|
from typing import Dict, Optional, TYPE_CHECKING
|
||||||
from urllib.parse import quote
|
from urllib.parse import quote
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
@ -194,7 +193,6 @@ class Node:
|
||||||
if msg.type == aiohttp.WSMsgType.CLOSED:
|
if msg.type == aiohttp.WSMsgType.CLOSED:
|
||||||
retry = backoff.delay()
|
retry = backoff.delay()
|
||||||
await asyncio.sleep(retry)
|
await asyncio.sleep(retry)
|
||||||
|
|
||||||
if not self.is_connected:
|
if not self.is_connected:
|
||||||
self._bot.loop.create_task(self.connect())
|
self._bot.loop.create_task(self.connect())
|
||||||
else:
|
else:
|
||||||
|
|
@ -220,7 +218,7 @@ class Node:
|
||||||
async def send(self, **data):
|
async def send(self, **data):
|
||||||
if not self._available:
|
if not self._available:
|
||||||
raise NodeNotAvailable(
|
raise NodeNotAvailable(
|
||||||
f"The node '{self.identifier}' is unavailable."
|
f"The node '{self._identifier}' is unavailable."
|
||||||
)
|
)
|
||||||
|
|
||||||
await self._websocket.send_str(json.dumps(data))
|
await self._websocket.send_str(json.dumps(data))
|
||||||
|
|
@ -240,6 +238,11 @@ class Node:
|
||||||
self._task = self._bot.loop.create_task(self._listen())
|
self._task = self._bot.loop.create_task(self._listen())
|
||||||
self._available = True
|
self._available = True
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
except aiohttp.ClientConnectorError:
|
||||||
|
raise NodeConnectionFailure(
|
||||||
|
f"The connection to node '{self._identifier}' failed."
|
||||||
|
)
|
||||||
except aiohttp.WSServerHandshakeError:
|
except aiohttp.WSServerHandshakeError:
|
||||||
raise NodeConnectionFailure(
|
raise NodeConnectionFailure(
|
||||||
f"The password for node '{self._identifier}' is invalid."
|
f"The password for node '{self._identifier}' is invalid."
|
||||||
|
|
@ -248,10 +251,6 @@ class Node:
|
||||||
raise NodeConnectionFailure(
|
raise NodeConnectionFailure(
|
||||||
f"The URI for node '{self._identifier}' is invalid."
|
f"The URI for node '{self._identifier}' is invalid."
|
||||||
)
|
)
|
||||||
except socket.gaierror:
|
|
||||||
raise NodeConnectionFailure(
|
|
||||||
f"The node '{self._identifier}' failed to connect."
|
|
||||||
)
|
|
||||||
|
|
||||||
async def disconnect(self):
|
async def disconnect(self):
|
||||||
"""Disconnects a connected Lavalink node and removes it from the node pool.
|
"""Disconnects a connected Lavalink node and removes it from the node pool.
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,10 @@ class Album:
|
||||||
def __init__(self, data: dict) -> None:
|
def __init__(self, data: dict) -> None:
|
||||||
self.name = data["name"]
|
self.name = data["name"]
|
||||||
self.artists = ", ".join(artist["name"] for artist in data["artists"])
|
self.artists = ", ".join(artist["name"] for artist in data["artists"])
|
||||||
self.tracks = [Track(track) for track in data["tracks"]["items"]]
|
self.image = data["images"][0]["url"]
|
||||||
|
self.tracks = [Track(track, image=self.image) for track in data["tracks"]["items"]]
|
||||||
self.total_tracks = data["total_tracks"]
|
self.total_tracks = data["total_tracks"]
|
||||||
self.id = data["id"]
|
self.id = data["id"]
|
||||||
self.image = data["images"][0]["url"]
|
|
||||||
self.uri = data["external_urls"]["spotify"]
|
self.uri = data["external_urls"]["spotify"]
|
||||||
|
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
class Track:
|
class Track:
|
||||||
"""The base class for a Spotify Track"""
|
"""The base class for a Spotify Track"""
|
||||||
|
|
||||||
def __init__(self, data: dict) -> None:
|
def __init__(self, data: dict, image = None) -> None:
|
||||||
self.name = data["name"]
|
self.name = data["name"]
|
||||||
self.artists = ", ".join(artist["name"] for artist in data["artists"])
|
self.artists = ", ".join(artist["name"] for artist in data["artists"])
|
||||||
self.length = data["duration_ms"]
|
self.length = data["duration_ms"]
|
||||||
|
|
@ -10,7 +10,7 @@ class Track:
|
||||||
if data.get("album") and data["album"].get("images"):
|
if data.get("album") and data["album"].get("images"):
|
||||||
self.image = data["album"]["images"][0]["url"]
|
self.image = data["album"]["images"][0]["url"]
|
||||||
else:
|
else:
|
||||||
self.image = None
|
self.image = image
|
||||||
|
|
||||||
if data["is_local"]:
|
if data["is_local"]:
|
||||||
self.uri = None
|
self.uri = None
|
||||||
|
|
|
||||||
2
setup.py
2
setup.py
|
|
@ -6,7 +6,7 @@ with open("README.md") as f:
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="pomice",
|
name="pomice",
|
||||||
author="cloudwithax",
|
author="cloudwithax",
|
||||||
version="1.1.5.1",
|
version="1.1.6",
|
||||||
url="https://github.com/cloudwithax/pomice",
|
url="https://github.com/cloudwithax/pomice",
|
||||||
packages=setuptools.find_packages(),
|
packages=setuptools.find_packages(),
|
||||||
license="GPL",
|
license="GPL",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue