Added download mode and !volume

Added download mode since streaming is buggy. This is now the default
mode and can be turned on and off with !downloadmode
Added !volume [0-1]
This commit is contained in:
Twentysix 2016-01-05 16:51:37 +01:00
parent 0ac2a02968
commit 47e9c657b2
2 changed files with 129 additions and 24 deletions

View File

@ -2,7 +2,8 @@ import json
import logging import logging
default_settings = ('{"TRIVIA_ADMIN_ONLY": false, "EDIT_CC_ADMIN_ONLY": false, "PASSWORD": "PASSWORDHERE", "FILTER": true, "CUSTOMCOMMANDS": true, ' + default_settings = ('{"TRIVIA_ADMIN_ONLY": false, "EDIT_CC_ADMIN_ONLY": false, "PASSWORD": "PASSWORDHERE", "FILTER": true, "CUSTOMCOMMANDS": true, ' +
'"TRIVIAMAXSCORE": 10, "TRIVIADELAY": 15, "LOGGING": true, "EMAIL": "EMAILHERE", "ADMINROLE": "Transistor"}') '"TRIVIAMAXSCORE": 10, "TRIVIADELAY": 15, "LOGGING": true, "EMAIL": "EMAILHERE", "ADMINROLE": "Transistor", "DOWNLOADMODE" : true, ' +
'"VOLUME": 0.10}')
logger = logging.getLogger("__main__") logger = logging.getLogger("__main__")

150
red.py
View File

