not-lain commited on
Commit
264b095
·
1 Parent(s): 3d78788

remove client

Browse files
Files changed (1) hide show
  1. app.py +13 -161
app.py CHANGED
@@ -1,7 +1,6 @@
1
  import asyncio
2
  import logging
3
  import os
4
- import time
5
  import threading
6
  from dataclasses import dataclass
7
  from enum import Enum
@@ -13,7 +12,6 @@ from discord.ext import commands
13
  from dotenv import load_dotenv
14
  import gradio as gr
15
  from huggingface_hub import hf_hub_download
16
- from gradio_client import Client
17
 
18
  # Configure logging
19
  logging.basicConfig(
@@ -24,8 +22,6 @@ logger = logging.getLogger(__name__)
24
 
25
  class LoopMode(str, Enum):
26
  NONE = "none"
27
- SINGLE = "single"
28
- QUEUE = "queue"
29
 
30
 
31
  @dataclass
@@ -33,9 +29,6 @@ class BotConfig:
33
  ASSETS_DIR: str = "assets"
34
  SONG_FILE: str = "lofi.mp3"
35
  HF_REPO: str = "not-lain/assets"
36
- HF_SPACE: str = "https://not-lain-ytdlp.hf.space/"
37
- MAX_RETRY_ATTEMPTS: int = 3
38
- MAX_CACHE_SIZE: int = 100 # Maximum number of songs to cache
39
 
40
  @property
41
  def song_path(self) -> str:
@@ -63,17 +56,6 @@ class MusicBot:
63
  self.last_context: Optional[commands.Context] = None
64
  self.loop_mode: LoopMode = LoopMode.NONE
65
  self.current_song: Optional[QueueItem] = None
66
- self.queue: list[QueueItem] = []
67
- self.hf_client = Client(config.HF_SPACE, hf_token=None)
68
- self.song_cache: dict[str, tuple[str, str]] = {} # url -> (title, file_path)
69
-
70
- def _manage_cache(self) -> None:
71
- """Remove oldest songs if cache exceeds maximum size"""
72
- if len(self.song_cache) > self.config.MAX_CACHE_SIZE:
73
- # Convert to list to get oldest entries (assuming insertion order is maintained)
74
- oldest_urls = list(self.song_cache.keys())[: -self.config.MAX_CACHE_SIZE]
75
- for url in oldest_urls:
76
- del self.song_cache[url]
77
 
78
  async def ensure_voice_state(self, ctx: commands.Context) -> None:
79
  """Validate voice state and raise appropriate errors"""
@@ -83,46 +65,17 @@ class MusicBot:
83
  if self.voice_client and ctx.author.voice.channel != self.voice_client.channel:
84
  raise VoiceStateError("You must be in the same voice channel as the bot!")
85
 
86
- async def download_song(self, queue_item: QueueItem) -> None:
87
- """Download song from URL and update queue item with file path, using cache when available"""
88
- try:
89
- # Check if song is in cache
90
- if queue_item.url in self.song_cache:
91
- title, file_path = self.song_cache[queue_item.url]
92
- queue_item.title = title
93
- queue_item.file_path = file_path
94
- logger.info(f"Found song in cache: {title}")
95
- return
96
-
97
- # Download if not in cache
98
- job = self.hf_client.submit(url=queue_item.url, api_name="/predict")
99
- while not job.done():
100
- time.sleep(0.1)
101
- title, file_path = job.outputs()[0]
102
-
103
- # Update cache
104
- self.song_cache[queue_item.url] = (title, file_path)
105
- self._manage_cache()
106
-
107
- queue_item.title = title
108
- queue_item.file_path = file_path
109
- logger.info(f"Downloaded and cached new song: {title}")
110
- except Exception as e:
111
- logger.error(f"Error downloading song: {e}")
112
- raise
113
-
114
  async def play_next(self, ctx: commands.Context) -> None:
115
  if self.is_playing:
116
  return
117
 
118
  try:
119
- if not self.current_song and self.queue:
120
- self.current_song = self.queue.pop(0)
121
- # Download song if it hasn't been downloaded yet
122
- if not self.current_song.file_path:
123
- await self.download_song(self.current_song)
124
- elif not self.current_song:
125
- return
126
 
127
  self.is_playing = True
128
  audio_source = discord.FFmpegPCMAudio(self.current_song.file_path)
@@ -143,9 +96,6 @@ class MusicBot:
143
  async def handle_song_end(self, ctx: commands.Context) -> None:
144
  if self.loop_mode == LoopMode.NONE:
145
  self.current_song = None
146
- elif self.loop_mode == LoopMode.QUEUE and self.current_song:
147
- self.queue.append(self.current_song)
148
- self.current_song = None
149
 
150
  if not self.is_playing:
151
  await self.play_next(ctx)
@@ -177,20 +127,12 @@ class MusicBot:
177
  self._reset_state()
178
  return False
179
 
180
- def add_to_queue(self, url: str) -> int:
181
- """Add song to queue and return position"""
182
- queue_item = QueueItem(url=url)
183
- self.queue.append(queue_item)
184
- return len(self.queue)
185
-
186
  def _reset_state(self) -> None:
187
  self.is_playing = False
188
  self.voice_client = None
189
  self.last_context = None
190
  self.loop_mode = LoopMode.NONE
191
  self.current_song = None
192
- self.queue.clear()
193
- # Note: We don't clear the cache when resetting state
194
 
195
 
196
  async def handle_voice_command(
@@ -241,10 +183,6 @@ async def on_ready():
241
  async def lofi(interaction: discord.Interaction):
242
  async def play_lofi(ctx, interaction: discord.Interaction):
243
  await music_bot.join_voice(ctx)
244
- # music_bot.loop_mode = LoopMode.SINGLE
245
- music_bot.current_song = QueueItem(
246
- url=config.song_path, title="Lofi Music", file_path=config.song_path
247
- )
248
  if not music_bot.is_playing:
249
  await music_bot.play_next(ctx)
250
  await interaction.followup.send("Playing lofi music! 🎵")
@@ -254,73 +192,18 @@ async def lofi(interaction: discord.Interaction):
254
  await handle_voice_command(interaction, play_lofi)
255
 
256
 
257
- @bot.tree.command(name="play", description="Play a youtube song")
258
- async def play(interaction: discord.Interaction, url: str):
259
- async def play_song(ctx, interaction: discord.Interaction):
260
- await music_bot.join_voice(ctx)
261
-
262
- if music_bot.is_playing or music_bot.queue:
263
- position = music_bot.add_to_queue(url)
264
- await interaction.followup.send(
265
- f"Added song to queue at position {position}! 🎵"
266
- )
267
- else:
268
- music_bot.add_to_queue(url)
269
- await music_bot.play_next(ctx)
270
- if music_bot.current_song and music_bot.current_song.title:
271
- await interaction.followup.send(
272
- f"Playing {music_bot.current_song.title}! 🎵"
273
- )
274
- else:
275
- await interaction.followup.send("Playing song! 🎵")
276
-
277
- await handle_voice_command(interaction, play_song)
278
-
279
-
280
- @bot.tree.command(name="skip", description="Skip the current song")
281
- async def skip(interaction: discord.Interaction):
282
- # Check if user is in a voice channel
283
  if not interaction.user.voice:
284
  await interaction.response.send_message(
285
  "You must be in a voice channel to use this command!"
286
  )
287
  return
288
 
289
- # Check if bot is in a voice channel
290
  if not music_bot.voice_client:
291
- await interaction.response.send_message("No song is currently playing!")
292
  return
293
 
294
- # Check if user is in the same channel as the bot
295
- if interaction.user.voice.channel != music_bot.voice_client.channel:
296
- await interaction.response.send_message(
297
- "You must be in the same voice channel as the bot!"
298
- )
299
- return
300
-
301
- if music_bot.voice_client and music_bot.is_playing:
302
- music_bot.is_playing = False # Reset playing state
303
- music_bot.voice_client.stop()
304
- await interaction.response.send_message("Skipped current song!")
305
- else:
306
- await interaction.response.send_message("No song is currently playing!")
307
-
308
-
309
- @bot.tree.command(name="leave", description="Disconnect bot from voice channel")
310
- async def leave(interaction: discord.Interaction):
311
- # Check if user is in a voice channel
312
- if not interaction.user.voice:
313
- await interaction.response.send_message(
314
- "You must be in a voice channel to use this command!"
315
- )
316
- return
317
-
318
- # Check if bot is in a voice channel
319
- if not music_bot.voice_client:
320
- await interaction.response.send_message("I'm not in any voice channel!")
321
- return
322
-
323
- # Check if user is in the same channel as the bot
324
  if interaction.user.voice.channel != music_bot.voice_client.channel:
325
  await interaction.response.send_message(
326
  "You must be in the same voice channel as the bot!"
@@ -333,45 +216,14 @@ async def leave(interaction: discord.Interaction):
333
  try:
334
  success = await music_bot.stop_playing(ctx)
335
  if success:
336
- await interaction.followup.send("Successfully disconnected! 👋")
337
  else:
338
  await interaction.followup.send(
339
- "Failed to disconnect properly. Please try again."
340
  )
341
  except Exception as e:
342
- print(f"Error during leave command: {e}")
343
- await interaction.followup.send("An error occurred while trying to disconnect.")
344
-
345
-
346
- @bot.tree.command(name="loop", description="Set loop mode")
347
- @app_commands.choices(
348
- mode=[app_commands.Choice(name=mode.value, value=mode.value) for mode in LoopMode]
349
- )
350
- async def loop(interaction: discord.Interaction, mode: str):
351
- try:
352
- music_bot.loop_mode = LoopMode(mode)
353
- await interaction.response.send_message(f"Loop mode set to: {mode}")
354
- except ValueError:
355
- await interaction.response.send_message("Invalid loop mode!")
356
-
357
-
358
- @bot.tree.command(name="queue", description="Show current queue")
359
- async def queue(interaction: discord.Interaction):
360
- if not music_bot.queue and not music_bot.current_song:
361
- await interaction.response.send_message("Queue is empty!")
362
- return
363
-
364
- queue_list = []
365
- if music_bot.current_song:
366
- status = "🎵 Now playing"
367
- title = music_bot.current_song.title or "Loading..."
368
- queue_list.append(f"{status}: {title}")
369
-
370
- for i, item in enumerate(music_bot.queue, 1):
371
- title = item.title or "Loading..."
372
- queue_list.append(f"{i}. {title}")
373
-
374
- await interaction.response.send_message("\n".join(queue_list))
375
 
376
 
377
  def initialize_assets() -> None:
 
1
  import asyncio
2
  import logging
3
  import os
 
4
  import threading
5
  from dataclasses import dataclass
6
  from enum import Enum
 
12
  from dotenv import load_dotenv
13
  import gradio as gr
14
  from huggingface_hub import hf_hub_download
 
15
 
16
  # Configure logging
17
  logging.basicConfig(
 
22
 
23
  class LoopMode(str, Enum):
24
  NONE = "none"
 
 
25
 
26
 
27
  @dataclass
 
29
  ASSETS_DIR: str = "assets"
30
  SONG_FILE: str = "lofi.mp3"
31
  HF_REPO: str = "not-lain/assets"
 
 
 
32
 
33
  @property
34
  def song_path(self) -> str:
 
56
  self.last_context: Optional[commands.Context] = None
57
  self.loop_mode: LoopMode = LoopMode.NONE
58
  self.current_song: Optional[QueueItem] = None
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  async def ensure_voice_state(self, ctx: commands.Context) -> None:
61
  """Validate voice state and raise appropriate errors"""
 
65
  if self.voice_client and ctx.author.voice.channel != self.voice_client.channel:
66
  raise VoiceStateError("You must be in the same voice channel as the bot!")
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  async def play_next(self, ctx: commands.Context) -> None:
69
  if self.is_playing:
70
  return
71
 
72
  try:
73
+ if not self.current_song:
74
+ self.current_song = QueueItem(
75
+ url=self.config.song_path,
76
+ title="Lofi Music",
77
+ file_path=self.config.song_path,
78
+ )
 
79
 
80
  self.is_playing = True
81
  audio_source = discord.FFmpegPCMAudio(self.current_song.file_path)
 
96
  async def handle_song_end(self, ctx: commands.Context) -> None:
97
  if self.loop_mode == LoopMode.NONE:
98
  self.current_song = None
 
 
 
99
 
100
  if not self.is_playing:
101
  await self.play_next(ctx)
 
127
  self._reset_state()
128
  return False
129
 
 
 
 
 
 
 
130
  def _reset_state(self) -> None:
131
  self.is_playing = False
132
  self.voice_client = None
133
  self.last_context = None
134
  self.loop_mode = LoopMode.NONE
135
  self.current_song = None
 
 
136
 
137
 
138
  async def handle_voice_command(
 
183
  async def lofi(interaction: discord.Interaction):
184
  async def play_lofi(ctx, interaction: discord.Interaction):
185
  await music_bot.join_voice(ctx)
 
 
 
 
186
  if not music_bot.is_playing:
187
  await music_bot.play_next(ctx)
188
  await interaction.followup.send("Playing lofi music! 🎵")
 
192
  await handle_voice_command(interaction, play_lofi)
193
 
194
 
195
+ @bot.tree.command(name="stop", description="Stop the lofi music")
196
+ async def stop(interaction: discord.Interaction):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  if not interaction.user.voice:
198
  await interaction.response.send_message(
199
  "You must be in a voice channel to use this command!"
200
  )
201
  return
202
 
 
203
  if not music_bot.voice_client:
204
+ await interaction.response.send_message("No music is currently playing!")
205
  return
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  if interaction.user.voice.channel != music_bot.voice_client.channel:
208
  await interaction.response.send_message(
209
  "You must be in the same voice channel as the bot!"
 
216
  try:
217
  success = await music_bot.stop_playing(ctx)
218
  if success:
219
+ await interaction.followup.send("Music stopped and bot disconnected! 👋")
220
  else:
221
  await interaction.followup.send(
222
+ "Failed to stop properly. Please try again."
223
  )
224
  except Exception as e:
225
+ print(f"Error during stop command: {e}")
226
+ await interaction.followup.send("An error occurred while trying to stop.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
 
229
  def initialize_assets() -> None: