From ac397afd833243d4e650510a8e9c71ced1a5ea5d Mon Sep 17 00:00:00 2001 From: acidvegas Date: Fri, 2 Jun 2023 01:43:45 -0400 Subject: [PATCH] Initial commit --- .screens/preview.png | Bin 0 -> 12085 bytes LICENSE | 15 +++ README.md | 26 ++++ scroll.py | 284 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 325 insertions(+) create mode 100644 .screens/preview.png create mode 100644 LICENSE create mode 100644 README.md create mode 100644 scroll.py diff --git a/.screens/preview.png b/.screens/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..0321f8fb034516dfa5ce4fd219e44316c1ddec8c GIT binary patch literal 12085 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 Q%)vvT%G$R|Zr*wHUpf`{uK)l5 literal 0 HcmV?d00001 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..881204a --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2021, acidvegas + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9187135 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# scroll + +Scroll is full-featured IRC bot that carries a **PENIS PUMP** & will brighten up all the mundane chats in your lame IRC channels with some colorful IRC artwork! Designed to be extremely stable, this bot is sure to stay rock hard & handle itself quite well! + +All of the IRC art is loaded directly from the [@ircart/ircart](https://github.com/ircart/ircart) repository. + +## Dependencies +* [python](https://www.python.org/) +* [chardet](https://pypi.org/project/chardet/) *(`pip install chardet`)* + +## Commands +| Command | Description | +| --------------------------------- | ---------------------------------------------------------- | +| `@scroll` | information about scroll | +| `.ascii ` | play the \ art file | +| `.ascii dirs` | list of ascii directories | +| `.ascii list` | list of ascii filenames | +| `.ascii random [dir]` | play random art, optionally from the [dir] directory only | +| `.ascii search ` | search for art diles that match \ | +| `.ascii stop` | stop playing art | + +## Mirrors +- [acid.vegas](https://git.acid.vegas/scroll) +- [GitHub](https://github.com/ircart/scroll) +- [GitLab](https://gitlab.com/ircart/scroll) +- [SuperNETs](https://git.supernets.org/ircart/scroll) \ No newline at end of file diff --git a/scroll.py b/scroll.py new file mode 100644 index 0000000..3afb8d9 --- /dev/null +++ b/scroll.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python +# Scroll IRC Art Bot - Developed by acidvegas in Python (https://git.acid.vegas/scroll) + +import asyncio +import random +import ssl +import time +import urllib.request + +class connection: + server = 'irc.network.com' + port = 6697 + ipv6 = False + ssl = True + vhost = None + channel = '#chats' + key = None + modes = None + +class identity: + nickname = 'scroll' + username = 'scroll' + realname = 'git.acid.vegas/scroll' + nickserv = None + +class throttle: + flood = 3 # delay between each command + max_lines = 300 # maximum number of lines in art file to be played outside of #scroll + message = 0.05 # delay between each line sent + results = 10 # maximum number of results returned from search + +# Formatting Control Characters / Color Codes +bold = '\x02' +italic = '\x1D' +underline = '\x1F' +reverse = '\x16' +reset = '\x0f' +white = '00' +black = '01' +blue = '02' +green = '03' +red = '04' +brown = '05' +purple = '06' +orange = '07' +yellow = '08' +light_green = '09' +cyan = '10' +light_cyan = '11' +light_blue = '12' +pink = '13' +grey = '14' +light_grey = '15' + +def color(msg, foreground, background=None): + return f'\x03{foreground},{background}{msg}{reset}' if background else f'\x03{foreground}{msg}{reset}' + +def debug(data): + print('{0} | [~] - {1}'.format(time.strftime('%I:%M:%S'), data)) + +def error(data, reason=None): + 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)) + +def ssl_ctx(): + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + return ctx + +class Bot(): + def __init__(self): + self.db = dict() + self.last = 0 + self.loops = dict() + self.playing = False + self.slow = False + self.reader = None + self.writer = None + + async def raw(self, data): + self.writer.write(data[:510].encode('utf-8') + b'\r\n') + await self.writer.drain() + + async def action(self, chan, msg): + await self.sendmsg(chan, f'\x01ACTION {msg}\x01') + + async def sendmsg(self, target, msg): + await self.raw(f'PRIVMSG {target} :{msg}') + + async def irc_error(self, chan, msg, reason=None): + 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)) + + async def connect(self): + while True: + try: + options = { + 'host' : connection.server, + 'port' : connection.port, + 'limit' : 1024, + 'ssl' : ssl_ctx() if connection.ssl else None, + 'family' : 10 if connection.ipv6 else 2, + 'local_addr' : connection.vhost + } + self.reader, self.writer = await asyncio.wait_for(asyncio.open_connection(**options), 15) + await self.raw(f'USER {identity.username} 0 * :{identity.realname}') + await self.raw('NICK ' + identity.nickname) + except Exception as ex: + error('failed to connect to ' + connection.server, ex) + else: + await self.listen() + finally: + self.loops = dict() + self.playing = False + self.slow = False + await asyncio.sleep(30) + + async def sync(self): + try: + cache = self.db + self.db = dict() + ascii = urllib.request.urlopen('https://raw.githubusercontent.com/ircart/ircart/master/ircart/.list').readlines() + for item in ascii: + item = item.decode(chardet.detect(item)['encoding']).replace('\n','').replace('\r','') + if '/' in item: + dir = item.split('/')[0] + name = item.split('/')[1] + self.db[dir] = self.db[dir]+[name,] if dir in self.db else [name,] + else: + self.db['root'] = self.db['root']+[item,] if 'root' in self.db else [item,] + except Exception as ex: + try: + await self.irc_error(connection.channel, 'failed to sync database', ex) + except: + error(connection.channel, 'failed to sync database', ex) + self.db = cache + + async def play(self, chan, name): + try: + ascii = urllib.request.urlopen(f'https://raw.githubusercontent.com/ircart/ircart/master/ircart/{name}.txt', timeout=10) + if ascii.getcode() == 200: + ascii = ascii.readlines() + if len(ascii) > throttle.max_lines and chan != '#scroll': + await self.irc_error(chan, 'file is too big', 'take it to #scroll') + else: + await self.action(chan, 'the ascii gods have chosen... ' + color(name, cyan)) + for line in ascii: + await self.sendmsg(chan, line.decode(chardet.detect(line)['encoding']).replace('\n','').replace('\r','') + reset) + await asyncio.sleep(throttle.message) + else: + await self.irc_error(chan, 'invalid name', name) + except Exception as ex: + try: + await self.irc_error(chan, 'error in play function', ex) + except: + error('error in play function', ex) + finally: + self.playing = False + + async def listen(self): + while True: + try: + if self.reader.at_eof(): + break + data = await asyncio.wait_for(self.reader.readuntil(b'\r\n'), 200) + line = data.decode('utf-8').strip() + args = line.split() + debug(line) + if line.startswith('ERROR :Closing Link:'): + raise Exception('Connection has closed.') + elif args[0] == 'PING': + await self.raw('PONG '+args[1][1:]) + elif args[1] == '001': + if connection.modes: + await self.raw(f'MODE {identity.nickname} +{connection.modes}') + if identity.nickserv: + await self.sendmsg('NickServ', f'IDENTIFY {identity.nickname} {identity.nickserv}') + await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel) + await self.raw('JOIN #scroll') + await self.sync() + elif args[1] == '433': + error('The bot is already running or nick is in use.') + elif args[1] == 'INVITE' and len(args) == 4: + invited = args[2] + chan = args[3][1:] + if invited == identity.nickname and chan in (connection.channel, '#scroll'): + await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel) + elif args[1] == 'KICK' and len(args) >= 4: + chan = args[2] + kicked = args[3] + if kicked == identity.nickname and chan in (connection.channel,'#scroll'): + await asyncio.sleep(3) + await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel) + elif args[1] == 'PRIVMSG' and len(args) >= 4: + nick = args[0].split('!')[0][1:] + chan = args[2] + msg = ' '.join(args[3:])[1:] + if chan in (connection.channel, '#scroll'): + args = msg.split() + if msg == '@cancer': + await self.sendmsg(chan, bold + 'CANCER IRC Bot - Developed by acidvegas in Python - https://git.acid.vegas/cancer') + elif args[0] == '.ascii': + if msg == '.ascii stop' and self.playing: + if chan in self.loops: + self.loops[chan].cancel() + elif time.time() - self.last < throttle.flood: + if not self.slow: + if not self.playing: + await self.irc_error(chan, 'slow down nerd') + self.slow = True + elif len(args) >= 2 and not self.playing: + self.slow = False + if msg == '.ascii dirs': + for dir in self.db: + await self.sendmsg(chan, '[{0}] {1}{2}'.format(color(str(list(self.db).index(dir)+1).zfill(2), pink), dir.ljust(10), color('('+str(len(self.db[dir]))+')', grey))) + await asyncio.sleep(throttle.message) + elif msg == '.ascii list': + await self.sendmsg(chan, underline + color('https://raw.githubusercontent.com/ircart/ircart/master/ircart/.list', light_blue)) + elif msg == '.ascii random': + self.playing = True + dir = random.choice(list(self.db)) + ascii = random.choice(self.db[dir]) if dir == 'root' else dir+'/'+random.choice(self.db[dir]) + self.loops[chan] = asyncio.create_task(self.play(chan, ascii)) + elif args[1] == 'random' and len(args) == 3: + dir = args[2] + if dir in self.db: + self.playing = True + ascii = random.choice(self.db[dir]) + self.loops[chan] = asyncio.create_task(self.play(chan, dir+'/'+ascii)) + else: + await self.irc_error(chan, 'invalid directory name', dir) + elif args[1] == 'search' and len(args) == 3: + query = args[2] + results = list() + for dir in self.db: + for ascii in self.db[dir]: + if query in ascii: + results.append({'dir':dir,'name':ascii}) + if results: + for item in results[:throttle.results]: + if item['dir'] == 'root': + await self.sendmsg(chan, '[{0}] {1}'.format(color(str(results.index(item)+1).zfill(2), pink), item['name'])) + else: + await self.sendmsg(chan, '[{0}] {1} {2}'.format(color(str(results.index(item)+1).zfill(2), pink), item['name'], color('('+item['dir']+')', grey))) + await asyncio.sleep(throttle.message) + else: + await self.irc_error(chan, 'no results found', query) + elif len(args) == 2: + option = args[1] + if [x for x in ('..','?','%','\\') if x in option]: + await self.irc_error(chan, 'nice try nerd') + elif option == 'random': + self.playing = True + self.loops[chan] = asyncio.create_task(self.play(chan, random.choice(self.db))) + else: + ascii = [dir+'/'+option for dir in self.db if option in self.db[dir]][0] + if ascii: + if ascii.startswith('root/'): + ascii = ascii.split('/')[1] + self.playing = True + self.loops[chan] = asyncio.create_task(self.play(chan, ascii)) + else: + await self.irc_error(chan, 'no results found', option) + except (UnicodeDecodeError, UnicodeEncodeError): + pass + except Exception as ex: + error('fatal error occured', ex) + break + finally: + self.last = time.time() + +# Main +print('#'*56) +print('#{:^54}#'.format('')) +print('#{:^54}#'.format('Scroll IRC Art Bot')) +print('#{:^54}#'.format('Developed by acidvegas in Python')) +print('#{:^54}#'.format('https://git.acid.vegas/scroll')) +print('#{:^54}#'.format('')) +print('#'*56) +try: + import chardet +except ImportError: + raise SystemExit('missing required \'chardet\' library (https://pypi.org/project/chardet/)') +else: + asyncio.run(Bot().connect()) \ No newline at end of file