@ -34,6 +34,7 @@ help = """**Commands list:**
!choose option1 or option2 or option3 (...) - Random choice !choose option1 or option2 or option3 (...) - Random choice
!8 [question] - Ask 8 ball !8 [question] - Ask 8 ball
!sw - Start/stop the stopwatch !sw - Start/stop the stopwatch
!avatar [name or mention] - Shows user's avatar
!trivia start - Start a trivia session !trivia start - Start a trivia session
!trivia stop - Stop a trivia session !trivia stop - Stop a trivia session
!twitch [stream] - Check if stream is online !twitch [stream] - Check if stream is online
@ -56,7 +57,8 @@ youtube_dl_options = {
'nocheckcertificate': True, 'nocheckcertificate': True,
'ignoreerrors': True, 'ignoreerrors': True,
'quiet': True, 'quiet': True,
'no_warnings': True} 'no_warnings': True,
'outtmpl': "cache/%(id)s"}
audio_help = """ audio_help = """
**General audio help commands:** **General audio help commands:**
@ -69,6 +71,8 @@ audio_help = """
!youtube [link] - Play a youtube video in a voice channel !youtube [link] - Play a youtube video in a voice channel
!sing - Make Red sing !sing - Make Red sing
!stop - Stop any voice channel activity !stop - Stop any voice channel activity
!volume [0-1] - Sets the volume
!downloadmode - Disables/enables download mode (admin only)
**Playlist commands:** **Playlist commands:**
!play [playlist_name] - Play chosen playlist !play [playlist_name] - Play chosen playlist
@ -203,6 +207,10 @@ async def on_message(message):
await playFavorites(message) await playFavorites(message)
elif message.content == "!getplaylist": elif message.content == "!getplaylist":
await sendPlaylist(message) await sendPlaylist(message)
elif message.content.startswith("!volume"):
await setVolume(message)
elif message.content == "!downloadmode":
await downloadMode(message)
################################################ ################################################
elif message.content == "!trivia start": elif message.content == "!trivia start":
if checkAuth("Trivia", message, settings): if checkAuth("Trivia", message, settings):
@ -376,20 +384,25 @@ class botPlays():
await client.change_status(discord.Game(name=choice(self.games))) await client.change_status(discord.Game(name=choice(self.games)))
class Playlist(): class Playlist():
def __init__(self, filename=None, singleSong=False): #a playlist with a single song is just there to make !addfavorite work with !youtube command def __init__(self, filename=None): #a playlist with a single song is just there to make !addfavorite work with !youtube command
self.filename = filename self.filename = filename
self.current = 0 self.current = 0
self.stop = False self.stop = False
self.lastAction = 999 self.lastAction = 999
if not singleSong: self.currentTitle = ""
if filename["type"] == "playlist": self.type = filename["type"]
self.playlist = dataIO.fileIO("playlists/" + filename["filename"] + ".txt", "load")["playlist"] if filename["type"] == "playlist":
elif filename["type"] == "favorites": self.playlist = dataIO.fileIO("playlists/" + filename["filename"] + ".txt", "load")["playlist"]
self.playlist = dataIO.fileIO("favorites/" + filename["filename"] + ".txt", "load") elif filename["type"] == "favorites":
elif filename["type"] == "local": self.playlist = dataIO.fileIO("favorites/" + filename["filename"] + ".txt", "load")
self.playlist = filename["filename"] elif filename["type"] == "local":
else: self.playlist = filename["filename"]
raise("Invalid playlist call.") elif filename["type"] == "singleSong":
self.playlist = [filename["filename"]]
self.playSingleSong(self.playlist[0])
else:
raise("Invalid playlist call.")
if filename["type"] != "singleSong":
self.nextSong(0) self.nextSong(0)
def nextSong(self, nextTrack, lastError=False): def nextSong(self, nextTrack, lastError=False):
@ -399,10 +412,22 @@ class Playlist():
self.lastAction = int(time.perf_counter()) self.lastAction = int(time.perf_counter())
try: try:
if isPlaylistValid([self.playlist[nextTrack]]): #Checks if it's a valid youtube link if isPlaylistValid([self.playlist[nextTrack]]): #Checks if it's a valid youtube link
musicPlayer = client.voice.create_ytdl_player(self.playlist[nextTrack], options=youtube_dl_options) if settings["DOWNLOADMODE"]:
musicPlayer.start() path = self.getVideo(self.playlist[nextTrack])
try:
logger.info("Starting track...")
musicPlayer = client.voice.create_ffmpeg_player("cache/" + path, options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start()
except:
logger.warning("Something went wrong with track " + self.playlist[self.current])
if not lastError: #prevents error loop
self.lastAction = 999
self.nextSong(self.getNextSong(), lastError=True)
else: #Stream mode. Buggy.
musicPlayer = client.voice.create_ytdl_player(self.playlist[nextTrack], options=youtube_dl_options)
musicPlayer.start()
else: # must be a local playlist then else: # must be a local playlist then
musicPlayer = client.voice.create_ffmpeg_player(self.playlist[nextTrack]) musicPlayer = client.voice.create_ffmpeg_player(self.playlist[nextTrack], options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start() musicPlayer.start()
except Exception as e: except Exception as e:
logger.warning("Something went wrong with track " + self.playlist[self.current]) logger.warning("Something went wrong with track " + self.playlist[self.current])
@ -410,6 +435,36 @@ class Playlist():
self.lastAction = 999 self.lastAction = 999
self.nextSong(self.getNextSong(), lastError=True) self.nextSong(self.getNextSong(), lastError=True)
def getVideo(self, url):
try:
yt = youtube_dl.YoutubeDL(youtube_dl_options)
v = yt.extract_info(url, download=False)
if not os.path.isfile("cache/" + v["id"]):
logger.info("Track not in cache, downloading...")
v = yt.extract_info(url, download=True)
self.currentTitle = v["title"]
return v["id"]
except Exception as e:
print(e)
return False
def playSingleSong(self, url):
global musicPlayer
if settings["DOWNLOADMODE"]:
v = self.getVideo(url)
if musicPlayer:
if musicPlayer.is_playing():
musicPlayer.stop()
if v:
musicPlayer = client.voice.create_ffmpeg_player("cache/" + v, options='''-filter:a "volume={}"'''.format(settings["VOLUME"]))
musicPlayer.start()
else:
if musicPlayer:
if musicPlayer.is_playing():
musicPlayer.stop()
musicPlayer = client.voice.create_ytdl_player(self.playlist[0], options=youtube_dl_options)
musicPlayer.start()
async def songSwitcher(self): async def songSwitcher(self):
while not self.stop: while not self.stop:
if musicPlayer.is_done() and not self.stop: if musicPlayer.is_done() and not self.stop:
@ -759,6 +814,7 @@ async def checkVoice(message):
async def playVideo(message): async def playVideo(message):
global musicPlayer, currentPlaylist global musicPlayer, currentPlaylist
toDelete = None
if await checkVoice(message): if await checkVoice(message):
pattern = "(?:youtube\.com\/watch\?v=)(.*)|(?:youtu.be/)(.*)" pattern = "(?:youtube\.com\/watch\?v=)(.*)|(?:youtu.be/)(.*)"
rr = re.search(pattern, message.content, re.I | re.U) rr = re.search(pattern, message.content, re.I | re.U)
@ -773,15 +829,21 @@ async def playVideo(message):
if canDeleteMessages(message): if canDeleteMessages(message):
await client.send_message(message.channel, "`Playing youtube video {} requested by {}`".format(id, message.author.name)) await client.send_message(message.channel, "`Playing youtube video {} requested by {}`".format(id, message.author.name))
await client.delete_message(message) await client.delete_message(message)
currentPlaylist = Playlist(singleSong=True) if settings["DOWNLOADMODE"]:
currentPlaylist.playlist = ['https://www.youtube.com/watch?v=' + id] toDelete = await client.send_message(message.channel, "`I'm in download mode. It might take a bit for me to start. I'll delete this message as soon as I'm ready.`".format(id, message.author.name))
musicPlayer = client.voice.create_ytdl_player('https://www.youtube.com/watch?v=' + id, options=youtube_dl_options) data = {"filename" : 'https://www.youtube.com/watch?v=' + id, "type" : "singleSong"}
musicPlayer.start() currentPlaylist = Playlist(data)
if toDelete:
await client.delete_message(toDelete)
# currentPlaylist.playlist = ['https://www.youtube.com/watch?v=' + id]
# musicPlayer = client.voice.create_ytdl_player('https://www.youtube.com/watch?v=' + id, options=youtube_dl_options)
# musicPlayer.start()
#!addfavorite compatibility stuff #!addfavorite compatibility stuff
async def playPlaylist(message, sing=False): async def playPlaylist(message, sing=False):
global musicPlayer, currentPlaylist global musicPlayer, currentPlaylist
msg = message.content msg = message.content
toDelete = None
if not sing: if not sing:
if msg != "!play" or msg != "play ": if msg != "!play" or msg != "play ":
if await checkVoice(message): if await checkVoice(message):
@ -789,9 +851,13 @@ async def playPlaylist(message, sing=False):
if dataIO.fileIO("playlists/" + msg + ".txt", "check"): if dataIO.fileIO("playlists/" + msg + ".txt", "check"):
stopMusic() stopMusic()
data = {"filename" : msg, "type" : "playlist"} data = {"filename" : msg, "type" : "playlist"}
if settings["DOWNLOADMODE"]:
toDelete = await client.send_message(message.channel, "`I'm in download mode. It might take a bit for me to start and switch between tracks. I'll delete this message as soon as the current playlist stops.`".format(id, message.author.name))
currentPlaylist = Playlist(data) currentPlaylist = Playlist(data)
await asyncio.sleep(2) await asyncio.sleep(2)
await currentPlaylist.songSwitcher() await currentPlaylist.songSwitcher()
if toDelete:
await client.delete_message(toDelete)
else: else:
await client.send_message(message.channel, "{} `That playlist doesn't exist.`".format(message.author.mention)) await client.send_message(message.channel, "{} `That playlist doesn't exist.`".format(message.author.mention))
else: else:
@ -802,10 +868,15 @@ async def playPlaylist(message, sing=False):
"https://www.youtube.com/watch?v=vFrjMq4aL-g", "https://www.youtube.com/watch?v=WROI5WYBU_A", "https://www.youtube.com/watch?v=vFrjMq4aL-g", "https://www.youtube.com/watch?v=WROI5WYBU_A",
"https://www.youtube.com/watch?v=41tIUr_ex3g", "https://www.youtube.com/watch?v=f9O2Rjn1azc"] "https://www.youtube.com/watch?v=41tIUr_ex3g", "https://www.youtube.com/watch?v=f9O2Rjn1azc"]
song = choice(playlist) song = choice(playlist)
currentPlaylist = Playlist(singleSong=True) data = {"filename" : song, "type" : "singleSong"}
currentPlaylist.playlist = [song] if settings["DOWNLOADMODE"]:
musicPlayer = client.voice.create_ytdl_player(song, options=youtube_dl_options) toDelete = await client.send_message(message.channel, "`I'm in download mode. It might take a bit for me to start. I'll delete this message as soon as I'm ready.`".format(id, message.author.name))
musicPlayer.start() currentPlaylist = Playlist(data)
# currentPlaylist.playlist = [song]
# musicPlayer = client.voice.create_ytdl_player(song, options=youtube_dl_options)
# musicPlayer.start()
if toDelete:
await client.delete_message(toDelete)
await client.send_message(message.channel, choice(msg)) await client.send_message(message.channel, choice(msg))
async def playLocal(message): async def playLocal(message):
@ -1030,6 +1101,36 @@ async def sendPlaylist(message):
msg += "```" msg += "```"
await client.send_message(message.author, msg) await client.send_message(message.author, msg)
async def setVolume(message):
global settings
msg = message.content
if len(msg.split(" ")) == 2:
msg = msg.split(" ")
try:
vol = float(msg[1])
if vol >= 0 or vol <= 1:
settings["VOLUME"] = vol
await(client.send_message(message.channel, "Volume set. Next track will have the desired volume."))
dataIO.fileIO("settings.json", "save", settings)
else:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.50"))
except:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.15"))
else:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.15"))
async def downloadMode(message):
if isMemberAdmin(message):
if settings["DOWNLOADMODE"]:
settings["DOWNLOADMODE"] = False
await(client.send_message(message.channel, "`Download mode disabled. This mode is unstable and tracks might interrupt. Also, the volume settings will not have any effect.`"))
else:
settings["DOWNLOADMODE"] = True
await(client.send_message(message.channel, "`Download mode enabled.`"))
dataIO.fileIO("settings.json", "save", settings)
else:
await(client.send_message(message.channel, "`I don't take orders from you.`"))
############## ADMIN COMMANDS ################### ############## ADMIN COMMANDS ###################
async def shutdown(message): async def shutdown(message):
@ -1226,7 +1327,7 @@ def loadDataFromFiles(loadsettings=False):
logger.info("Loaded " + str(len(proverbs)) + " proverbs.") logger.info("Loaded " + str(len(proverbs)) + " proverbs.")
commands = dataIO.fileIO("commands.json", "load") commands = dataIO.fileIO("commands.json", "load")
logger.info("Loaded " + str(len(commands)) + " lists of commands.") logger.info("Loaded " + str(len(commands)) + " lists of custom commands.")
# trivia_questions = dataIO.loadTrivia() # trivia_questions = dataIO.loadTrivia()
# logger.info("Loaded " + str(len(trivia_questions)) + " questions.") # logger.info("Loaded " + str(len(trivia_questions)) + " questions.")
@ -1279,6 +1380,9 @@ def main():
musicPlayer = None musicPlayer = None
currentPlaylist = None currentPlaylist = None
if not os.path.exists("cache/"): #Stores youtube audio for DOWNLOADMODE
os.makedirs("cache")
client.run(settings["EMAIL"], settings["PASSWORD"]) client.run(settings["EMAIL"], settings["PASSWORD"])
if __name__ == '__main__': if __name__ == '__main__':