Twitch alert system, custom commands' list

Added !twitchalert !stoptwitchalert to add and remove online alerts
about the specified streamer in the channel
Added !customcommands for the custom commands list of the server
Added startRedLoop.bat for automatically restarting the bot in case of
crash
This commit is contained in:
Twentysix 2016-01-08 15:56:21 +01:00
parent c722c9e117
commit 7a82c9ec68
5 changed files with 163 additions and 21 deletions

View File

@ -3,7 +3,7 @@ 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", "DOWNLOADMODE" : true, ' + '"TRIVIAMAXSCORE": 10, "TRIVIADELAY": 15, "LOGGING": true, "EMAIL": "EMAILHERE", "ADMINROLE": "Transistor", "DOWNLOADMODE" : true, ' +
'"VOLUME": 0.10}') '"VOLUME": 0.20}')
logger = logging.getLogger("__main__") logger = logging.getLogger("__main__")

170
red.py
View File

@ -38,8 +38,11 @@ help = """**Commands list:**
!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
!twitchalert [stream] - Whenever the stream is online the bot will send an alert in the channel (admin only)
!stoptwitchalert [stream] - Stop sending alerts about the specified stream in the channel (admin only)
!roll [number] - Random number between 0 and [number] !roll [number] - Random number between 0 and [number]
!gif [text] - GIF search !gif [text] - GIF search
!customcommands - Custom commands' list
!addcom [command] [text] - Add a custom command !addcom [command] [text] - Add a custom command
!editcom [command] [text] - Edit a custom command !editcom [command] [text] - Edit a custom command
!delcom [command] - Delete a custom command !delcom [command] - Delete a custom command
@ -146,10 +149,16 @@ async def on_message(message):
await editcom(message) await editcom(message)
elif message.content.startswith('!delcom'): elif message.content.startswith('!delcom'):
await delcom(message) await delcom(message)
elif message.content == "!customcommands":
await listCustomCommands(message)
elif message.content.startswith('!sw'): elif message.content.startswith('!sw'):
await stopwatch(message) await stopwatch(message)
elif message.content.startswith('!id'): elif message.content.startswith('!id'):
await client.send_message(message.channel, "{} `Your id is {}`".format(message.author.mention, message.author.id)) await client.send_message(message.channel, "{} `Your id is {}`".format(message.author.mention, message.author.id))
elif message.content.startswith('!twitchalert'):
await addTwitchAlert(message)
elif message.content.startswith('!stoptwitchalert'):
await removeTwitchAlert(message)
elif message.content.startswith('!twitch'): elif message.content.startswith('!twitch'):
await twitchCheck(message) await twitchCheck(message)
elif message.content.startswith('!image'): elif message.content.startswith('!image'):
@ -445,7 +454,7 @@ class Playlist():
self.currentTitle = v["title"] self.currentTitle = v["title"]
return v["id"] return v["id"]
except Exception as e: except Exception as e:
print(e) logger.error(e)
return False return False
def playSingleSong(self, url): def playSingleSong(self, url):
@ -578,6 +587,20 @@ async def delcom(message):
else: else:
await client.send_message(message.channel, "`You don't have permissions to edit custom commands.`") await client.send_message(message.channel, "`You don't have permissions to edit custom commands.`")
async def listCustomCommands(message):
msg = "Custom commands: \n\n```"
cmds = commands[message.channel.server.id].keys()
if cmds:
for i, d in enumerate(cmds):
if i % 4 == 0 and i != 0:
msg = msg + d + "\n"
else:
msg = msg + d + "\t"
msg += "```"
await client.send_message(message.author, msg)
else:
await client.send_message(message.author, "There are no custom commands.")
def checkAuth(cmd, message, settings): #checks if those settings are on. If they are, it checks if the user is a owner def checkAuth(cmd, message, settings): #checks if those settings are on. If they are, it checks if the user is a owner
if cmd == "ModifyCommands": if cmd == "ModifyCommands":
if settings["EDIT_CC_ADMIN_ONLY"]: if settings["EDIT_CC_ADMIN_ONLY"]:
@ -596,7 +619,7 @@ def checkAuth(cmd, message, settings): #checks if those settings are on. If they
else: else:
return True return True
else: else:
print("Invalid call to checkAuth") logger.error("Invalid call to checkAuth")
return False return False
@ -1077,14 +1100,15 @@ async def removeFromFavorites(message):
async def playFavorites(message): async def playFavorites(message):
global musicPlayer, currentPlaylist global musicPlayer, currentPlaylist
if dataIO.fileIO("favorites/" + message.author.id + ".txt", "check") and await checkVoice(message): if await checkVoice(message):
data = {"filename" : message.author.id, "type" : "favorites"} if dataIO.fileIO("favorites/" + message.author.id + ".txt", "check"):
stopMusic() data = {"filename" : message.author.id, "type" : "favorites"}
currentPlaylist = Playlist(data) stopMusic()
await asyncio.sleep(2) currentPlaylist = Playlist(data)
await currentPlaylist.songSwitcher() await asyncio.sleep(2)
else: await currentPlaylist.songSwitcher()
await client.send_message(message.channel, "{} `You don't have any favorites yet. Start adding them with !addfavorite`".format(message.author.mention)) else:
await client.send_message(message.channel, "{} `You don't have any favorites yet. Start adding them with !addfavorite`".format(message.author.mention))
async def sendPlaylist(message): async def sendPlaylist(message):
if currentPlaylist: if currentPlaylist:
@ -1109,14 +1133,14 @@ async def setVolume(message):
vol = float(msg[1]) vol = float(msg[1])
if vol >= 0 or vol <= 1: if vol >= 0 or vol <= 1:
settings["VOLUME"] = vol settings["VOLUME"] = vol
await(client.send_message(message.channel, "Volume set. Next track will have the desired volume.")) await(client.send_message(message.channel, "`Volume set. Next track will have the desired volume.`"))
dataIO.fileIO("settings.json", "save", settings) dataIO.fileIO("settings.json", "save", settings)
else: else:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.50")) await(client.send_message(message.channel, "`Volume must be between 0 and 1. Example: !volume 0.50`"))
except: except:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.15")) await(client.send_message(message.channel, "`Volume must be between 0 and 1. Example: !volume 0.15`"))
else: else:
await(client.send_message(message.channel, "Volume must be between 0 and 1. Example: !volume 0.15")) await(client.send_message(message.channel, "`Volume must be between 0 and 1. Example: !volume 0.15`"))
async def downloadMode(message): async def downloadMode(message):
if isMemberAdmin(message): if isMemberAdmin(message):
@ -1230,7 +1254,7 @@ async def changeName(message):
try: try:
await client.edit_profile(settings["PASSWORD"], username=msg[1]) await client.edit_profile(settings["PASSWORD"], username=msg[1])
except Exception as e: except Exception as e:
print(e) logger.error(e)
else: else:
await client.send_message(message.channel, "`!name [new name]`") await client.send_message(message.channel, "`!name [new name]`")
else: else:
@ -1302,8 +1326,101 @@ def isMemberAdmin(message):
def canDeleteMessages(message): def canDeleteMessages(message):
return message.channel.permissions_for(message.server.me).manage_messages return message.channel.permissions_for(message.server.me).manage_messages
async def addTwitchAlert(message):
global twitchStreams
added = False
if isMemberAdmin(message):
msg = message.content.split(" ")
if len(msg) == 2:
for i, stream in enumerate(twitchStreams):
if stream["NAME"] == msg[1] and message.channel.id in stream["CHANNELS"]:
await client.send_message(message.channel, "`I'm already monitoring that stream in this channel.`")
return False
for stream in twitchStreams:
if stream["NAME"] == msg[1] and message.channel.id not in stream["CHANNELS"]: # twitchAlert is already monitoring this streamer but not in this channel
twitchStreams[i]["CHANNELS"].append(message.channel.id)
added = True
if not added: # twitchAlert wasn't monitoring this streamer
twitchStreams.append({"CHANNELS" : [message.channel.id], "NAME" : msg[1], "ALREADY_ONLINE" : False})
dataIO.fileIO("twitch.json", "save", twitchStreams)
await client.send_message(message.channel, "`I will always send an alert in this channel whenever {}'s stream is online. Use !stoptwitchalert [name] to stop it.`".format(msg[1]))
else:
await client.send_message(message.channel, "`!twitchalert [name]`")
else:
await client.send_message(message.channel, "`I don't take orders from you.`")
async def removeTwitchAlert(message):
global twitchStreams
if isMemberAdmin(message):
msg = message.content.split(" ")
if len(msg) == 2:
for i, stream in enumerate(twitchStreams):
if stream["NAME"] == msg[1] and message.channel.id in stream["CHANNELS"]:
if len(stream["CHANNELS"]) == 1:
twitchStreams.remove(stream)
else:
twitchStreams[i]["CHANNELS"].remove(message.channel.id)
dataIO.fileIO("twitch.json", "save", twitchStreams)
await client.send_message(message.channel, "`I will stop sending alerts about {}'s stream in this channel.`".format(msg[1]))
return True
await client.send_message(message.channel, "`There's no alert for {}'s stream in this channel.`".format(msg[1]))
else:
await client.send_message(message.channel, "`!stoptwitchalert [name]`")
else:
await client.send_message(message.channel, "`I don't take orders from you.`")
################################################ ################################################
@asyncio.coroutine
async def twitchAlert():
global twitchStreams
CHECK_DELAY = 10
while True:
if twitchStreams and client.is_logged_in:
to_delete = []
save = False
consistency_check = twitchStreams
for i, stream in enumerate(twitchStreams):
if twitchStreams == consistency_check: #prevents buggy behavior if twitchStreams gets modified during the iteration
try:
url = "https://api.twitch.tv/kraken/streams/" + stream["NAME"]
data = requests.get(url).json()
if "error" in data: #Stream doesn't exist, remove from list
to_delete.append(stream)
elif "stream" in data:
if data["stream"] != None:
if not stream["ALREADY_ONLINE"]:
for channel in stream["CHANNELS"]:
try:
await client.send_message(client.get_channel(channel), "`{} is online!` {}".format(stream["NAME"], "http://www.twitch.tv/" + stream["NAME"]))
except: #In case of missing permissions
pass
twitchStreams[i]["ALREADY_ONLINE"] = True
save = True
else:
if stream["ALREADY_ONLINE"]:
twitchStreams[i]["ALREADY_ONLINE"] = False
save = True
except Exception as e:
logger.warning(e)
if save: #Saves online status, in case the bot needs to be restarted it can prevent message spam
dataIO.fileIO("twitch.json", "save", twitchStreams)
save = False
await asyncio.sleep(CHECK_DELAY)
else:
break
if to_delete:
for invalid_stream in to_delete:
twitchStreams.remove(invalid_stream)
dataIO.fileIO("twitch.json", "save", twitchStreams)
else:
await asyncio.sleep(5)
async def customCommand(message): async def customCommand(message):
msg = message.content[1:] msg = message.content[1:]
if message.channel.server.id in commands: if message.channel.server.id in commands:
@ -1320,7 +1437,7 @@ def console():
print("\n") print("\n")
def loadDataFromFiles(loadsettings=False): def loadDataFromFiles(loadsettings=False):
global proverbs, commands, trivia_questions, badwords, badwords_regex, shush_list global proverbs, commands, trivia_questions, badwords, badwords_regex, shush_list, twitchStreams
proverbs = dataIO.loadProverbs() proverbs = dataIO.loadProverbs()
logger.info("Loaded " + str(len(proverbs)) + " proverbs.") logger.info("Loaded " + str(len(proverbs)) + " proverbs.")
@ -1340,6 +1457,9 @@ def loadDataFromFiles(loadsettings=False):
shush_list = dataIO.fileIO("shushlist.json", "load") shush_list = dataIO.fileIO("shushlist.json", "load")
logger.info("Loaded " + str(len(shush_list)) + " silenced channels.") logger.info("Loaded " + str(len(shush_list)) + " silenced channels.")
twitchStreams = dataIO.fileIO("twitch.json", "load")
logger.info("Loaded " + str(len(twitchStreams)) + " streams to monitor.")
if loadsettings: if loadsettings:
global settings global settings
settings = dataIO.fileIO("settings.json", "load") settings = dataIO.fileIO("settings.json", "load")
@ -1351,6 +1471,10 @@ def main():
logger = loggerSetup() logger = loggerSetup()
dataIO.logger = logger dataIO.logger = logger
if not os.path.isfile("twitch.json"):
logger.info("Missing twitch.json. Creating it...")
dataIO.fileIO("twitch.json", "save", [])
settings = dataIO.loadAndCheckSettings() settings = dataIO.loadAndCheckSettings()
loadDataFromFiles() loadDataFromFiles()
@ -1382,7 +1506,17 @@ def main():
if not os.path.exists("cache/"): #Stores youtube audio for DOWNLOADMODE if not os.path.exists("cache/"): #Stores youtube audio for DOWNLOADMODE
os.makedirs("cache") os.makedirs("cache")
client.run(settings["EMAIL"], settings["PASSWORD"]) loop.create_task(twitchAlert())
#client.run(settings["EMAIL"], settings["PASSWORD"])
yield from client.login(settings["EMAIL"], settings["PASSWORD"])
yield from client.connect()
if __name__ == '__main__': if __name__ == '__main__':
main() loop = asyncio.get_event_loop()
try:
loop.run_until_complete(main())
except:
loop.run_until_complete(client.logout())
finally:
loop.close()

View File

@ -1 +1 @@
{"CUSTOMCOMMANDS": true, "EMAIL": "EMAILHERE", "TRIVIA_ADMIN_ONLY": false, "EDIT_CC_ADMIN_ONLY": false, "TRIVIAMAXSCORE": 10, "TRIVIADELAY": 15, "PASSWORD": "PASSWORDHERE", "LOGGING": true, "ADMINROLE": "Transistor", "FILTER": true} {"VOLUME": 0.2, "DOWNLOADMODE": true, "EDIT_CC_ADMIN_ONLY": false, "EMAIL": "EMAILHERE", "TRIVIAMAXSCORE": 10, "PASSWORD": "PASSWORDHERE", "FILTER": true, "CUSTOMCOMMANDS": true, "LOGGING": true, "TRIVIADELAY": 15, "TRIVIA_ADMIN_ONLY": false, "ADMINROLE": "Transistor"}

7
startRedLoop.bat Normal file
View File

@ -0,0 +1,7 @@
@Echo off
:Start
python red.py
timeout 2
goto Start

1
twitch.json Normal file
View File

@ -0,0 +1 @@
[]