Skip to content

Commit 021ef4e

Browse files
committed
Fixed too many things to count
1 parent 73995ba commit 021ef4e

File tree

6 files changed

+78
-54
lines changed

6 files changed

+78
-54
lines changed

core/events.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ async def track_start(self, event: TrackStartEvent):
114114

115115
async def track_end(self, event: TrackEndEvent):
116116
event.player.reset()
117+
await event.player.stop()
117118

118119
async def track_exception(self, event: TrackExceptionEvent):
119120
pass

core/lavalink.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import asyncio
2+
import logging
23
from enum import Enum
34

4-
import logging
55
from discord import InvalidArgument
66
from discord.ext.commands import BotMissingPermissions
77

88
from .exceptions import IllegalAction
9-
from .node import Node
10-
from .player import Player, AudioTrack
119
from .load_balancing import LoadBalancer
10+
from .node import Node
11+
from .player import Player, AudioTrackPlaylist
1212

1313
logger = logging.getLogger("magma")
1414

@@ -35,7 +35,7 @@ def __init__(self, user_id, shard_count):
3535

3636
@property
3737
def playing_guilds(self):
38-
return {name: node.stats.playing_players for name, node in self.nodes.items()}
38+
return {name: node.stats.playing_players for name, node in self.nodes.items() if node.stats}
3939

4040
@property
4141
def total_playing_guilds(self):
@@ -60,10 +60,11 @@ def get_link(self, guild_id: int, bot=None):
6060
:return: A Link
6161
"""
6262
guild_id = int(guild_id)
63-
if guild_id not in self.links:
64-
if not bot:
65-
raise IllegalAction("A bot instance was not passed when trying to acquire a Link!")
66-
self.links[guild_id] = Link(self, guild_id, bot)
63+
64+
if guild_id in self.links or not bot:
65+
return self.links.get(guild_id)
66+
67+
self.links[guild_id] = Link(self, guild_id, bot)
6768
return self.links[guild_id]
6869

6970
async def add_node(self, name, uri, rest_uri, password):
@@ -157,8 +158,8 @@ async def get_tracks(self, query):
157158
:return:
158159
"""
159160
node = await self.get_node(True)
160-
tracks = await node.get_tracks(query)
161-
return [AudioTrack(track) for track in tracks]
161+
results = await node.get_tracks(query)
162+
return AudioTrackPlaylist(results)
162163

163164
async def get_tracks_yt(self, query):
164165
return await self.get_tracks("ytsearch:" + query)
@@ -173,7 +174,7 @@ async def get_node(self, select_if_absent=False):
173174
:param select_if_absent: A boolean that indicates if a Node should be created if there is none
174175
:return: A Node
175176
"""
176-
if select_if_absent and not self.node:
177+
if select_if_absent and not (self.node and self.node.available):
177178
await self.change_node(await self.lavalink.get_best_node())
178179
return self.node
179180

@@ -188,8 +189,8 @@ async def change_node(self, node):
188189
self.node.links[self.guild_id] = self
189190
if self.last_voice_update:
190191
await node.send(self.last_voice_update)
191-
if self.player:
192-
await self.player.node_changed()
192+
if self._player:
193+
await self._player.node_changed()
193194

194195
async def connect(self, channel):
195196
"""
@@ -206,7 +207,7 @@ async def connect(self, channel):
206207

207208
me = channel.guild.me
208209
permissions = me.permissions_in(channel)
209-
if not permissions.connect and not permissions.move_members:
210+
if (not permissions.connect or len(channel.members) >= channel.user_limit) and not permissions.move_members:
210211
raise BotMissingPermissions(["connect"])
211212

212213
self.set_state(State.CONNECTING)

core/load_balancing.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,15 @@ def __init__(self, node, lavalink):
6666
async def get_total(self):
6767
# hard maths
6868
stats = self.node.stats
69-
if not stats:
70-
return
69+
if not self.node.available or not stats:
70+
return big_number
7171

72-
if self.lavalink:
73-
# REEEEE complexity levels
74-
for link in self.lavalink.links.values():
75-
if self.node == await link.get_node() and link.player.current and not link.player.paused:
76-
self.player_penalty += 1
77-
else:
78-
self.player_penalty = stats.playing_players
72+
self.player_penalty = stats.playing_players
7973

8074
self.cpu_penalty = 1.05 ** (100 * stats.system_load) * 10 - 10
8175
if stats.avg_frame_deficit != -1:
8276
self.deficit_frame_penalty = (1.03 ** (500 * (stats.avg_frame_deficit / 3000))) * 600 - 600
8377
self.null_frame_penalty = (1.03 ** (500 * (stats.avg_frame_nulled / 3000))) * 300 - 300
8478
self.null_frame_penalty *= 2
8579

86-
if not self.node.available or not self.node.stats:
87-
return big_number
8880
return self.player_penalty + self.cpu_penalty + self.deficit_frame_penalty + self.null_frame_penalty

core/node.py

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
import aiohttp
77
import logging
88
import websockets
9+
from discord.backoff import ExponentialBackoff
910

1011
from .events import TrackEndEvent, TrackStuckEvent, TrackExceptionEvent
1112
from .exceptions import NodeException
1213

1314
logger = logging.getLogger("magma")
14-
timeout = 5
15-
tries = 5
1615

1716

1817
class NodeStats:
@@ -49,6 +48,7 @@ def __init__(self, msg):
4948
class KeepAlive(threading.Thread):
5049
def __init__(self, node, interval, *args, **kwargs):
5150
super().__init__(*args, **kwargs)
51+
self.name = f"{node.name}-KeepAlive"
5252
self.daemon = True
5353
self.node = node
5454
self.ws = node.ws
@@ -68,13 +68,9 @@ def run(self):
6868
asyncio.run_coroutine_threadsafe(self.node.on_close(e.code, e.reason), loop=self.loop)
6969
return
7070

