mirror of
				https://gitlab.com/gpvkt/twitchtts.git
				synced 2025-10-31 17:17:35 +01:00 
			
		
		
		
	Quote function added
This commit is contained in:
		
							parent
							
								
									995738368c
								
							
						
					
					
						commit
						2751d329c3
					
				
					 4 changed files with 177 additions and 2 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -3,3 +3,4 @@ build | ||||||
| tts.spec | tts.spec | ||||||
| tts.exe | tts.exe | ||||||
| random*.txt | random*.txt | ||||||
|  | quotes.txt | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
										
									
									
									
								
							|  | @ -118,8 +118,11 @@ Please note that the `oauth_token` is valid for approximately 60 days. If it bec | ||||||
| * `votestart`: Message when a quickvote is started. | * `votestart`: Message when a quickvote is started. | ||||||
| * `voteend`: Message if a quickvote ends. | * `voteend`: Message if a quickvote ends. | ||||||
| * `votenobody`: Message if quickvote ends, but nobody has voted. | * `votenobody`: Message if quickvote ends, but nobody has voted. | ||||||
| * `voteresult`: Prefix for the result (will be read out) | * `voteresult`: Prefix for the result (will be read out). | ||||||
| * `votes`: Suffix to vote count. | * `votes`: Suffix to vote count. | ||||||
|  | * `quotenotfound`: Message if requests quote wasn't found. | ||||||
|  | * `quoteaddedprefix`: Prefix for `Quote <number> added` message. | ||||||
|  | * `quoteaddedsuffix`: Suffix for `Quote <number> added` message. | ||||||
| 
 | 
 | ||||||
| ##### log | ##### log | ||||||
| 
 | 
 | ||||||
|  | @ -176,6 +179,22 @@ The `!quickvote` feature implements a simple vote system. If a broadcaster or mo | ||||||
| 
 | 
 | ||||||
| The `!random` command will read a random line from a file called `random.txt`. You can also use multiple files, if you call `!random foo` the bot fetch the random line from a file called `random_foo.txt` instead of `random.txt`. `!random bar` will use the file `random_bar.txt` and so on. The `!random` command is restricted to the broadcaster and moderators. | The `!random` command will read a random line from a file called `random.txt`. You can also use multiple files, if you call `!random foo` the bot fetch the random line from a file called `random_foo.txt` instead of `random.txt`. `!random bar` will use the file `random_bar.txt` and so on. The `!random` command is restricted to the broadcaster and moderators. | ||||||
| 
 | 
 | ||||||
|  | #### !smartvote | ||||||
|  | 
 | ||||||
|  | The `!smartvote` command will read a line from a file called `quotes.txt`. You can add a parameter after the command. If the parameter is numeric the bot will search for a line starting with `#$number`. If the parameter is a string it will search for a line matching the parameter. If no parameter is given it will search for a completely random line. | ||||||
|  | 
 | ||||||
|  | The format of `quotes.txt` looks as follows: | ||||||
|  | 
 | ||||||
