Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- waimport socket
- import sys
- import re
- from time import sleep, time
- import errno
- import pymysql.cursors
- import random
- from btts import btts
- from config import *
- tts = btts()
- CHANNEL = 'sentdex'
- # Connect to the database
- connection = pymysql.connect(host=IP,
- user=USERNAME,
- password=PASSWORD,
- db=DB,
- charset='utf8mb4',
- cursorclass=pymysql.cursors.DictCursor)
- with connection.cursor() as cursor:
- cursor.execute('SET NAMES utf8mb4')
- cursor.execute('SET character_set_client="utf8mb4"')
- def modify_input(string):
- tokenized = string.split(' ')
- if tokenized[0] == '@Charles_the_AI':
- string = ' '.join([i for i in tokenized[1:]])
- if '@Charles_the_AI' in string:
- string = string.replace('@Charles_the_AI','Charles')
- if '@charles_the_ai' in string:
- string = string.replace('@charles_the_ai','Charles')
- if '@Charles_the_ai' in string:
- string = string.replace('@Charles_the_ai','Charles')
- if '@Charles_The_AI' in string:
- string = string.replace('@Charles_The_AI','Charles')
- if '@CharlestheAI' in string:
- string = string.replace('@CharlestheAI','Charles')
- if '@charlestheai' in string:
- string = string.replace('@charlestheai','Charles')
- if '@Charlestheai' in string:
- string = string.replace('@Charlestheai','Charles')
- if '@CharlesTheAI' in string:
- string = string.replace('@CharlesTheAI','Charles')
- if 'CharlesTheAI' in string:
- string = string.replace('CharlesTheAI','Charles')
- if 'charlestheai' in string:
- string = string.replace('charlestheai','Charles')
- #string = re.sub(r"(?<=^|(?<=[^a-zA-Z0-9-_\\.]))@([A-Za-z]+[A-Za-z0-9_]+)","that person",string)
- string = string.strip()
- #string = string.replace('<3', '<3')
- return string
- def say_something(original,thing,user):
- ##'''
- ##engine = pyttsx3.init()
- ##voices = engine.getProperty('voices')
- ##for voice in voices:
- ##engine.setProperty('voice', 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Speech\Voices\Tokens\TTS_MS_EN-US_ZIRA_11.0')
- ##print(voice.id)
- ##engine.say('The quick brown fox jumped over the lazy dog.')
- ##engine.runAndWait()
- ##'''
- punc_dict = {"!":['exclaims','yells','shouts','cries','roars','hollers',],
- "?":['wonders','asks','inquires','is curious','wants to know'],
- ".":['says','states','declares','proclaims']}
- try:
- user_emote = random.choice(punc_dict[original[-1]])
- except:
- user_emote = random.choice(punc_dict['.'])
- #original = original.replace('<3', '<3')
- original = '{} {}: {}'.format(user, user_emote, original)
- tts.speak({
- 'phrases':[
- {
- 'text': "{}".format(original),
- 'voice': 'Google UK English Female',
- },
- {
- 'text': "{}".format( thing.replace("$000","One million dollars").replace("0'0 '","{} centimeters".format(str(random.randrange(183,213)))).replace("00",str(random.randrange(1,99))).replace("0",str(random.randrange(0,9))).replace('00',str(random.randrange(11,99))) ),
- 'voice': 'Google UK English Male',
- }
- ],
- 'source':'Twitch'
- })
- def check_mentions(mentions):
- for mention in mentions:
- try:
- with connection.cursor() as cursor:
- # check to see if user has already asked this message in the last 10 minutes?
- # check to see if user has asked more than 30 questions in the last 3600 seconds
- if 'charlestheai' in mention['message'].lower():
- #mention['message'] = mention['message'].replace('<3', '<3')
- print('Yes, a charles mention', mention['message'])
- # check to see if someone recently said this same thing in the last 5 minutes
- sql = "SELECT `id` FROM `chat_nmt` WHERE `question`=%s AND `unix` > %s"
- cursor.execute(sql, (mention['message'],int(time()-300))) # last 5 minutes
- result1 = cursor.fetchone()
- # check to see if any one user has asked more than 30 questions in the last hour
- sql = "SELECT `id` FROM `chat_nmt` WHERE `source_id`=%s AND `unix` > %s"
- cursor.execute(sql, (mention['user'],int(time()-3600))) # last 5 minutes
- result2 = cursor.fetchall()
- if result1 == None and len(result2)<=60:
- # Create a new record
- sql = "INSERT INTO `chat_nmt` (`unix`, `question`, `source`, `source_id`, `type`) VALUES (%s, %s, %s, %s, %s)"
- cursor.execute(sql, ( str(int(time())), mention['message'], 'twitch', mention['user'], 'twitch_mention'))
- connection.commit()
- except Exception as e:
- print(str(e))
- def check_to_reply():
- global last_msg
- unk_msgs = ['Hmm, I do not understand.',
- 'Try asking in another way.',
- 'I am confused with the question.',
- 'I do not know how to answer']
- with connection.cursor() as cursor:
- # check to see if that record exists:
- sql = "SELECT `id`, `question`,`response`, `source_id`, `type` FROM `chat_nmt` WHERE `source` = 'twitch' and `responded` = 0 and `response` IS NOT NULL"
- cursor.execute(sql)
- results = cursor.fetchall()
- replies = []
- for result in results:
- try:
- print(result)
- # Create a new record
- print(result)
- r_id = result['id']
- r_question = result['question']
- r_response = result['response']
- r_source_id = result['source_id']
- r_type = result['type']
- sql = "UPDATE chat SET `responded`=%s WHERE `id`=%s"
- cursor.execute(sql, ('1', r_id))
- replies.append([r_source_id, r_question, r_response])
- if '_UNK' not in r_response:
- say_something(modify_input(r_question),r_response, r_source_id)
- last_msg = time()
- if '_UNK' in r_response:
- twitch.sendMessage("@{} {}".format(r_source_id, random.choice(unk_msgs)))
- last_msg = time()
- except Exception as e:
- print(str(e))
- connection.commit()
- return replies
- class Twitch():
- # socket settings
- socket = {}
- host = None
- port = None
- nickname = None
- tiken = None
- channel = None
- received_messages = []
- log_file = None
- DEBUG = True
- # init
- def __init__(self, nickname, token, channel, log_file = 'twitchlog.txt', host = 'irc.chat.twitch.tv', port = 6667):
- # set properties
- self.host = host
- self.port = port
- self.nickname = nickname
- self.token = token
- self.channel = channel
- self.log_file = open(log_file, 'w')
- # connect
- self.connect()
- # tick
- def tick(self):
- self.checkForNewData()
- self.sendMessages()
- self.ping()
- # connect to Twitch IRC server
- def connect(self):
- self.info("Connecting to Twitch IRC server")
- # setup socket
- self.socket = {
- 'name': "twitch-irc",
- 'socket': socket.socket(socket.AF_INET, socket.SOCK_STREAM),
- 'buffer': "",
- 'last_msg': time(),
- 'last_ping_response': time(),
- 'next_ping': time() + 5,
- 'delimiter': "\r\n",
- 'messages': []
- }
- # connect
- self.socket['socket'].settimeout(5)
- try:
- self.socket['socket'].connect((self.host, self.port))
- except IOError as e:
- self.info("%s (%s)" % (e.errno, e.strerror), "ERROR: ")
- self.socket = None
- return False
- except:
- self.info("Unexpected error: %s" % sys.exc_info()[0], "ERROR: ")
- self.socket = None
- return False
- # set nonblocking connection
- self.socket['socket'].setblocking(0)
- self.info("Connected")
- # log in
- self.info("Logging in")
- self.socketWrite("CAP REQ :twitch.tv/tags")
- self.socketWrite("CAP REQ :twitch.tv/commands")
- self.socketWrite("CAP END")
- self.socketWrite("PASS oauth:%s" % self.token)
- self.socketWrite("NICK %s" % self.nickname.lower())
- # wait for response
- flag = False
- for i in range(500):
- sleep(0.01)
- # check if there is any response
- data = self.socketRead()
- # if true
- if data:
- # parse data
- response = self.parseChatLine(data)
- # we are logged in now
- if response['status'] == 'info' and not flag:
- self.info("Logged in")
- flag = True
- break
- # Twitch returned error message
- elif response['status'] == 'error':
- self.info("Login failed", "ERROR: ")
- self.socket = None
- return False
- # connection error?
- elif data is not None:
- self.socket = None
- return False
- # after 5 seconds long loop if there is no response still - error
- if not flag:
- self.info("Login failed", "ERROR: ")
- self.socket = None
- return False
- # join channel
- self.info("Joining #%s" % self.channel)
- self.socketWrite("JOIN #%s" % self.channel)
- # wait for response
- flag = False
- for i in range(500):
- sleep(0.01)
- # check if there is any response
- data = self.socketRead()
- # if true
- if data:
- # parse data
- response = self.parseChatLine(data)
- # joined a channel
- if response['status'] == 'join' and not flag:
- self.info("Joined #%s" % self.channel)
- flag = True
- break
- # connection error?
- elif data is not None:
- self.socket = None
- return False
- # after 5 seconds long loop if there is no response still - error
- if not flag:
- self.info("Joining failed", "ERROR: ")
- self.socket = None
- return False
- # parse irc command
- def parseChatLine(self, line):
- # ping
- if line == "PING :tmi.twitch.tv":
- self.socketWrite("PONG :tmi.twitch.tv")
- return {'status': 'ping'}
- # pong
- elif "PONG tmi.twitch.tv" in line:
- self.socket['last_ping_response'] = time()
- return {'status': 'pong'}
- # parse line
- line = re.search("(?:(?P<badges>[^\s]+) )?:(?P<host>[^\s]+) (?P<code>[^\s]+) (?P<info>[^\s]+)( (?P<message>.*))?", line)
- if line:
- message = line.groupdict().get('message', '')
- message = message[1:] if message and message.startswith(":") else message # drop first colon
- # join
- if line.group('code') == "JOIN":
- return {'status': 'join'}
- # notice
- elif line.group('code') == "NOTICE":
- self.info(message, "NOTICE: ")
- if message == "Login authentication failed":
- return {'status': 'error'}
- else:
- return {'status': 'notice'}
- # msg https://dev.twitch.tv/docs/v5/guides/irc/#privmsg-twitch-tags
- elif line.group('code') == 'PRIVMSG':
- user = re.search("!(?P<user>.*?)@", line.group('host'))
- bits = re.search("bits=(?P<bits>.*?);", line.group('badges'))
- subscriber = re.search("subscriber=(?P<subscriber>.*?);", line.group('badges'))
- if bits and bits.group('bits'):
- return {'status': 'cheer', 'user': user.group('user'), 'message': message, 'bits': int(bits.group('bits'))}
- else:
- return {'status': 'message', 'user': user.group('user'), 'message': message, 'subscriber': bool(int(subscriber.group('subscriber')))}
- # sub or resub https://dev.twitch.tv/docs/v5/guides/irc/#usernotice-twitch-tags
- elif line.group('code') == 'USERNOTICE':
- user = re.search("display-name=(?P<user>.*?);", line.group('badges'))
- if not user.group('user'):
- user = re.search("login=(?P<user>.*?);", line.group('badges'))
- wessage = re.search("system-msg=(?P<chatmessage>.*?);", line.group('badges'))
- if message is None:
- message = ''
- return {'status': 'sub', 'user': user.group('user'), 'message': message, 'chatmessage': str(chatmessage.group('chatmessage')).replace("\s", " ")}
- # info status
- else:
- if str(line.group('code')).isnumeric():
- return {'status': 'info'}
- line.group('code').isnumeric()
- # unrecognized command
- return {'status': 'unrecognized'}
- # still connected?
- def checkIfConnected(self):
- # if socket not exists
- if not self.socket:
- # connection is lost
- self.info("Connection to Twitch lost. Reconnecting in 5 seconds...", "ERROR: ")
- sleep(5)
- self.connect()
- if not self.socket:
- return False
- return True
- # check for incoming packets
- def checkForNewData(self):
- # if socket exists
- if self.socket:
- # grab all chat lines
- while True:
- # grab one chat line
- data = self.socketRead()
- # if there is some data - parse it
- if data:
- message = self.parseChatLine(data)
- # if message is unrecognized - drop it
- if message['status'] == 'unrecognized':
- continue
- # append message to a list of received messages
- self.received_messages.append(message)
- # no new data
- elif data is None:
- break
- # connection errors
- else:
- self.socket = None
- break
- # send message from list to chat
- def sendMessages(self):
- # if socket exists and there are messages to be sent back
- if self.socket and len(self.socket['messages']):
- # if time less than 0.5s from last sent message
- if time() - self.socket['last_msg'] <= 0.5 or len(self.socket['messages']) == 0:
- return
- # includes callback?
- callback = None
- if type(self.socket['messages'][0]) is list:
- callback = self.socket['messages'][0][1]
- self.socket['messages'][0] = self.socket['messages'][0][0]
- # send response from list to chat
- response = self.socketWrite(self.socket['messages'][0])
- # if successful
- if response:
- # remove message from list
- self.socket['messages'].pop(0)
- # callback?
- if callback is not None:
- callback()
- # connection errors
- else:
- self.socket = None
- # update time stamp of last sent message
- if self.socket:
- self.socket['last_msg'] = time()
- # append message to list
- def sendMessage(self, message):
- # message with callback
- if type(message) is list:
- message[0] = "PRIVMSG #%s :%s" % (self.channel, message[0])
- # just message
- else:
- message = "PRIVMSG #%s :%s" % (self.channel, message)
- # append message to a list
- self.socket['messages'].append(message)
- # get new messages
- def getMessages(self):
- messages = self.received_messages
- self.received_messages = []
- return messages
- # ping irc
- def ping(self):
- # socket exists and time to ping?
- if self.socket and self.socket['next_ping'] < time():
- # write message directly to a socket
- response = self.socketWrite("PING :tmi.twitch.tv")
- # connection errors?
- if not response:
- self.socket = None
- return False
- # set time stamp of next ping
- self.socket['next_ping'] += 60
- # check if there is a response for a ping - if not, connection is lost
- if self.socket and self.socket['next_ping'] > self.socket['last_ping_response'] + 130:
- self.socket = None
- # write to a log file
- def info(self, line, type="INFO: "):
- self.log_file.write("%s%s\n" % (type, line))
- self.log_file.flush()
- # read from socket, process one line
- def socketRead(self):
- # get up to 4096 bytes from socket
- try:
- self.socket['buffer'] += self.socket['socket'].recv(4096).decode("ascii", "backslashreplace")
- except IOError as e:
- if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
- self.info("Receiving data error: %s (%s)" % (e.errno, e.strerror), "ERROR: ")
- return False
- except:
- self.info("Unknown receiving data error: %s" % sys.exc_info()[0], "ERROR: ")
- return False
- # if there is at least one full line
- if not self.socket['delimiter'] or self.socket['delimiter'] in self.socket['buffer']:
- # split by delimiter, store in buffer and get one line
- if self.socket['delimiter']:
- (line, self.socket['buffer']) = self.socket['buffer'].split(self.socket['delimiter'], 1)
- # just one full line
- else:
- line = self.socket['buffer']
- self.socket['buffer'] = ""
- # write received message to a log
- if self.DEBUG and line:
- self.info(line, "DEBUG: %s: < " % self.socket['name'])
- # return chat message
- return line
- # no new data
- return None
- # write one line to socket
- def socketWrite(self, line):
- # write message to socket
- try:
- self.socket['socket'].send(("%s%s" % (line, self.socket['delimiter'])).encode('utf-8'))
- except IOError as e:
- if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
- self.info("Writing data error: %s (%s)" % (e.errno, e.strerror), "ERROR: ")
- return False
- except:
- self.info("Unknown writing data error: %s" % sys.exc_info()[0], "ERROR: ")
- return False
- # write sent message to a log
- if self.DEBUG:
- self.info(line.replace('\n', '\\n'), "DEBUG: %s: > " % self.socket['name'])
- return True
- #example:
- if __name__ == '__main__':
- twitch = Twitch('CharlesTheAI', '88m15rbrvxdzrd29rsjrgst2i2mlu3', CHANNEL)
- #twitch = Twitch('AICharlesBot', 'uxyngxigcs02qs4cfcdo2xqvqxi79x', 'daniel_kukiela')
- twitch.sendMessage("Hello everyone!")
- last_msg = time()
- # connect to twitch
- # nickname, token, channel, log file (optional, default: ./twitchlog.txt), host (optional, default: irc.chat.twitch.tv), port (optional, default: 6667)
- # main loop
- bored_msgs = ['Hello!',
- 'Hello, anyone there?',
- 'What is everyone up to?',
- 'Hi there!',
- 'Greetings humans.',
- 'Hello humans?',
- ]
- while True:
- try:
- # still connected?
- if not twitch.checkIfConnected():
- continue
- # get messages
- messages = twitch.getMessages()
- print(messages)
- print(last_msg)
- replies = check_to_reply()
- check_mentions(messages)
- # possible message objects:
- # {'status': 'message', 'user': 'twitch_username', 'message': 'message_body', 'subscriber': is_viewer_a_subcriber}
- # {'status': 'cheer', 'user': 'twitch_username', 'message': 'message_body', 'bits': number_of_bits}
- # {'status': 'sub', 'user': 'twitch_username', 'message': 'message_body', 'chatmessage': subscription_message} - chatmessage is a system message like "xxx has subscribed for y month(s)..."
- # ignore messages with other statuses
- if time() - last_msg > 300:
- twitch.sendMessage(random.choice(bored_msgs))
- last_msg = time()
- # you can also send a message with callback, callback will be called at the moment message is physically sent to a chat
- # (sendMessage method placies it in a list of messages to be sent asap)
- # a callback might be acquired by calling getattr(self, 'some_method')
- # twitch.sendMessage(["Some message", getattr(self, 'some_method')])
- # that has to be called just before end of loop
- twitch.tick()
- # wait for 1s (as this loop is sending message every passage)
- # should be 0.01s
- sleep(5)
- # sleep(0.01)
- except Exception as e:
- sleep(30)
- print(str(e))
- # Connect to the database
- # Connect to the database
- connection = pymysql.connect(host=IP,
- user=USERNAME,
- password=PASSWORD,
- db=DB,
- charset='utf8mb4',
- cursorclass=pymysql.cursors.DictCursor)
- with connection.cursor() as cursor:
- cursor.execute('SET NAMES utf8mb4')
- cursor.execute('SET character_set_client="utf8mb4"')
- sleep(5)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement