mirror of
git://git.acid.vegas/scroll.git
synced 2024-11-21 23:56:39 +00:00
Added admin, settings viewing & changing, code cleanup, README updated
This commit is contained in:
parent
9d120737c3
commit
a57316332f
35
README.md
35
README.md
@ -11,20 +11,33 @@ There is no API key needed, no local art files needed, & no reason to not setup
|
|||||||
* [chardet](https://pypi.org/project/chardet/) *(`pip install chardet`)*
|
* [chardet](https://pypi.org/project/chardet/) *(`pip install chardet`)*
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
| ------------------------ | ---------------------------------------------------------- |
|
| ------------------------------------ | ---------------------------------------------------------- |
|
||||||
| `@scroll` | information about scroll |
|
| `@scroll` | information about scroll |
|
||||||
| `.ascii <name>` | play the \<name> art file |
|
| `.ascii <name>` | play the \<name> art file |
|
||||||
| `.ascii dirs` | list of art directories |
|
| `.ascii dirs` | list of art directories |
|
||||||
| `.ascii list` | list of art filenames |
|
| `.ascii list` | list of art filenames |
|
||||||
| `.ascii play <url>` | play the contents of \<url> *(must be a raw pastebin url)* |
|
| `.ascii play <url>` | play the contents of \<url> *(must be a raw pastebin url)* |
|
||||||
| `.ascii random [dir]` | play random art, optionally from the [dir] directory only |
|
| `.ascii random [dir]` | play random art, optionally from the [dir] directory only |
|
||||||
| `.ascii search <query>` | search for art diles that match \<query> |
|
| `.ascii settings` | view settings |
|
||||||
| `.ascii stop` | stop playing art |
|
| `.ascii settings <setting> <option>` | change \<setting> to \<option> |
|
||||||
| `.ascii sync` | sync the ascii database to pump the newest art |
|
| `.ascii stop` | stop playing art |
|
||||||
|
| `.ascii sync` | sync the ascii database to pump the newest art |
|
||||||
|
|
||||||
**NOTE**: You can do `.ascii help` to play the [help.txt](https://github.com/ircart/ircart/blob/master/ircart/doc/help.txt) file in your channel.
|
**NOTE**: You can do `.ascii help` to play the [help.txt](https://github.com/ircart/ircart/blob/master/ircart/doc/help.txt) file in your channel.
|
||||||
|
|
||||||
|
**NOTE**: The sync & settings commands are admin only! `admin` is a *nick!user@host* mask defined in [scroll.py](https://github.com/ircart/scroll/blob/master/scroll.py)
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
| Setting | Description |
|
||||||
|
| --------- | ---------------------------------------------------------------------------- |
|
||||||
|
| `flood` | delay between each command |
|
||||||
|
| `ignore` | directories to ignore in `.ascii random` *(comma seperated list, no spaces)* |
|
||||||
|
| `lines` | max lines outside of #scroll |
|
||||||
|
| `msg` | delay between each message sent |
|
||||||
|
| `results` | max results to return in `.ascii search` |
|
||||||
|
| `paste` | enable or disable `.ascii play` |
|
||||||
|
|
||||||
## Preview
|
## Preview
|
||||||
|
|
||||||
![](.screens/preview.png)
|
![](.screens/preview.png)
|
||||||
|
83
scroll.py
83
scroll.py
@ -4,19 +4,20 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
import ssl
|
import ssl
|
||||||
import time
|
import time
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
class connection:
|
class connection:
|
||||||
server = 'irc.network.com'
|
server = 'irc.server.com'
|
||||||
port = 6697
|
port = 6697
|
||||||
ipv6 = False
|
ipv6 = False
|
||||||
ssl = True
|
ssl = True
|
||||||
vhost = None
|
vhost = None
|
||||||
channel = '#chats'
|
channel = '#chats'
|
||||||
key = None
|
key = None
|
||||||
modes = None
|
modes = 'BdDg'
|
||||||
|
|
||||||
class identity:
|
class identity:
|
||||||
nickname = 'scroll'
|
nickname = 'scroll'
|
||||||
@ -24,12 +25,8 @@ class identity:
|
|||||||
realname = 'git.acid.vegas/scroll'
|
realname = 'git.acid.vegas/scroll'
|
||||||
nickserv = None
|
nickserv = None
|
||||||
|
|
||||||
class throttle:
|
# Settings
|
||||||
flood = 2 # delay between each command
|
admin = 'acidvegas!~stillfree@most.dangerous.motherfuck' # CHANGE ME
|
||||||
max_lines = 300 # maximum number of lines in art file to be played outside of #scroll
|
|
||||||
message = 0.03 # delay between each line sent
|
|
||||||
results = 25 # maximum number of results returned from search
|
|
||||||
pastes = True # toggle the .ascii play command
|
|
||||||
|
|
||||||
# Formatting Control Characters / Color Codes
|
# Formatting Control Characters / Color Codes
|
||||||
bold = '\x02'
|
bold = '\x02'
|
||||||
@ -63,6 +60,9 @@ def debug(data):
|
|||||||
def error(data, reason=None):
|
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))
|
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 is_admin(ident):
|
||||||
|
return re.compile(admin.replace('*','.*')).search(ident)
|
||||||
|
|
||||||
def ssl_ctx():
|
def ssl_ctx():
|
||||||
ctx = ssl.create_default_context()
|
ctx = ssl.create_default_context()
|
||||||
ctx.check_hostname = False
|
ctx.check_hostname = False
|
||||||
@ -72,9 +72,10 @@ def ssl_ctx():
|
|||||||
class Bot():
|
class Bot():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db = None
|
self.db = None
|
||||||
self.last = 0
|
self.last = time.time()
|
||||||
self.loops = dict()
|
self.loops = dict()
|
||||||
self.playing = False
|
self.playing = False
|
||||||
|
self.settings = {'flood':1, 'ignore':'big,birds,doc,gorf,hang,nazi,pokemon', 'lines':300, 'msg':0.03, 'results':25, 'paste':True}
|
||||||
self.slow = False
|
self.slow = False
|
||||||
self.reader = None
|
self.reader = None
|
||||||
self.writer = None
|
self.writer = None
|
||||||
@ -145,22 +146,23 @@ class Bot():
|
|||||||
async def play(self, chan, name, paste=None):
|
async def play(self, chan, name, paste=None):
|
||||||
try:
|
try:
|
||||||
if paste:
|
if paste:
|
||||||
ascii = urllib.request.urlopen(name), timeout=10)
|
ascii = urllib.request.urlopen(name, timeout=10)
|
||||||
else:
|
else:
|
||||||
ascii = urllib.request.urlopen(f'https://raw.githubusercontent.com/ircart/ircart/master/ircart/{name}.txt', timeout=10)
|
ascii = urllib.request.urlopen(f'https://raw.githubusercontent.com/ircart/ircart/master/ircart/{name}.txt', timeout=10)
|
||||||
if ascii.getcode() == 200:
|
if ascii.getcode() == 200:
|
||||||
ascii = ascii.readlines()
|
ascii = ascii.readlines()
|
||||||
if len(ascii) > throttle.max_lines and chan != '#scroll':
|
if len(ascii) > int(self.settings['lines']) and chan != '#scroll':
|
||||||
await self.irc_error(chan, 'file is too big', 'take it to #scroll')
|
await self.irc_error(chan, 'file is too big', 'take it to #scroll')
|
||||||
else:
|
else:
|
||||||
await self.action(chan, 'the ascii gods have chosen... ' + color(name, cyan))
|
await self.action(chan, 'the ascii gods have chosen... ' + color(name, cyan))
|
||||||
for line in ascii:
|
for line in ascii:
|
||||||
|
line = line.replace('\n','').replace('\r','')
|
||||||
try:
|
try:
|
||||||
line = line.decode().replace('\n','').replace('\r','')
|
line = line.decode()
|
||||||
else:
|
except:
|
||||||
line = line.encode(chardet.detect(line)['encoding']).decode() # Get fucked UTF-16
|
line = line.encode(chardet.detect(line)['encoding']).decode() # Get fucked UTF-16
|
||||||
await self.sendmsg(chan, line + reset)
|
await self.sendmsg(chan, line + reset)
|
||||||
await asyncio.sleep(throttle.message)
|
await asyncio.sleep(self.settings['msg'])
|
||||||
else:
|
else:
|
||||||
await self.irc_error(chan, 'invalid name', name)
|
await self.irc_error(chan, 'invalid name', name)
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
@ -206,9 +208,10 @@ class Bot():
|
|||||||
await asyncio.sleep(3)
|
await asyncio.sleep(3)
|
||||||
await self.raw(f'JOIN {connection.channel} {connection.key}') if connection.key else await self.raw('JOIN ' + connection.channel)
|
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:
|
elif args[1] == 'PRIVMSG' and len(args) >= 4:
|
||||||
nick = args[0].split('!')[0][1:]
|
ident = args[0][1:]
|
||||||
chan = args[2]
|
nick = args[0].split('!')[0][1:]
|
||||||
msg = ' '.join(args[3:])[1:]
|
chan = args[2]
|
||||||
|
msg = ' '.join(args[3:])[1:]
|
||||||
if chan in (connection.channel, '#scroll'):
|
if chan in (connection.channel, '#scroll'):
|
||||||
args = msg.split()
|
args = msg.split()
|
||||||
if msg == '@scroll':
|
if msg == '@scroll':
|
||||||
@ -218,7 +221,7 @@ class Bot():
|
|||||||
if self.playing:
|
if self.playing:
|
||||||
if chan in self.loops:
|
if chan in self.loops:
|
||||||
self.loops[chan].cancel()
|
self.loops[chan].cancel()
|
||||||
elif time.time() - self.last < throttle.flood:
|
elif time.time() - self.last < self.settings['flood']:
|
||||||
if not self.slow:
|
if not self.slow:
|
||||||
if not self.playing:
|
if not self.playing:
|
||||||
await self.irc_error(chan, 'slow down nerd')
|
await self.irc_error(chan, 'slow down nerd')
|
||||||
@ -228,23 +231,23 @@ class Bot():
|
|||||||
if msg == '.ascii dirs':
|
if msg == '.ascii dirs':
|
||||||
for dir in self.db:
|
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 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)
|
await asyncio.sleep(self.settings['msg'])
|
||||||
elif msg == '.ascii list':
|
elif msg == '.ascii list':
|
||||||
await self.sendmsg(chan, underline + color('https://raw.githubusercontent.com/ircart/ircart/master/ircart/.list', light_blue))
|
await self.sendmsg(chan, underline + color('https://raw.githubusercontent.com/ircart/ircart/master/ircart/.list', light_blue))
|
||||||
elif msg == '.ascii random':
|
elif msg == '.ascii random':
|
||||||
self.playing = True
|
self.playing = True
|
||||||
dir = random.choice(list(self.db))
|
dir = random.choice([item for item in self.db if item not in self.settings['ignore']])
|
||||||
ascii = f'{dir}/{random.choice(self.db[dir])}'
|
ascii = f'{dir}/{random.choice(self.db[dir])}'
|
||||||
self.loops[chan] = asyncio.create_task(self.play(chan, ascii))
|
self.loops[chan] = asyncio.create_task(self.play(chan, ascii))
|
||||||
elif msg == '.ascii sync':
|
elif msg == '.ascii sync' and is_admin(ident):
|
||||||
await self.sync()
|
await self.sync()
|
||||||
await self.sendmsg(chan, bold + color('database synced', light_green))
|
await self.sendmsg(chan, bold + color('database synced', light_green))
|
||||||
elif args[1] == 'play' and len(args) == 3 and throttle.pastes:
|
elif args[1] == 'play' and len(args) == 3 and self.settings['paste']:
|
||||||
url = args[2]
|
url = args[2]
|
||||||
if url.startswith('https://pastebin.com/raw/') and len(url.split('raw/')) > 1:
|
if url.startswith('https://pastebin.com/raw/') and len(url.split('raw/')) > 1:
|
||||||
self.loops[chan] = asyncio.create_task(self.play(chan, url, paste=True))
|
self.loops[chan] = asyncio.create_task(self.play(chan, url, paste=True))
|
||||||
else:
|
else:
|
||||||
await self.irc_error(chan 'invalid pastebin url', paste)
|
await self.irc_error(chan, 'invalid pastebin url', paste)
|
||||||
elif args[1] == 'random' and len(args) == 3:
|
elif args[1] == 'random' and len(args) == 3:
|
||||||
dir = args[2]
|
dir = args[2]
|
||||||
if dir in self.db:
|
if dir in self.db:
|
||||||
@ -257,14 +260,42 @@ class Bot():
|
|||||||
query = args[2]
|
query = args[2]
|
||||||
results = [{'name':ascii,'dir':dir} for dir in self.db for ascii in self.db[dir] if query in ascii]
|
results = [{'name':ascii,'dir':dir} for dir in self.db for ascii in self.db[dir] if query in ascii]
|
||||||
if results:
|
if results:
|
||||||
for item in results[:throttle.results]:
|
for item in results[:int(self.settings['results'])]:
|
||||||
if item['dir'] == 'root':
|
if item['dir'] == 'root':
|
||||||
await self.sendmsg(chan, '[{0}] {1}'.format(color(str(results.index(item)+1).zfill(2), pink), item['name']))
|
await self.sendmsg(chan, '[{0}] {1}'.format(color(str(results.index(item)+1).zfill(2), pink), item['name']))
|
||||||
else:
|
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 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)
|
await asyncio.sleep(self.settings['msg'])
|
||||||
else:
|
else:
|
||||||
await self.irc_error(chan, 'no results found', query)
|
await self.irc_error(chan, 'no results found', query)
|
||||||
|
elif args[1] == 'settings':
|
||||||
|
if len(args) == 2:
|
||||||
|
for item in self.settings:
|
||||||
|
await self.sendmsg(chan, color(item, yellow).ljust(10) + color(str(self.settings[item]), grey))
|
||||||
|
elif len(args) == 4 and is_admin(ident):
|
||||||
|
setting = args[2]
|
||||||
|
option = args[3]
|
||||||
|
if setting in self.settings:
|
||||||
|
if setting in ('flood','lines','msg','results'):
|
||||||
|
try:
|
||||||
|
option = float(option)
|
||||||
|
self.settings[setting] = option
|
||||||
|
await self.sendmsg(chan, color('OK', light_green))
|
||||||
|
except ValueError:
|
||||||
|
await self.sendmsg(chan, 'invalid option', 'must be a float or int')
|
||||||
|
elif setting == 'paste':
|
||||||
|
if option == 'on':
|
||||||
|
self.settings[setting] = True
|
||||||
|
await self.sendmsg(chan, color('OK', light_green))
|
||||||
|
elif option == 'off':
|
||||||
|
self.settings[setting] = False
|
||||||
|
await self.sendmsg(chan, color('OK', light_green))
|
||||||
|
else:
|
||||||
|
await self.irc_error(chan, 'invalid option', 'must be on or off')
|
||||||
|
else:
|
||||||
|
self.settings[setting] = option
|
||||||
|
else:
|
||||||
|
await self.irc_error(chan, 'invalid setting', setting)
|
||||||
elif len(args) == 2:
|
elif len(args) == 2:
|
||||||
query = args[1]
|
query = args[1]
|
||||||
results = [dir+'/'+ascii for dir in self.db for ascii in self.db[dir] if query == ascii]
|
results = [dir+'/'+ascii for dir in self.db for ascii in self.db[dir] if query == ascii]
|
||||||
|
Loading…
Reference in New Issue
Block a user