Update for DRBv3

This commit is contained in:
Logan Cusano
2024-04-03 23:25:31 -04:00
parent 51027d794d
commit e84adaa9c4
3 changed files with 203 additions and 289 deletions

View File

@@ -3,6 +3,7 @@ from NoiseGatev2 import AudioStream
print('Getting a list of devices') print('Getting a list of devices')
list_of_devices = AudioStream().list_devices() list_of_devices = AudioStream().list_devices()
print("----- INPUT DEVICES -----") print("----- INPUT DEVICES -----")
print("----- *You will likely want to pick from one of these devices* -----")
for inputDevice in list_of_devices['Input']: for inputDevice in list_of_devices['Input']:
print(f"{inputDevice}\t-\t{list_of_devices['Input'][inputDevice]}") print(f"{inputDevice}\t-\t{list_of_devices['Input'][inputDevice]}")

458
main.py
View File

@@ -1,301 +1,213 @@
import argparse, platform, os # Python client file (client.py)
from discord import Intents, Client, Member, opus import argparse
import logging
import os
import platform
import socketio
import asyncio
from discord import Intents, opus
from discord.ext import commands from discord.ext import commands
from NoiseGatev2 import NoiseGate from NoiseGatev2 import NoiseGate
# Load the proper OPUS library for the device being used logging.basicConfig(level=logging.INFO)
async def load_opus(): logger = logging.getLogger(__name__)
# Check the system type and load the correct library
# Linux ARM AARCH64 running 32bit OS sio = socketio.AsyncClient()
client = None
device_id = None
ng_threshold = None
### Core functions
def load_opus():
processor = platform.machine() processor = platform.machine()
print("Processor: ", processor) logger.info(f"Processor: {processor}")
if os.name == 'nt': if os.name == 'nt':
if processor == "AMD64": opus_path = './opus/libopus_amd64.dll' if processor == "AMD64" else None
print(f"Loaded OPUS library for AMD64")
opus.load_opus('./opus/libopus_amd64.dll')
return "AMD64"
else: else:
if processor == "aarch64": opus_path = './opus/libopus_aarcch64.so' if processor == "aarch64" else './opus/libopus_armv7l.so'
print(f"Loaded OPUS library for aarch64")
opus.load_opus('./opus/libopus_aarcch64.so') if opus_path:
return "aarch64" opus.load_opus(opus_path)
elif processor == "armv7l": logger.info(f"Loaded OPUS library from {opus_path}")
print(f"Loaded OPUS library for armv7l") return True
opus.load_opus('./opus/libopus_armv7l.so') else:
return "armv7l" logger.error("Unsupported architecture or OS.")
return False
def main(clientId='OTQzNzQyMDQwMjU1MTE1MzA0.Yg3eRA.ZxEbRr55xahjfaUmPY8pmS-RHTY', channelId=367396189529833476, NGThreshold=50, deviceId=1): async def join_voice_channel(channel_id):
intents = Intents.default() global device_id, ng_threshold
channel = client.get_channel(int(channel_id))
client = commands.Bot(command_prefix='!', intents=intents) logger.info(f"Joining voice channel {channel}")
voice_connection = await channel.connect(timeout=60.0, reconnect=True)
@client.event
async def on_ready():
print(f'We have logged in as {client.user}')
channelIdToJoin = client.get_channel(channelId)
print("Channel", channelIdToJoin)
print("Loading opus")
await load_opus()
if opus.is_loaded(): if opus.is_loaded():
print("Joining voice") logger.info("OPUS library loaded successfully")
channelConnection = await channelIdToJoin.connect(timeout=60.0, reconnect=True) stream_handler = NoiseGate(
print("Voice Connected") _input_device_index=device_id,
streamHandler = NoiseGate( _voice_connection=voice_connection,
_input_device_index=deviceId, _noise_gate_threshold=ng_threshold
_voice_connection=channelConnection, )
_noise_gate_threshold=NGThreshold) stream_handler.run()
# Start the audio stream logger.info("Audio stream started")
streamHandler.run() return True
print("stream running") else:
logger.error("Failed to load OPUS library")
return False
client.run(clientId) async def leave_voice_channel(guild_id):
guild = await client.fetch_guild(guild_id)
logger.info(f"Leaving voice channel in guild {guild}")
voice_client = guild.voice_client
if voice_client:
await voice_client.disconnect()
logger.info("Disconnected from voice channel")
else:
logger.info("Not connected to any voice channel in the guild")
parser = argparse.ArgumentParser() # Check if the client needs to open
parser.add_argument("deviceId", type=int, help="The ID of the audio device to use") if len(check_for_open_vc_connections()) <= 0:
parser.add_argument("channelId", type=int, help="The ID of the voice channel to use") # Tell the server the client is going to close
parser.add_argument("clientId", type=str, help="The discord client ID") return False
parser.add_argument("-n", "--NGThreshold", type=int, help="Change the noisegate threshold. This defaults to 50")
args = parser.parse_args()
if (not args.NGThreshold): return True
args.NGThreshold = 50
print("Arguments:", args)
main(
clientId=args.clientId,
channelId=args.channelId,
NGThreshold=args.NGThreshold,
deviceId=args.deviceId
)
def check_for_open_vc_connections():
return client.voice_clients
def check_if_discord_vc_connected(guild_id):
if client:
return any(int(vc.guild.id) == int(guild_id) for vc in client.voice_clients)
return False
async def get_discord_username(guild_id):
try:
guild = await client.fetch_guild(guild_id)
member = await guild.fetch_member(get_discord_id())
if member.nick:
print(f"Username: {member.nick}")
return member.nick
print(f"Username: {client.user.name if client.user else None}")
return client.user.name if client.user else None
except Exception as e:
logging.warning(e)
return None
def check_if_client_is_open():
if client:
return client.is_ready()
return False
def get_discord_id():
print(f"ID: {client.user.id if client.user else None}")
return int(client.user.id) if client.user else None
async def on_connect():
logger.info("Connected to WebSocket server")
#import asyncio async def on_disconnect():
#import functools logger.info("Disconnected from WebSocket server")
#import itertools
#import math
#import random ### Socket Events
# @sio.event
#import discord async def connect_error():
#from async_timeout import timeout logger.error("Connection to WebSocket server failed")
#from discord.ext import commands
#
# @sio.event
#class VoiceError(Exception): async def join_server(data):
# pass logger.info(f"Received command to join server: {data['channelId']}")
# return await join_voice_channel(data['channelId'])
#
#class VoiceState:
# def __init__(self, bot: commands.Bot, ctx: commands.Context): @sio.event
# self.bot = bot async def leave_server(data):
# self._ctx = ctx logger.info(f"Received command to leave server: {data['guild_id']}")
# return await leave_voice_channel(data['guild_id'])
# self.current = None
# self.voice = None
# self.next = asyncio.Event() @sio.event
# self.songs = SongQueue() async def check_discord_vc_connected(data):
# return check_if_discord_vc_connected(data['guild_id'])
# self._loop = False
# self._volume = 0.5
# self.skip_votes = set() @sio.event
# async def request_discord_username(data):
# self.audio_player = bot.loop.create_task(self.audio_player_task()) return await get_discord_username(data['guild_id'])
#
# def __del__(self):
# self.audio_player.cancel() @sio.event
# async def check_client_is_open():
# @property return check_if_client_is_open()
# def loop(self):
# return self._loop
# @sio.event
# @loop.setter async def request_discord_id():
# def loop(self, value: bool): return get_discord_id()
# self._loop = value
#
# @property async def on_ready():
# def volume(self): logger.info(f"We have logged in as {client.user}")
# return self._volume logger.info("Loading OPUS library")
# if not load_opus():
# @volume.setter return
# def volume(self, value: float):
# self._volume = value # Send update to socket server
# try:
# @property logger.info('Emitting to the server')
# def is_playing(self): await sio.emit('discord_ready', {'message': 'Discord bot is ready'})
# return self.voice and self.current except Exception as e:
# logger.error(f"Error emitting to the server: {e}")
# async def audio_player_task(self): logger.info('Server not ready yet')
# while True:
# self.next.clear()
# async def main(args):
# if not self.loop: global client, device_id, ng_threshold
# # Try to get the next song within 3 minutes.
# # If no song will be added to the queue in time, # Connect to the WebSocket server
# # the player will disconnect due to performance await sio.connect('http://127.0.0.1:{}'.format(args.websocket_port), namespaces=['/'])
# # reasons. logger.info("Connecting to WebSocket server...")
# try:
# async with timeout(180): # 3 minutes intents = Intents.default()
# self.current = await self.songs.get() client = commands.Bot(command_prefix='!', intents=intents)
# except asyncio.TimeoutError:
# self.bot.loop.create_task(self.stop()) device_id = args.device_id
# return ng_threshold = args.ng_threshold
#
# self.current.source.volume = self._volume client.add_listener(on_connect)
# self.voice.play(self.current.source, after=self.play_next_song) client.add_listener(on_disconnect)
# await self.current.source.channel.send(embed=self.current.create_embed()) client.add_listener(on_ready)
#
# await self.next.wait() await client.start(args.client_id)
#
# def play_next_song(self, error=None):
# if error: def parse_arguments():
# raise VoiceError(str(error)) parser = argparse.ArgumentParser()
# parser.add_argument("device_id", type=int, help="The ID of the audio device to use")
# self.next.set() parser.add_argument("client_id", type=str, help="The Discord client ID")
# parser.add_argument("websocket_port", type=int, help="The port of the WebSocket server")
# def skip(self): parser.add_argument("-n", "--ng_threshold", type=int, default=50,
# self.skip_votes.clear() help="Change the noise gate threshold. Defaults to 50")
# return parser.parse_args()
# if self.is_playing:
# self.voice.stop()
# if __name__ == "__main__":
# async def stop(self): args = parse_arguments()
# self.songs.clear() logger.info("Arguments: %s", args)
# asyncio.run(main(args))
# if self.voice:
# await self.voice.disconnect()
# self.voice = None
#
#
#class Music(commands.Cog):
# def __init__(self, bot: commands.Bot):
# self.bot = bot
# self.voice_states = {}
#
# def get_voice_state(self, ctx: commands.Context):
# state = self.voice_states.get(ctx.guild.id)
# if not state:
# state = VoiceState(self.bot, ctx)
# self.voice_states[ctx.guild.id] = state
#
# return state
#
# def cog_unload(self):
# for state in self.voice_states.values():
# self.bot.loop.create_task(state.stop())
#
# def cog_check(self, ctx: commands.Context):
# if not ctx.guild:
# raise commands.NoPrivateMessage('This command can\'t be used in DM channels.')
#
# return True
#
# async def cog_before_invoke(self, ctx: commands.Context):
# ctx.voice_state = self.get_voice_state(ctx)
#
# async def cog_command_error(self, ctx: commands.Context, error: commands.CommandError):
# await ctx.send('An error occurred: {}'.format(str(error)))
#
# @commands.command(name='join', invoke_without_subcommand=True)
# async def _join(self, ctx: commands.Context):
# """Joins a voice channel."""
#
# destination = ctx.author.voice.channel
# if ctx.voice_state.voice:
# await ctx.voice_state.voice.move_to(destination)
# return
#
# ctx.voice_state.voice = await destination.connect()
#
# @commands.command(name='summon')
# @commands.has_permissions(manage_guild=True)
# async def _summon(self, ctx: commands.Context, *, channel: discord.VoiceChannel = None):
# """Summons the bot to a voice channel.
#
# If no channel was specified, it joins your channel.
# """
#
# if not channel and not ctx.author.voice:
# raise VoiceError('You are neither connected to a voice channel nor specified a channel to join.')
#
# destination = channel or ctx.author.voice.channel
# if ctx.voice_state.voice:
# await ctx.voice_state.voice.move_to(destination)
# return
#
# ctx.voice_state.voice = await destination.connect()
#
# @commands.command(name='leave', aliases=['disconnect'])
# @commands.has_permissions(manage_guild=True)
# async def _leave(self, ctx: commands.Context):
# """Clears the queue and leaves the voice channel."""
#
# if not ctx.voice_state.voice:
# return await ctx.send('Not connected to any voice channel.')
#
# await ctx.voice_state.stop()
# del self.voice_states[ctx.guild.id]
#
# @commands.command(name='play')
# async def _play(self, ctx: commands.Context, *, search: str):
# """Plays a song.
#
# If there are songs in the queue, this will be queued until the
# other songs finished playing.
#
# This command automatically searches from various sites if no URL is provided.
# A list of these sites can be found here: https://rg3.github.io/youtube-dl/supportedsites.html
# """
#
# if not ctx.voice_state.voice:
# await ctx.invoke(self._join)
#
# async with ctx.typing():
# try:
# source = await YTDLSource.create_source(ctx, search, loop=self.bot.loop)
# except YTDLError as e:
# await ctx.send('An error occurred while processing this request: {}'.format(str(e)))
# else:
# song = Song(source)
#
# await ctx.voice_state.songs.put(song)
# await ctx.send('Enqueued {}'.format(str(source)))
#
# @_join.before_invoke
# @_play.before_invoke
# async def ensure_voice_state(self, ctx: commands.Context):
# if not ctx.author.voice or not ctx.author.voice.channel:
# raise commands.CommandError('You are not connected to any voice channel.')
#
# if ctx.voice_client:
# if ctx.voice_client.channel != ctx.author.voice.channel:
# raise commands.CommandError('Bot is already in a voice channel.')
#
#intents = discord.Intents.default()
#intents.message_content = True
#
#bot = commands.Bot('music.', description="Brent's Revenge", intents=intents)
#bot.add_cog(Music(bot))
#
#
#@bot.event
#async def on_ready():
# print('Logged in as:\n{0.user.name}\n{0.user.id}'.format(bot))
#
#bot.run('OTQzNzQyMDQwMjU1MTE1MzA0.Yg3eRA.ZxEbRr55xahjfaUmPY8pmS-RHTY')

View File

@@ -1,5 +1,6 @@
discord^=2.2.3 discord==2.3.2
PyNaCl^=1.5.0 PyNaCl==1.5.0
pyaudio^=0.2.13 pyaudio==0.2.14
numpy^=1.24.3 numpy==1.26.4
argparse argparse
python-socketio[client]