archive

- Random tools & helpful resources for IRC
git clone git://git.acid.vegas/archive.git
Log | Files | Refs | Archive

tailbot.py (4572B)

      1 #!/usr/bin/env python
      2 # Tail Bot for syn (cause fuck gh0st and his skid scripts) - Developed by acidvegas in Python (https://git.acid.vegas/archive)
      3 
      4 import asyncio
      5 import aiofiles
      6 import pathlib
      7 import ssl
      8 import time
      9 import urllib.request
     10 import os
     11 
     12 class connection:
     13 	server  = 'irc.supernets.org'
     14 	port    = 6697
     15 	ipv6    = False
     16 	ssl     = True
     17 	vhost   = None
     18 	channel = '#dev'
     19 	key     = None
     20 	modes   = None
     21 
     22 class identity:
     23 	nickname = 'TailBot'
     24 	username = 'tail'
     25 	realname = 'gh0st is a skid LOL'
     26 	nickserv = None
     27 
     28 FIFO_PATH = pathlib.Path('HPOT_FIFO')
     29 
     30 def color(msg, foreground, background=None):
     31 	return f'\x03{foreground},{background}{msg}{reset}' if background else f'\x03{foreground}{msg}{reset}'
     32 
     33 def debug(data):
     34 	print('{0} | [~] - {1}'.format(time.strftime('%I:%M:%S'), data))
     35 
     36 def error(data, reason=None):
     37 	print('{0} | [!] - {1} ({2})'.format(time.strftime('%I:%M:%S'), data, str(reason))) if reason else print('{0} | [!] - {1}'.format(time.strftime('%I:%M:%S'), data))
     38 
     39 def ssl_ctx():
     40 	ctx = ssl.create_default_context()
     41 	ctx.check_hostname = False
     42 	ctx.verify_mode = ssl.CERT_NONE
     43 	return ctx
     44 
     45 class Bot():
     46 	def __init__(self):
     47 		self.last            = 0
     48 		self.loops           = dict()
     49 		self.slow            = False
     50 		self.reader          = None
     51 		self.writer          = None
     52 
     53 	async def raw(self, data):
     54 		self.writer.write(data[:510].encode('utf-8') + b'\r\n')
     55 		await self.writer.drain()
     56 
     57 	async def sendmsg(self, target, msg):
     58 		await self.raw(f'PRIVMSG {target} :{msg}')
     59 
     60 	async def irc_error(self, chan, msg, reason=None):
     61 		await self.sendmsg(chan, '[{0}] {1} {2}'.format(color('ERROR', red), msg, color(f'({reason})', grey))) if reason else await self.sendmsg(chan, '[{0}] {1}'.format(color('ERROR', red), msg))
     62 
     63 	async def loop_tail(self):
     64 		if not os.path.exists(FIFO_PATH):
     65 			os.mkfifo(FIFO_PATH)
     66 		while True:
     67 			async with aiofiles.open(FIFO_PATH, mode='r') as fifo:
     68 				while True:
     69 					try:
     70 						content = await fifo.readlines()
     71 						for line in content:
     72 							await self.sendmsg(connection.channel, line)
     73 							await asyncio.sleep(0.1)
     74 					except Exception as ex:
     75 						try:
     76 							await self.irc_error(connection.channel, 'Error occured in the loop_tail function!', ex)
     77 							break
     78 						except:
     79 							error('Fatal error occured in the loop_tail functions!', ex)
     80 							break
     81 
     82 	async def connect(self):
     83 		while True:
     84 			try:
     85 				options = {
     86 					'host'       : connection.server,
     87 					'port'       : connection.port,
     88 					'limit'      : 1024,
     89 					'ssl'        : ssl_ctx() if connection.ssl else None,
     90 					'family'     : 10 if connection.ipv6 else 2,
     91 					'local_addr' : connection.vhost
     92 				}
     93 				self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), 300)
     94 				await self.raw(f'USER {identity.username} 0 * :{identity.realname}')
     95 				await self.raw('NICK ' + identity.nickname)
     96 			except Exception as ex:
     97 				error('failed to connect to ' + connection.server, ex)
     98 			else:
     99 				await self.listen()
    100 			finally:
    101 				self.loops   = dict()
    102 				await asyncio.sleep(30)
    103 
    104 	async def listen(self):
    105 		while True:
    106 			try:
    107 				if self.reader.at_eof():
    108 					break
    109 				data = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), 60)
    110 				line = data.decode('utf-8').strip()
    111 				args = line.split()
    112 				debug(line)
    113 				if line.startswith('ERROR :Closing Link:'):
    114 					raise Exception('Connection has closed.')
    115 				elif args[0] == 'PING':
    116 					await self.raw('PONG '+args[1][1:])
    117 				elif args[1] == '001':
    118 					await asyncio.sleep(5)
    119 					if connection.modes:
    120 						await self.raw(f'MODE {identity.nickname} +{connection.modes}')
    121 					if identity.nickserv:
    122 						await self.sendmsg('NickServ', f'IDENTIFY {identity.nickname} {identity.nickserv}')
    123 					await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel)
    124 					self.loops['tail'] = asyncio.create_task(self.loop_tail())
    125 				elif args[1] == '433':
    126 					error('The bot is already running or nick is in use.')
    127 			except (UnicodeDecodeError, UnicodeEncodeError):
    128 				pass
    129 			except Exception as ex:
    130 				error('fatal error occured', ex)
    131 				break
    132 			finally:
    133 				self.last = time.time()
    134 
    135 # Main
    136 print('#'*56)
    137 print('#{:^54}#'.format(''))
    138 print('#{:^54}#'.format('Tail IRC Bot (for syn)'))
    139 print('#{:^54}#'.format('Developed by acidvegas in Python (without 3rd party libraries cause im not a skid like gh0st)'))
    140 print('#{:^54}#'.format('https://git.acid.vegas/archive (fuck twistednet supernets wanna-be)'))
    141 print('#{:^54}#'.format(''))
    142 print('#'*56)
    143 asyncio.run(Bot().connect())