| Total Complexity | 175 |
| Total Lines | 568 |
| Duplicated Lines | 4.75 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Portal_World often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | try: |
||
| 2 | import http.server |
||
| 3 | from twitchio.ext import commands |
||
| 4 | from twitchio.errors import AuthenticationError,EchoMessageWarning |
||
| 5 | import json |
||
| 6 | from re import search,findall,IGNORECASE,MULTILINE |
||
| 7 | from sys import argv |
||
| 8 | import os |
||
| 9 | import threading |
||
| 10 | import time |
||
| 11 | import ctypes |
||
| 12 | import steam |
||
| 13 | import socketserver |
||
| 14 | import webbrowser |
||
| 15 | except ImportError as e: |
||
| 16 | input(str(e)) |
||
| 17 | exit() |
||
| 18 | |||
| 19 | class Bot(commands.Bot): |
||
| 20 | |||
| 21 | def __init__(self): |
||
| 22 | with open(path3 + '/def.txt','r') as infile: |
||
| 23 | default = infile.read() |
||
| 24 | with open(path3 + '/settings.txt', 'r') as infile: |
||
| 25 | settings = infile.read() |
||
| 26 | mat = findall(r'"(.+?)"', settings) |
||
| 27 | if len(mat) < 6 or default == settings: |
||
| 28 | print('Error, please fill settings.txt completely in first.') |
||
| 29 | exit() |
||
| 30 | self.user_count = mat[3] |
||
| 31 | self.settings = mat |
||
| 32 | try: |
||
| 33 | super().__init__(irc_token=mat[0],prefix=mat[5], nick=mat[1], initial_channels=[mat[2]]) |
||
| 34 | except AuthenticationError: |
||
| 35 | print('settings.txt not filled in correctly. Please close this window and check you settings.') |
||
| 36 | |||
| 37 | def close(self): |
||
| 38 | os.system('exit') |
||
| 39 | |||
| 40 | # Events don't need decorators when subclassed |
||
| 41 | async def event_ready(self): |
||
| 42 | print(f'Ready | {self.nick}') |
||
| 43 | |||
| 44 | async def send_message(self,message,channel): |
||
| 45 | if len(message) == 0 or message == None: |
||
| 46 | return |
||
| 47 | if len(message) < 500: |
||
| 48 | await channel.send(message) |
||
| 49 | return |
||
| 50 | |||
| 51 | while len(message) >= 500: |
||
| 52 | await channel.send(message[:499]) |
||
| 53 | message = message[499:] |
||
| 54 | if len(message) != 0: |
||
| 55 | await channel.send(message) |
||
| 56 | |||
| 57 | async def event_message(self, message): |
||
| 58 | try: |
||
| 59 | if message.author == self.nick: |
||
| 60 | return |
||
| 61 | |||
| 62 | await self.handle_commands(message) |
||
| 63 | |||
| 64 | await self.help_command(message) |
||
| 65 | |||
| 66 | except Exception as e: |
||
| 67 | if isinstance(e,commands.errors.CommandNotFound) or isinstance(e,EchoMessageWarning): |
||
| 68 | return |
||
| 69 | await message.channel.send("Uncaught error: {}".format(e)) |
||
| 70 | |||
| 71 | async def event_command_error(self, ctx, error): |
||
| 72 | if isinstance(error, commands.errors.CommandNotFound) or isinstance(error,EchoMessageWarning): |
||
| 73 | return |
||
| 74 | raise error |
||
| 75 | |||
| 76 | async def help_command(self,ctx): |
||
| 77 | if len(self.settings) >= 8: |
||
| 78 | if ctx.content.startswith(str(self.settings[5]) + str(self.settings[7])): |
||
| 79 | await self.send_message('{0}add[submit] (level url), {0}remove[delete] (level name, url or id), {0}list[queue,q], {0}mylist[myqueue,myq], {0}current[np]'.format(self.settings[5]), ctx.channel) |
||
| 80 | |||
| 81 | # Commands use a different decorator |
||
| 82 | @commands.command(name='add',aliases=['submit']) |
||
| 83 | async def add(self, ctx): |
||
| 84 | with open(path,'r') as infile: |
||
| 85 | data = json.load(infile) |
||
| 86 | try: |
||
| 87 | if data[len(data) - 1] == False: |
||
| 88 | await self.send_message("Couldn't add level due to the queue being locked",ctx) |
||
| 89 | return |
||
| 90 | except IndexError: |
||
| 91 | pass |
||
| 92 | |||
| 93 | mat = search(r"""(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])\?id=(\d*)""", ctx.content, IGNORECASE) |
||
| 94 | if mat: |
||
| 95 | levelLink = mat.string |
||
| 96 | authId = mat.group(1) |
||
| 97 | |||
| 98 | levelJson = steam.webapi.post(interface='ISteamRemoteStorage',method='GetPublishedFileDetails',params={'itemcount': 1, 'publishedfileids[0]':authId}) |
||
| 99 | |||
| 100 | if levelJson: |
||
| 101 | levelName = levelJson['response']['publishedfiledetails'][0]['title'] |
||
| 102 | sId = levelJson['response']['publishedfiledetails'][0]['creator'] |
||
| 103 | |||
| 104 | try: |
||
| 105 | if int(levelJson['response']['publishedfiledetails'][0]['consumer_app_id']) != int(self.settings[6]): |
||
| 106 | await self.send_message("Couldn't add item due to it not being for the correct game",ctx) |
||
| 107 | return |
||
| 108 | except ValueError: |
||
| 109 | pass |
||
| 110 | |||
| 111 | uinfo = steam.webapi.get(interface='ISteamUser',method='GetPlayerSummaries',version=2,params={'key':'ABCE07D6D3E64ECBB4733E9E3DA30892','steamids':sId}) |
||
| 112 | if uinfo: |
||
| 113 | authorName = uinfo['response']['players'][0]['personaname'] |
||
| 114 | |||
| 115 | i = 0 |
||
| 116 | for level in data: |
||
| 117 | if len(data) > 2: |
||
| 118 | if level['twitchID'] == ctx.author.id: |
||
| 119 | i += 1 |
||
| 120 | if level['link'].lower() == levelLink.lower(): |
||
| 121 | await self.send_message('Unable to add level due to {0} already being in the queue!'.format(levelName),ctx) |
||
| 122 | return |
||
| 123 | |||
| 124 | if len(data) > int(self.user_count) - 1: |
||
| 125 | if i >= int(self.user_count): |
||
| 126 | await self.send_message('Unable to add level due to {0} already having {1} levels in the queue!'.format(ctx.author.display_name,self.user_count),ctx) |
||
| 127 | return |
||
| 128 | |||
| 129 | with open(path,'w') as outfile: |
||
| 130 | data.append({'link':levelLink,'levelName':levelName,'twitchID':ctx.author.id,'levelMakerName':authorName,'submitterName':ctx.author.display_name}) |
||
| 131 | json.dump(data,outfile) |
||
| 132 | await self.send_message(f'Succesfully added {levelName} to the queue at place {len(data)}!',ctx) |
||
| 133 | else: |
||
| 134 | await ctx.send('Error with steam api') |
||
| 135 | else: |
||
| 136 | await ctx.send('Error finding level, is the url correct?') |
||
| 137 | else: |
||
| 138 | mat = findall(f"{self.settings[5]}([\\w]+)\\s",ctx.content) |
||
| 139 | if mat: |
||
| 140 | await ctx.send(f'Invalid syntax, {self.settings[5]}{mat[0]} [level url]') |
||
| 141 | else: |
||
| 142 | await ctx.send('Invalid syntax') |
||
| 143 | |||
| 144 | @commands.command(name='remove', aliases=['delete']) |
||
| 145 | async def remove(self, ctx): |
||
| 146 | mat = findall(r"""(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])""", ctx.content, IGNORECASE) |
||
| 147 | if mat: |
||
| 148 | with open(path, 'r') as infile: |
||
| 149 | levels = json.load(infile) |
||
| 150 | i = 0 |
||
| 151 | for level in levels: |
||
| 152 | View Code Duplication | if level['link'].lower() == mat[0].lower(): |
|
|
|
|||
| 153 | if level['twitchID'] == ctx.author.id or ctx.author.is_mod: |
||
| 154 | if i == 0: |
||
| 155 | await ctx.send('Cannot remove level due to it currently being played.') |
||
| 156 | else: |
||
| 157 | lname = level['levelName'] |
||
| 158 | levels.pop(i) |
||
| 159 | with open(path, 'w') as outfile: |
||
| 160 | json.dump(levels, outfile) |
||
| 161 | |||
| 162 | await self.send_message(f'Succesfully removed {lname} from list!', ctx) |
||
| 163 | else: |
||
| 164 | await self.send_message('Cannot remove level because {0} submitted it, not {1}.'.format(level['submitterName'], ctx.author.display_name), ctx) |
||
| 165 | break |
||
| 166 | i += 1 |
||
| 167 | |||
| 168 | else: |
||
| 169 | mat = search(r"\s(\d)", ctx.content) |
||
| 170 | if mat: |
||
| 171 | with open(path, 'r') as infile: |
||
| 172 | levels = json.load(infile) |
||
| 173 | i = int(mat.group(1)) - 1 |
||
| 174 | if i == 0: |
||
| 175 | await ctx.send('Cannot remove level due to it currently being played.') |
||
| 176 | elif i + 1 > len(levels): |
||
| 177 | await ctx.send('Invalid level id') |
||
| 178 | else: |
||
| 179 | if level['twitchID'] == ctx.author.id or ctx.author.is_mod: |
||
| 180 | lname = level['levelName'] |
||
| 181 | levels.pop(i) |
||
| 182 | with open(path, 'w') as outfile: |
||
| 183 | json.dump(levels, outfile) |
||
| 184 | |||
| 185 | await self.send_message(f'Succesfully removed {lname} from list!', ctx) |
||
| 186 | else: |
||
| 187 | await self.send_message('Cannot remove level because {0} submitted it, not {1}.'.format(level['submitterName'], ctx.author.display_name), ctx) |
||
| 188 | else: |
||
| 189 | mat = search(r"\s(.+)", ctx.content) |
||
| 190 | if mat: |
||
| 191 | with open(path, 'r') as infile: |
||
| 192 | levels = json.load(infile) |
||
| 193 | i = 0 |
||
| 194 | for level in levels: |
||
| 195 | View Code Duplication | if level['levelName'].lower() == mat.group(1).lower(): |
|
| 196 | if level['twitchID'] == ctx.author.id or ctx.author.is_mod: |
||
| 197 | if i == 0: |
||
| 198 | await ctx.send('Cannot remove level due to it currently being played.') |
||
| 199 | else: |
||
| 200 | lname = level['levelName'] |
||
| 201 | levels.pop(i) |
||
| 202 | with open(path, 'w') as outfile: |
||
| 203 | json.dump(levels, outfile) |
||
| 204 | await self.send_message(f'Succesfully removed {lname} from list!', ctx) |
||
| 205 | else: |
||
| 206 | await self.send_message('Cannot remove level because {0} submitted it, not {1}.'.format(level['submitterName'], ctx.author.display_name), ctx) |
||
| 207 | break |
||
| 208 | i += 1 |
||
| 209 | else: |
||
| 210 | mat = findall(f"{self.settings[5]}([\\w]+)\\s", ctx.content) |
||
| 211 | if mat: |
||
| 212 | await ctx.send(f'Invalid syntax, {self.settings[5]}{mat[0]} [link, level name or level id]') |
||
| 213 | else: |
||
| 214 | await ctx.send('You should not be seeing this, something went terribly wrong. Anyways, incorrect syntax.') |
||
| 215 | |||
| 216 | @commands.command(name='promote') |
||
| 217 | async def promote(self,ctx): |
||
| 218 | mat = findall(r"""(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])""", ctx.content, IGNORECASE) |
||
| 219 | if mat: |
||
| 220 | with open(path, 'r') as infile: |
||
| 221 | levels = json.load(infile) |
||
| 222 | i = 0 |
||
| 223 | for level in levels: |
||
| 224 | if level['link'].lower() == mat[0].lower(): |
||
| 225 | if ctx.author.is_mod: |
||
| 226 | if i == 0: |
||
| 227 | await ctx.send('Cannot promote level due to it currently being played.') |
||
| 228 | else: |
||
| 229 | lname = level['levelName'] |
||
| 230 | levels.pop(i) |
||
| 231 | levels.insert(1, level) |
||
| 232 | with open(path, 'w') as outfile: |
||
| 233 | json.dump(levels, outfile) |
||
| 234 | |||
| 235 | await self.send_message(f'{lname} is now up next!', ctx) |
||
| 236 | break |
||
| 237 | i += 1 |
||
| 238 | else: |
||
| 239 | mat = search(r"\s(\d)", ctx.content) |
||
| 240 | if mat: |
||
| 241 | with open(path, 'r') as infile: |
||
| 242 | levels = json.load(infile) |
||
| 243 | i = int(mat.group(1)) - 1 |
||
| 244 | if ctx.author.is_mod: |
||
| 245 | if i == 0: |
||
| 246 | await ctx.send('Cannot promote level due to it currently being played.') |
||
| 247 | elif i + 1 > len(levels): |
||
| 248 | await ctx.send('Invalid level id') |
||
| 249 | else: |
||
| 250 | level = levels[i] |
||
| 251 | lname = level['levelName'] |
||
| 252 | levels.pop(i) |
||
| 253 | levels.insert(1, level) |
||
| 254 | with open(path, 'w') as outfile: |
||
| 255 | json.dump(levels, outfile) |
||
| 256 | await self.send_message(f'{lname} is now up next!', ctx) |
||
| 257 | else: |
||
| 258 | mat = search(r"\s(.+)", ctx.content) |
||
| 259 | if mat: |
||
| 260 | with open(path, 'r') as infile: |
||
| 261 | levels = json.load(infile) |
||
| 262 | i = 0 |
||
| 263 | for level in levels: |
||
| 264 | if level['levelName'].lower() == mat.group(1).lower(): |
||
| 265 | if ctx.author.is_mod: |
||
| 266 | if i == 0: |
||
| 267 | await ctx.send('Cannot promote level due to it currently being played.') |
||
| 268 | else: |
||
| 269 | lname = level['levelName'] |
||
| 270 | levels.pop(i) |
||
| 271 | levels.insert(1, level) |
||
| 272 | with open(path, 'w') as outfile: |
||
| 273 | json.dump(levels, outfile) |
||
| 274 | |||
| 275 | await self.send_message(f'{lname} is now up next!', ctx) |
||
| 276 | break |
||
| 277 | i += 1 |
||
| 278 | else: |
||
| 279 | self.send_message(f'Invalid syntax: {self.settings[5]}promote [level name, url or id]',ctx) |
||
| 280 | |||
| 281 | @commands.command(name='list',aliases=['queue','q']) |
||
| 282 | async def list(self,ctx): |
||
| 283 | with open(path,'r') as infile: |
||
| 284 | levels = json.load(infile) |
||
| 285 | out = "" |
||
| 286 | i = 1 |
||
| 287 | if len(levels) > 0: |
||
| 288 | if levels[len(levels) - 1] == False: |
||
| 289 | levels = levels[:len(levels) - 1] |
||
| 290 | if len(levels) <= int(self.settings[4]): |
||
| 291 | for level in levels: |
||
| 292 | out += "{3} - Level: '{0}' - Made by: '{1}' - Submitted by: '{2}' ".format(level['levelName'],level['levelMakerName'],level['submitterName'],i) |
||
| 293 | i += 1 |
||
| 294 | await self.send_message(out,ctx) |
||
| 295 | else: |
||
| 296 | for level in levels: |
||
| 297 | if i <= int(self.settings[4]): |
||
| 298 | out += "{3} - Level: '{0}' - Made by: '{1}' - Submitted by: '{2}' ".format(level['levelName'],level['levelMakerName'],level['submitterName'],i) |
||
| 299 | i += 1 |
||
| 300 | if i > int(self.settings[4]): |
||
| 301 | ileft = i - int(self.settings[4]) |
||
| 302 | out += f" And {ileft} more levels in queue." |
||
| 303 | await self.send_message(out,ctx) |
||
| 304 | else: |
||
| 305 | await ctx.send('The queue is currently empty.') |
||
| 306 | |||
| 307 | @commands.command(name='mylist',aliases=['myqueue','myq']) |
||
| 308 | async def mylist(self,ctx): |
||
| 309 | with open(path,'r') as infile: |
||
| 310 | levels = json.load(infile) |
||
| 311 | out = "" |
||
| 312 | lInQueue = False |
||
| 313 | i = 1 |
||
| 314 | if len(levels) > 0: |
||
| 315 | if levels[len(levels) - 1] == False: |
||
| 316 | levels = levels[:len(levels) - 1] |
||
| 317 | if len(levels) <= int(self.settings[4]): |
||
| 318 | for level in levels: |
||
| 319 | if level['twitchID'] == ctx.author.id: |
||
| 320 | out += "{3} - Level: '{0}' - Made by: '{1}' - Submitted by: '{2}' ".format(level['levelName'],level['levelMakerName'],level['submitterName'],i) |
||
| 321 | lInQueue = True |
||
| 322 | i += 1 |
||
| 323 | if out != "" and lInQueue: |
||
| 324 | await self.send_message(out,ctx) |
||
| 325 | else: |
||
| 326 | await self.send_message('{} has no levels in the queue.'.format(ctx.author.display_name),ctx) |
||
| 327 | else: |
||
| 328 | for level in levels: |
||
| 329 | if i <= int(self.settings[4]): |
||
| 330 | if level['twitchID'] == ctx.author.id: |
||
| 331 | out += "{3} - Level: '{0}' - Made by: '{1}' - Submitted by: '{2}' ".format(level['levelName'],level['levelMakerName'],level['submitterName'],i) |
||
| 332 | lInQueue = True |
||
| 333 | else: |
||
| 334 | ileft = i - int(self.settings[4]) |
||
| 335 | out += f" And {ileft} more levels in queue." |
||
| 336 | break |
||
| 337 | i += 1 |
||
| 338 | if out != "" and lInQueue: |
||
| 339 | await self.send_message(out,ctx) |
||
| 340 | else: |
||
| 341 | await self.send_message('{} has no levels in the queue.'.format(ctx.author.display_name),ctx) |
||
| 342 | else: |
||
| 343 | await ctx.send('The queue is currently empty.') |
||
| 344 | |||
| 345 | @commands.command(name='lock') |
||
| 346 | async def lock(self, ctx): |
||
| 347 | if ctx.author.is_mod: |
||
| 348 | with open(path, 'r') as infile: |
||
| 349 | levels = json.load(infile) |
||
| 350 | if len(levels) > 0: |
||
| 351 | if levels[len(levels) - 1] == False: |
||
| 352 | await self.send_message('Queue was already locked', ctx) |
||
| 353 | return |
||
| 354 | else: |
||
| 355 | levels.append(False) |
||
| 356 | with open(path, 'w') as outfile: |
||
| 357 | json.dump(levels, outfile) |
||
| 358 | await self.send_message('Succesfully locked queue', ctx) |
||
| 359 | else: |
||
| 360 | levels.append(False) |
||
| 361 | with open(path, 'w') as outfile: |
||
| 362 | json.dump(levels, outfile) |
||
| 363 | await self.send_message('Succesfully locked queue', ctx) |
||
| 364 | |||
| 365 | @commands.command(name='unlock') |
||
| 366 | async def unlock(self, ctx): |
||
| 367 | if ctx.author.is_mod: |
||
| 368 | with open(path, 'r') as infile: |
||
| 369 | levels = json.load(infile) |
||
| 370 | if len(levels) > 0: |
||
| 371 | if levels[len(levels) - 1] == False: |
||
| 372 | levels.pop(len(levels) - 1) |
||
| 373 | with open(path, 'w') as outfile: |
||
| 374 | json.dump(levels, outfile) |
||
| 375 | await self.send_message('Succesfully unlocked queue', ctx) |
||
| 376 | else: |
||
| 377 | await self.send_message('Queue was already unlocked', ctx) |
||
| 378 | else: |
||
| 379 | await self.send_message('Queue was already unlocked', ctx) |
||
| 380 | |||
| 381 | @commands.command(name='next', aliases=['skip']) |
||
| 382 | async def next(self, ctx): |
||
| 383 | if ctx.author.is_mod: |
||
| 384 | with open(path, 'r') as infile: |
||
| 385 | levels = json.load(infile) |
||
| 386 | if len(levels) > 0: |
||
| 387 | if levels[0] != False: |
||
| 388 | levels.pop(0) |
||
| 389 | with open(path, 'w') as outfile: |
||
| 390 | json.dump(levels, outfile) |
||
| 391 | await self.send_message('Succesfully skipped level', ctx) |
||
| 392 | return |
||
| 393 | await self.send_message("Couldn't skip level due to the queue being empty", ctx) |
||
| 394 | |||
| 395 | @commands.command(name='clear',aliases=['reset','empty','init']) |
||
| 396 | async def clear(self,ctx): |
||
| 397 | if ctx.author.is_mod: |
||
| 398 | with open(path,'w') as outfile: |
||
| 399 | outfile.write('[]') |
||
| 400 | await ctx.send('Succesfully cleared queue!') |
||
| 401 | |||
| 402 | @commands.command(name='current',aliases=['currentlevel','np','nowplaying','now']) |
||
| 403 | async def current(self,ctx): |
||
| 404 | with open(path,'r') as infile: |
||
| 405 | levels = json.load(infile) |
||
| 406 | if len(levels) > 0 and levels[0] != False: |
||
| 407 | await self.send_message('The current level is "{0}" by "{1}" submitted by "{2}" link {3}.'.format(levels[0]['levelName'],levels[0]['levelMakerName'],levels[0]['submitterName'],levels[0]['link']),ctx) |
||
| 408 | else: |
||
| 409 | await ctx.send('The queue is currently empty.') |
||
| 410 | |||
| 411 | |||
| 412 | if len(argv) < 2: |
||
| 413 | path = os.path.dirname(os.path.abspath(__file__)) + "/dir/levels.json" |
||
| 414 | else: |
||
| 415 | path = argv[1] |
||
| 416 | |||
| 417 | if len(argv) < 3: |
||
| 418 | path3 = os.path.dirname(os.path.abspath(__file__)) + '/dir' |
||
| 419 | else: |
||
| 420 | path3 = argv[2] |
||
| 421 | |||
| 422 | favicon = os.path.dirname(os.path.abspath(__file__)) + '/imgs/favicon.ico' |
||
| 423 | |||
| 424 | with open(path3 + '/def.txt', 'r') as infile: |
||
| 425 | default = infile.read() |
||
| 426 | |||
| 427 | with open(path3 + '/settings.txt', 'r') as infile: |
||
| 428 | settings = infile.read() |
||
| 429 | mat = findall(r'"(.+?)"', settings) |
||
| 430 | if len(mat) < 7 or default == settings: |
||
| 431 | input('Error, please fill settings.txt completely in first. ') |
||
| 432 | exit() |
||
| 433 | |||
| 434 | class run_bot(threading.Thread): |
||
| 435 | def __init__(self, name): |
||
| 436 | threading.Thread.__init__(self) |
||
| 437 | self.name = name |
||
| 438 | self.bot = Bot() |
||
| 439 | |||
| 440 | def run(self): |
||
| 441 | try: |
||
| 442 | self.bot.run() |
||
| 443 | finally: |
||
| 444 | exit() |
||
| 445 | |||
| 446 | def stop(self): |
||
| 447 | self.bot.close() |
||
| 448 | |||
| 449 | class run_serv(threading.Thread): |
||
| 450 | def __init__(self, name): |
||
| 451 | threading.Thread.__init__(self) |
||
| 452 | self.name = name |
||
| 453 | |||
| 454 | def run(self): |
||
| 455 | |||
| 456 | class getHandler(http.server.SimpleHTTPRequestHandler): |
||
| 457 | |||
| 458 | def do_GET(self): |
||
| 459 | try: |
||
| 460 | http.server.SimpleHTTPRequestHandler.do_GET(self) |
||
| 461 | except ConnectionAbortedError: |
||
| 462 | pass |
||
| 463 | except FileNotFoundError: |
||
| 464 | pass |
||
| 465 | try: |
||
| 466 | mat = findall(r"/dashboard.html\?removeLevelId=([\w]+)", self.path) |
||
| 467 | if mat: |
||
| 468 | try: |
||
| 469 | removeIndex = int(mat[0]) |
||
| 470 | except ValueError: |
||
| 471 | if mat[0] == 'all': |
||
| 472 | with open(path,'w') as outfile: |
||
| 473 | outfile.write('[]') |
||
| 474 | elif mat[0] == 'lock': |
||
| 475 | with open(path, 'r') as infile: |
||
| 476 | levels = json.loads(infile.read()) |
||
| 477 | try: |
||
| 478 | if levels[len(levels) - 1] == False: |
||
| 479 | levels.pop(len(levels) - 1) |
||
| 480 | else: |
||
| 481 | levels.append(False) |
||
| 482 | except IndexError: |
||
| 483 | levels.append(False) |
||
| 484 | with open(path, 'w') as outfile: |
||
| 485 | json.dump(levels, outfile) |
||
| 486 | else: |
||
| 487 | with open(path,'r') as infile: |
||
| 488 | levels = json.load(infile) |
||
| 489 | if levels[removeIndex] != False: |
||
| 490 | levels.pop(removeIndex) |
||
| 491 | with open(path,'w') as outfile: |
||
| 492 | json.dump(levels,outfile) |
||
| 493 | else: |
||
| 494 | mat = findall(r"/dashboard.html\?promoteLevelId=([\w]+)", self.path) |
||
| 495 | if mat: |
||
| 496 | with open(path, 'r') as infile: |
||
| 497 | levels = json.load(infile) |
||
| 498 | i = int(mat[0]) - 1 |
||
| 499 | if i != 0 or i + 1 < len(levels): |
||
| 500 | level = levels[i] |
||
| 501 | levels.pop(i) |
||
| 502 | levels.insert(1, level) |
||
| 503 | with open(path, 'w') as outfile: |
||
| 504 | json.dump(levels, outfile) |
||
| 505 | |||
| 506 | mat = findall(r"\/dashboard\.html\?levelName=(.*?)&levelMakerName=(.*?)&submitterName=(.*?)&link=(.*?)&d=", self.path) |
||
| 507 | if mat: |
||
| 508 | link = mat[0][3] |
||
| 509 | levelName = mat[0][0].replace('+',' ') |
||
| 510 | levelMakerName = mat[0][1].replace('+', ' ') |
||
| 511 | submitterName = mat[0][2].replace('+', ' ') |
||
| 512 | |||
| 513 | l = {'link':link,'levelName':levelName,'twitchID':None,'levelMakerName':levelMakerName,'submitterName':submitterName} |
||
| 514 | with open(path,'r') as infile: |
||
| 515 | levels = json.load(infile) |
||
| 516 | levels.append(l) |
||
| 517 | with open(path,'w') as outfile: |
||
| 518 | json.dump(levels,outfile) |
||
| 519 | |||
| 520 | except Exception: |
||
| 521 | pass |
||
| 522 | |||
| 523 | def do_HEAD(self): |
||
| 524 | http.server.SimpleHTTPRequestHandler.do_HEAD(self) |
||
| 525 | |||
| 526 | def log_message(self, format, *args): |
||
| 527 | return |
||
| 528 | |||
| 529 | def log_error(self, format, *args): |
||
| 530 | return |
||
| 531 | |||
| 532 | try: |
||
| 533 | Handler = getHandler |
||
| 534 | PORT = 8000 |
||
| 535 | os.chdir(str(path3)) |
||
| 536 | with socketserver.TCPServer(("", PORT), Handler) as httpd: |
||
| 537 | httpd.serve_forever() |
||
| 538 | finally: |
||
| 539 | while True: |
||
| 540 | try: |
||
| 541 | httpd.shutdown() |
||
| 542 | except Exception: |
||
| 543 | pass |
||
| 544 | else: |
||
| 545 | break |
||
| 546 | exit() |
||
| 547 | |||
| 548 | def get_id(self): |
||
| 549 | # returns id of the respective thread |
||
| 550 | for id, thread in threading._active.items(): |
||
| 551 | if thread is self: |
||
| 552 | return id |
||
| 553 | |||
| 554 | def stop(self): |
||
| 555 | thread_id = self.get_id() |
||
| 556 | res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id,ctypes.py_object(SystemExit)) |
||
| 557 | if res > 1: |
||
| 558 | ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0) |
||
| 559 | |||
| 560 | if __name__ == '__main__': |
||
| 561 | |||
| 562 | rbot = run_bot('twitch') |
||
| 563 | rserv = run_serv('localhost') |
||
| 564 | rbot.start() |
||
| 565 | rserv.start() |
||
| 566 | time.sleep(1) |
||
| 567 | webbrowser.open('http://localhost:8000/dashboard.html') |
||
| 568 |