|  | ``` lang=text | ||||||
|  | #1: "the quote" -username (date) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | #### !addquote | ||||||
|  | 
 | ||||||
|  | The `!addvote` command adds a new line to `quotes.txt`. It expects two parameters: `!addquote username quote` where `username` is the name of the user to be quoted. | ||||||
|  | 
 | ||||||
|  | Only Subs, Mods and Broadcaster are allowed to add quotes. | ||||||
|  | 
 | ||||||
| ## Build | ## Build | ||||||
| 
 | 
 | ||||||
| If you prefer to build your own `tts.exe` instead of using the shipped one, you can do as follows: | If you prefer to build your own `tts.exe` instead of using the shipped one, you can do as follows: | ||||||
|  |  | ||||||
|  | @ -1 +1,2 @@ | ||||||
|  | fuzzywuzzy==0.18.0 | ||||||
| PyYAML==6.0 | PyYAML==6.0 | ||||||
|  |  | ||||||
							
								
								
									
										156
									
								
								tts.py
									
										
									
									
									
								
							
							
						
						
									
										156
									
								
								tts.py
									
										
									
									
									
								
							|  | @ -41,6 +41,8 @@ from http.server import BaseHTTPRequestHandler | ||||||
| 
 | 
 | ||||||
| import yaml | import yaml | ||||||
| 
 | 
 | ||||||
|  | from fuzzywuzzy import process | ||||||
|  | 
 | ||||||
| class IRC: | class IRC: | ||||||
|     """ IRC bot """ |     """ IRC bot """ | ||||||
|     irc = socket.socket() |     irc = socket.socket() | ||||||
|  | @ -207,6 +209,14 @@ class IRC: | ||||||
|                 logging.debug("Ping check received.") |                 logging.debug("Ping check received.") | ||||||
|                 self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), "Pong!") |                 self.sendmsg(conf['IRC_CHANNEL'], "@"+str(user), "Pong!") | ||||||
| 
 | 
 | ||||||
|  |             if msg.startswith('!addquote'): | ||||||
|  |                 logging.debug("!addquote command detected") | ||||||
|  |                 self.Commands.addquote(self, tags, msg) | ||||||
|  | 
 | ||||||
|  |             if msg.startswith('!smartquote'): | ||||||
|  |                 logging.debug("!smartquote command detected") | ||||||
|  |                 self.Commands.quote(self, tags, msg) | ||||||
|  | 
 | ||||||
|             elif msg.startswith('!dtts'): |             elif msg.startswith('!dtts'): | ||||||
|                 logging.debug("!dtts command detected") |                 logging.debug("!dtts command detected") | ||||||
|                 self.Commands.dtts(self, msg) |                 self.Commands.dtts(self, msg) | ||||||
|  | @ -408,6 +418,146 @@ class IRC: | ||||||
|                 logging.info('Sending TTS message to raw_queue') |                 logging.info('Sending TTS message to raw_queue') | ||||||
|                 IRC.send_tts_msg(self, msg, tags) |                 IRC.send_tts_msg(self, msg, tags) | ||||||
| 
 | 
 | ||||||
|  |         def addquote(self, tags, msg): | ||||||
|  |             """ !addquote command | ||||||
|  |              | ||||||
|  |                 Adds a newline to quotes.txt | ||||||
|  |             """ | ||||||
|  | 
 | ||||||
|  |             user = tags['user'] | ||||||
|  | 
 | ||||||
|  |             if IRC.check_user_denied(self, user): | ||||||
|  |                 logging.info('User is not allowed to use TTS') | ||||||
|  |             elif IRC.check_subonly(self, tags): | ||||||
|  |                 logging.info('TTS is sub-only') | ||||||
|  |             else: | ||||||
|  |                 try: | ||||||
|  |                     with open("quotes.txt", "rb") as fp: | ||||||
|  |                         nol = len(fp.readlines()) | ||||||
|  |                     fp.close() | ||||||
|  |                 except FileNotFoundError: | ||||||
|  |                     logging.warn("quotes.txt does not exists, will create") | ||||||
|  |                     nol = 0 | ||||||
|  | 
 | ||||||
|  |                 nol = nol + 1 | ||||||
|  |                 quote = msg.replace("!addquote ", "").strip() | ||||||
|  |                 quote = quote.split(" ",1) | ||||||
|  |                 username = quote[0] | ||||||
|  |                  | ||||||
|  |                 quote = '#%s: "%s" -%s' % (nol, quote[1], username) | ||||||
|  |                 logging.info('Adding quote %s', quote) | ||||||
|  | 
 | ||||||
|  |                 with open("quotes.txt", "ab") as fp: | ||||||
|  |                     fp.write(quote.encode('utf-8')) | ||||||
|  | 
 | ||||||
|  |                 msg = "%s #%s %s" % (conf['MESSAGE']['QUOTE_ADDED_PREFIX'], nol, conf['MESSAGE']['QUOTE_ADDED_SUFFIX']) | ||||||
|  | 
 | ||||||
|  |                 raw_msg = { | ||||||
|  |                     "TTS": True, | ||||||
|  |                     "msg": msg, | ||||||
|  |                     "badges": True, | ||||||
|  |                     "subscriber": True, | ||||||
|  |                     "msgid": True, | ||||||
|  |                     "user": conf['IRC_USERNAME'], | ||||||
|  |                     "length": conf['IRC_TTS_LEN'], | ||||||
|  |                     "queuetime": datetime.datetime.now(), | ||||||
|  |                     "timestamp": str(time.time_ns()) | ||||||
|  |                 } | ||||||
|  |                 msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] | ||||||
|  |                 IRC.sendmsg(self, conf['IRC_CHANNEL'], "@"+str(user), msg) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |         def quote(self, tags, msg = False): | ||||||
|  |             """ !q command | ||||||
|  | 
 | ||||||
|  |                 Gets a line from quotes.txt. If a number if given as msg | ||||||
|  |                 it fetch the given line number. If a string is given | ||||||
|  |                 it fetch the best matching line. If nothing is given | ||||||
|  |                 it fetch a random line. | ||||||
|  |             """ | ||||||
|  | 
 | ||||||
|  |             user = tags['user'] | ||||||
|  |             query = msg.replace('!smartquote', '').strip() | ||||||
|  | 
 | ||||||
|  |             try: | ||||||
|  |                 if query.isdigit(): | ||||||
|  |                     logging.info('Fetching quote #%s', query) | ||||||
|  |                      | ||||||
|  |                     fp = open("quotes.txt", "rb") | ||||||
|  |                     quotes = fp.readlines() | ||||||
|  | 
 | ||||||
|  |                     for line in quotes: | ||||||
|  |                         if line.decode('utf-8').startswith("#"+str(query)+":"): | ||||||
|  |                             quote = line | ||||||
|  |                             break | ||||||
|  |                     fp.close() | ||||||
|  | 
 | ||||||
|  |                 elif query != "": | ||||||
|  |                     logging.info('Fetching match for %s', query) | ||||||
|  | 
 | ||||||
|  |                     fp = open("quotes.txt", "rb") | ||||||
|  |                     quotes = fp.readlines() | ||||||
|  |                     matches = process.extract(query, quotes, limit=20) | ||||||
|  |                     quotes = [] | ||||||
|  | 
 | ||||||
|  |                     for match, score in matches: | ||||||
|  |                         if score >= 60: | ||||||
|  |                             quotes.append(match) | ||||||
|  |                      | ||||||
|  |                     quote = random.choice(quotes) | ||||||
|  | 
 | ||||||
|  |                 else: | ||||||
|  |                     logging.info('Fetching random quote') | ||||||
|  |                      | ||||||
|  |                     with open("quotes.txt", "rb") as file: | ||||||
|  |                         lines = file.read().splitlines() | ||||||
|  |                         quote = random.choice(lines) | ||||||
|  |             except FileNotFoundError: | ||||||
|  |                 logging.error('"quotes.txt does not exists.') | ||||||
|  | 
 | ||||||
|  |             if not 'quote' in vars(): | ||||||
|  |                 logging.info('No quote found.') | ||||||
|  |                 quote = conf['MESSAGE']['QUOTE_NOT_FOUND'] | ||||||
|  |                 IRC.sendmsg(self, conf['IRC_CHANNEL'], "", quote) | ||||||
|  |                 return False | ||||||
|  | 
 | ||||||
|  |             if isinstance(quote, str): | ||||||
|  |                 quote = quote | ||||||
|  |             else: | ||||||
|  |                 quote = quote.decode('utf-8') | ||||||
|  | 
 | ||||||
|  |             if IRC.check_tts_disabled(self, user): | ||||||
|  |                 logging.info('TTS is disabled') | ||||||
|  |             elif IRC.check_user_denied(self, user): | ||||||
|  |                 logging.info('User is not allowed to use TTS') | ||||||
|  |             elif IRC.check_subonly(self, tags): | ||||||
|  |                 logging.info('TTS is sub-only') | ||||||
|  |             elif IRC.check_modonly(self, tags): | ||||||
|  |                 logging.info('TTS is mod-only') | ||||||
|  |             elif IRC.check_whitelist(self, user): | ||||||
|  |                 logging.info('User is not on whitelist') | ||||||
|  |             else: | ||||||
|  |                 logging.info('Sending quote to TTS') | ||||||
|  |                 logging.debug("Quote: %s", quote) | ||||||
|  |                 IRC.sendmsg(self, conf['IRC_CHANNEL'], "", quote) | ||||||
|  | 
 | ||||||
|  |                 quote = quote.rsplit('(', 1)[0] | ||||||
|  | 
 | ||||||
|  |                 raw_msg = { | ||||||
|  |                     "TTS": True, | ||||||
|  |                     "msg": quote, | ||||||
|  |                     "badges": True, | ||||||
|  |                     "subscriber": True, | ||||||
|  |                     "msgid": True, | ||||||
|  |                     "user": conf['IRC_USERNAME'], | ||||||
|  |                     "length": conf['IRC_TTS_LEN'], | ||||||
|  |                     "queuetime": datetime.datetime.now(), | ||||||
|  |                     "timestamp": str(time.time_ns()) | ||||||
|  |                 } | ||||||
|  |                 msg_queue[raw_msg['timestamp']] = [raw_msg['user'], raw_msg['msg']] | ||||||
|  | 
 | ||||||
|  |             return True | ||||||
|  | 
 | ||||||
|         def quickvote(self, msg): |         def quickvote(self, msg): | ||||||
|             """ !quickvote command |             """ !quickvote command | ||||||
| 
 | 
 | ||||||
|  | @ -760,7 +910,11 @@ def load_config(): | ||||||
|             conf['MESSAGE']['VOTEEND'] = cfg.get('messages', {}).get('voteend', "Quickvote ended. The results are:") |             conf['MESSAGE']['VOTEEND'] = cfg.get('messages', {}).get('voteend', "Quickvote ended. The results are:") | ||||||
|             conf['MESSAGE']['VOTENOBODY']  = cfg.get('messages', {}).get('votenobody', "Nobody casted a vote. :(") |             conf['MESSAGE']['VOTENOBODY']  = cfg.get('messages', {}).get('votenobody', "Nobody casted a vote. :(") | ||||||
|             conf['MESSAGE']['VOTERESULT']  = cfg.get('messages', {}).get('voteresult', "Voting has ended. The result is:") |             conf['MESSAGE']['VOTERESULT']  = cfg.get('messages', {}).get('voteresult', "Voting has ended. The result is:") | ||||||
|             conf['MESSAGE']['VOTES']  = cfg.get('messages', {}).get('votes', "Stimmen") |             conf['MESSAGE']['VOTES']  = cfg.get('messages', {}).get('votes', "Votes") | ||||||
|  | 
 | ||||||
|  |             conf['MESSAGE']['QUOTE_NOT_FOUND'] = cfg.get('messages', {}).get('quotenotfound', "Sorry, no quote found.") | ||||||
|  |             conf['MESSAGE']['QUOTE_ADDED_PREFIX'] = cfg.get('messages', {}).get('quoteaddedprefix', "Quote:") | ||||||
|  |             conf['MESSAGE']['QUOTE_ADDED_SUFFIX'] = cfg.get('messages', {}).get('quoteaddedsuffix', "added.") | ||||||
| 
 | 
 | ||||||
|             conf['USERMAP'] = cfg.get('usermapping', []) |             conf['USERMAP'] = cfg.get('usermapping', []) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue