This commit is contained in:
vveeps 2021-10-09 22:44:12 +03:00
commit a72afa8031
6 changed files with 81 additions and 33 deletions

View File

@ -4,10 +4,17 @@ __version__ = "1.0.5"
__title__ = "pomice"
__author__ = "cloudwithax"
import discord
if discord.__version__ != '2.0.0a':
raise exit("You must have discord.py 2.0 to use this library. Uninstall your current version and install discord.py 2.0 using 'pip install git+https://github.com/Rapptz/discord.py'")
from .enums import SearchType
from .events import *
from .exceptions import *
from .filters import *
from .node import Node, NodePool
from .objects import Track, Playlist
from .pool import *
from .objects import *
from .player import Player
from .enums import SearchType

View File

@ -1,4 +1,4 @@
from .node import NodePool
from .pool import NodePool
class PomiceEvent:

View File

@ -1,3 +1,4 @@
from re import S
from typing import Optional
from discord.ext import commands
@ -36,6 +37,11 @@ class Track:
self.is_seekable = info.get("isSeekable")
self.position = info.get("position")
if self.spotify:
self.youtube_result = None
if search_type:
self.search_type = search_type
def __eq__(self, other):
if not isinstance(other, Track):
return False

View File

@ -2,7 +2,7 @@ import time
from typing import Any, Dict, Type, Union
import discord
from discord import VoiceChannel, VoiceProtocol, Guild, Member
from discord import VoiceChannel, VoiceProtocol, Guild
from discord.ext import commands
from . import events
@ -24,10 +24,9 @@ class Player(VoiceProtocol):
super().__init__(client=client, channel=channel)
self.client = client
self._bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]] = client
self._bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot] = client
self.channel = channel
self._guild: discord.Guild = self.channel.guild
self._dj: discord.Member = None
self._node = NodePool.get_node()
self._current: Track = None
@ -71,6 +70,11 @@ class Player(VoiceProtocol):
"""Property which returns whether or not the player is actively playing a track."""
return self._is_connected and self.current is not None
@property
def is_connected(self) -> bool:
"""Property which returns whether or not the player is connected"""
return self._is_connected
@property
def is_paused(self) -> bool:
"""Property which returns whether or not the player has a track which is paused or not."""
@ -96,11 +100,6 @@ class Player(VoiceProtocol):
"""Property which returns the players current volume"""
return self._volume
@property
def dj(self) -> Member:
"""Property which returns the DJ for the player session"""
return self._dj
@property
def filter(self) -> Filter:
"""Property which returns the currently applied filter, if one is applied"""
@ -161,11 +160,11 @@ class Player(VoiceProtocol):
async def connect(self, *, timeout: float, reconnect: bool):
await self.guild.change_voice_state(channel=self.channel)
self._node._players[self.guild.id] = self
self.is_connected = True
self._is_connected = True
async def stop(self):
"""Stops a currently playing track."""
self.current = None
self._current = None
await self._node.send(op="stop", guildId=str(self.guild.id))
async def disconnect(self, *, force: bool = False):
@ -184,10 +183,17 @@ class Player(VoiceProtocol):
async def play(self, track: Track, start_position: int = 0) -> Track:
"""Plays a track. If a Spotify track is passed in, it will be handled accordingly."""
if track.spotify:
<< << << < HEAD
search: Track = (await self._node.get_tracks(
f"{track._search_type}:{track.author} - {track.title}"
))[0]
track.original = search
== == == =
spotify_track: objects.Track = (await self._node.get_tracks(f"{track.search_type}"))[0]
track.youtube_result = spotify_track
>>>>>> > f6a375229831e0e68f0ccc8483ebde284247ee9c
await self._node.send(
op="play",
guildId=str(self.guild.id),

View File

@ -33,6 +33,10 @@ SPOTIFY_URL_REGEX = re.compile(
r"https?://open.spotify.com/(?P<type>album|playlist|track)/(?P<id>[a-zA-Z0-9]+)"
)
DISCORD_MP3_URL_REGEX = re.compile(
r"https?://cdn.discordapp.com/attachments/(?P<channel_id>[0-9]+)/(?P<message_id>[0-9]+)/(?P<file>[a-zA-Z0-9_.]+)+"
)
class Node:
"""The base class for a node.
@ -43,16 +47,17 @@ class Node:
def __init__(
self,
pool,
bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]],
bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot],
host: str,
port: int,
password: str,
identifier: str,
session: Optional[aiohttp.ClientSession],
spotify_client_id: Optional[str],
spotify_client_secret: Optional[str],
session: Optional[aiohttp.ClientSession]
):
self._bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]] = bot
self._bot: Union[discord.Client, commands.Bot, commands.AutoShardedBot] = bot
self._host: str = host
self._port: int = port
self._pool: NodePool = pool
@ -123,7 +128,7 @@ class Node:
return self._players
@property
def bot(self) -> Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]]:
def bot(self) -> Union[discord.Client, commands.Bot, commands.AutoShardedBot]:
"""Property which returns the discord.py client linked to this node"""
return self._bot
@ -194,13 +199,13 @@ class Node:
await player._update_state(data)
async def send(self, **data):
if not self.available:
if not self._available:
raise NodeNotAvailable(
f"The node '{self.identifier}' is not currently available.")
await self._websocket.send_str(json.dumps(data))
def get_player(self, guild_id: int) -> Player:
def get_player(self, guild_id: int):
"""Takes a guild ID as a parameter. Returns a pomice Player object."""
return self._players.get(guild_id, None)
@ -262,10 +267,10 @@ class Node:
"please obtain Spotify API credentials here: https://developer.spotify.com/"
)
spotify_type = spotify_url_check.group("type")
spotify_search_type = spotify_url_check.group("type")
spotify_id = spotify_url_check.group("id")
if spotify_type == "playlist":
if spotify_search_type == "playlist":
results = spotify.Playlist(
client=self._spotify_client,
data=await self._spotify_http_client.get_playlist(spotify_id)
@ -277,7 +282,7 @@ class Node:
Track(
track_id=track.id,
ctx=ctx,
search_type=search_type,
search_type=f"{search_type}{track.artists[0].name} - {track.name}" if search_type else f"ytmsearch:{track.artists[0].name} - {track.name}",
spotify=True,
info={
"title": track.name or "Unknown",
@ -309,7 +314,7 @@ class Node:
f"Unable to find results for {query}"
)
elif spotify_type == "album":
elif spotify_search_type == "album":
results = await self._spotify_client.get_album(spotify_id=spotify_id)
try:
@ -318,7 +323,7 @@ class Node:
Track(
track_id=track.id,
ctx=ctx,
search_type=search_type,
search_type=f"{search_type}{track.artists[0].name} - {track.name}" if search_type else f"ytmsearch:{track.artists[0].name} - {track.name}",
spotify=True,
info={
"title": track.name or "Unknown",
@ -348,7 +353,7 @@ class Node:
except SpotifyException:
raise SpotifyAlbumLoadFailed(f"Unable to find results for {query}")
elif spotify_type == 'track':
elif spotify_search_type == 'track':
try:
results = await self._spotify_client.get_track(spotify_id=spotify_id)
@ -356,7 +361,7 @@ class Node:
Track(
track_id=results.id,
ctx=ctx,
search_type=search_type,
search_type=f"{search_type}{results.artists[0].name} - {results.name}" if search_type else f"ytmsearch:{results.artists[0].name} - {results.name}",
spotify=True,
info={
"title": results.name or "Unknown",
@ -377,6 +382,28 @@ class Node:
except SpotifyException:
raise SpotifyTrackLoadFailed(f"Unable to find results for {query}")
elif discord_url := DISCORD_MP3_URL_REGEX.match(query):
async with self._session.get(
url=f"{self._rest_uri}/loadtracks?identifier={quote(query)}",
headers={"Authorization": self._password}
) as response:
data: dict = await response.json()
track: dict = data["tracks"][0]
info: dict = track.get('info')
return [Track(
track_id=track['track'],
info={
"title": discord_url.group('file'),
"author": "Unknown",
"length": info.get('length'),
"uri": info.get('uri'),
"position": info.get('position'),
"identifier": info.get('identifier')
},
ctx=ctx)]
else:
async with self._session.get(
url=f"{self._rest_uri}/loadtracks?identifier={quote(query)}",
@ -451,14 +478,16 @@ class NodePool:
@classmethod
async def create_node(
bot: Type[Union[discord.Client, commands.Bot, commands.AutoShardedBot]],
cls,
bot: Type[discord.Client],
host: str,
port: str,
password: str,
identifier: str,
spotify_client_id: Optional[str] = None,
spotify_client_secret: Optional[str] = None
spotify_client_id: Optional[str],
spotify_client_secret: Optional[str],
session: Optional[aiohttp.ClientSession] = None,
) -> Node:
"""Creates a Node object to be then added into the node pool.
For Spotify searching capabilites, pass in valid Spotify API credentials.
@ -467,9 +496,9 @@ class NodePool:
raise NodeCreationError(f"A node with identifier '{identifier}' already exists.")
node = Node(
bot=bot, pool=cls, host=host, port=port, password=password,
pool=cls, bot=bot, host=host, port=port, password=password,
identifier=identifier, spotify_client_id=spotify_client_id,
spotify_client_secret=spotify_client_secret
session=session, spotify_client_secret=spotify_client_secret
)
await node.connect()

View File

@ -6,7 +6,7 @@ with open("README.md") as f:
setuptools.setup(
name="pomice",
author="cloudwithax",
version="1.0.5",
version="1.0.5.3",
url="https://github.com/cloudwithax/pomice",
packages=setuptools.find_packages(),
license="GPL",