dustbot/modules/qdb.py

108 lines
2.8 KiB
Python

"""
QDB module
Grabs quotes from an online QDB database
"""
import random
import requests
import bs4
import bot
# map of supported databases
QDB_URLS = {
'xkcd':'http://www.xkcdb.com/random',
'bash':'http://www.bash.org/?random',
'qdb': 'http://www.qdb.us/random',
'wg':'https://qdb.worldgenesis.net/?random',
'tilde': 'https://quotes.tilde.chat/random'
}
@bot.command( 'qdb' )
async def get_quote( parms, ctx ):
"""
Grabs a random quote from specified quote database,
default random or database with same name as current network.
Supported databases: xkcd, bash, qdb, tilde, wg.
Does not output quotes with more than 5 lines by default unless 'spam' is first param.
"""
con = ctx['con']
dst = ctx['dst']
spam = False
db_name = ''
sv_name = con.cfg['sv']['name'].lower()
if sv_name in QDB_URLS.keys(): db_name = sv_name
if parms:
if parms[0] == 'spam':
spam = True
if len( parms ) > 1:
db_name = parms[1].lower()
else: db_name = parms[0].lower()
if not db_name: db_name = random.choice( list( QDB_URLS.keys() ) )
if db_name not in QDB_URLS.keys():
con.say_to( dst, 'No QDB known by name \'{}\'!'.format( db_name ) )
return
con.say_to( dst, 'Grabbing a quote from QDB \'{}\'...'.format( db_name ) )
req = requests.get( QDB_URLS[db_name] )
soup = bs4.BeautifulSoup( req.text, 'html.parser' )
qts = []
# element filter for soup depending on database
# do you even switch bro
if db_name == 'wg':
qts = soup.findAll( 'div', {'class':'quote_quote'} )
elif db_name == 'xkcd':
qts = soup.findAll( 'span', {'class':'quote'} )
elif db_name == 'qdb':
qts = soup.findAll( 'span', {'class':'qt'} )
elif db_name == 'bash':
qts = soup.findAll( 'p', {'class': 'qt'} )
elif db_name == 'tilde':
qts = soup.findAll( 'pre' )
# quote number notes.
# wg: <a class="quote_number">
# bash: first <b> child of <p> quote
# xkcd: first <a> child of <span class="quotehead">
# qdb: <a class="ql">
# tilde: ???
if qts:
# number of quotes per page
#print( len( qts ) )
# one random quote from page
rqt = random.choice( qts )
# grab raw quote text and split to lines
qt_lines = rqt.text.strip().split('\n')
# if too many lines for spam filter, try to find a shorter one
while not spam and len( qt_lines ) > 5:
#for q in qts:
if not qts:
qt_lines = None; break
qt_lines = qts.pop().text.strip().split('\n')
if not qt_lines:
con.say_to( dst, 'Quote had too many lines!' ); return
for l in qt_lines:
# find some kind of resemblence of a nick. doesnt account for timestamps
nsep = l.find( '>' )+1
if nsep <= 0: nsep = l.find( ':' )+1
if nsep <= 0: nsep = l.find( ' ' )
nn = l[: nsep]
nnc = 0
for c in nn: nnc += ord( c )
nnc %= 16
con.say_to( dst, '> \002\003{}{}\003\002{}'.format( nnc, nn, l[nsep:] ) )
else:
con.say_to( dst, 'No quotes found! :(' )