71-
try:
72-
logger.info(f"Attempting to reconnect `{self.node.name}`")
73-
future = asyncio.run_coroutine_threadsafe(self.node.connect(), loop=self.loop)
74-
future.result()
75-
except NodeException:
76-
future = asyncio.run_coroutine_threadsafe(self.node.on_close(e.code, e.reason), loop=self.loop)
77-
future.result()
71+
logger.info(f"Attempting to reconnect `{self.node.name}`")
72+
future = asyncio.run_coroutine_threadsafe(self.node.connect(), loop=self.loop)
73+
future.result()
7874

7975
def stop(self):
8076
self._stop_ev.set()
@@ -94,19 +90,18 @@ def __init__(self, lavalink, name, uri, rest_uri, headers):
9490
self.available = False
9591
self.closing = False
9692

97-
async def _connect(self, try_=0):
98-
try:
99-
self.ws = await websockets.connect(self.uri, extra_headers=self.headers)
100-
self.keep_alive = KeepAlive(self, 4)
101-
self.keep_alive.start()
102-
asyncio.ensure_future(self.listen())
103-
except OSError:
104-
if try_ < tries:
105-
logger.error(f"Connection refused, trying again in {timeout}s, try: {try_+1}/{tries}")
106-
await asyncio.sleep(timeout)
107-
await self._connect(try_+1)
108-
else:
109-
raise NodeException(f"Connection failed after {tries} tries")
93+
async def _connect(self):
94+
backoff = ExponentialBackoff(2)
95+
while not (self.ws and self.ws.open):
96+
try:
97+
self.ws = await websockets.connect(self.uri, extra_headers=self.headers)
98+
asyncio.ensure_future(self.listen())
99+
self.keep_alive = KeepAlive(self, 3)
100+
self.keep_alive.start()
101+
except OSError:
102+
delay = backoff.delay()
103+
logger.error(f"Connection refused, trying again in {delay:.2f}s")
104+
await asyncio.sleep(delay)
110105

111106
async def connect(self):
112107
await self._connect()
@@ -153,8 +148,8 @@ async def listen(self):
153148
pass # ping() handles this for us, no need to hear it twice..
154149

155150
async def on_open(self):
156-
await self.lavalink.load_balancer.on_node_connect(self)
157151
self.available = True
152+
await self.lavalink.load_balancer.on_node_connect(self)
158153

159154
async def on_close(self, code, reason):
160155
self.closing = False
@@ -177,7 +172,8 @@ async def on_message(self, msg):
177172
op = msg.get("op")
178173
if op == "playerUpdate":
179174
link = self.lavalink.get_link(msg.get("guildId"))
180-
await link.player.provide_state(msg.get("state"))
175+
if link:
176+
await link.player.provide_state(msg.get("state"))
181177
elif op == "stats":
182178
self.stats = NodeStats(msg)
183179
elif op == "event":

core/player.py

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1+
import traceback
2+
from enum import Enum
13
from time import time
24

35
from .exceptions import IllegalAction
46
from .events import InternalEventAdapter, TrackPauseEvent, TrackResumeEvent, TrackStartEvent
57

68

9+
class LoadTypes(Enum):
10+
NO_MATCHES = -2
11+
LOAD_FAILED = -1
12+
UNKNOWN = 0
13+
TRACK_LOADED = 1
14+
PLAYLIST_LOADED = 2
15+
SEARCH_RESULT = 3
16+
17+
718
class AudioTrack:
819
"""
920
The base AudioTrack class that is used by the player to play songs
@@ -20,6 +31,25 @@ def __init__(self, track):
2031
self.user_data = None
2132

2233

34+
class AudioTrackPlaylist:
35+
def __init__(self, results):
36+
self.playlist_info = results["playlistInfo"]
37+
self.playlist_name = self.playlist_info.get("name")
38+
self.selected_track = self.playlist_info.get("selectedTrack")
39+
self.load_type = LoadTypes[results["loadType"]]
40+
self.tracks = [AudioTrack(track) for track in results["tracks"]]
41+
42+
def __iter__(self):
43+
for track in self.tracks:
44+
yield track
45+
46+
def __len__(self):
47+
return self.tracks.__len__()
48+
49+
def __getitem__(self, item):
50+
return self.tracks[item]
51+
52+
2353
class Player:
2454
internal_event_adapter = InternalEventAdapter()
2555

@@ -161,10 +191,12 @@ async def destroy(self):
161191
"guildId": str(self.link.guild_id),
162192
}
163193
node = await self.link.get_node()
164-
if node.available:
194+
if node and node.available:
165195
await node.send(payload)
166-
await self.event_adapter.destroy()
167-
self.event_adapter = None
196+
197+
if self.event_adapter:
198+
await self.event_adapter.destroy()
199+
self.event_adapter = None
168200

169201
async def node_changed(self):
170202
if self.current:
@@ -173,4 +205,7 @@ async def node_changed(self):
173205
async def trigger_event(self, event):
174206
await Player.internal_event_adapter.on_event(event)
175207
if self.event_adapter: # If we defined our on adapter
176-
await self.event_adapter.on_event(event)
208+
try:
209+
await self.event_adapter.on_event(event)
210+
except:
211+
traceback.print_exc()

requirements.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
git+https://github.com/Rapptz/discord.py@rewrite#egg=discord.py[voice]
2-
aiohttp==2.2.5

0 commit comments

Comments
 (0)