+++ /dev/null
-# Reddark streaming module
-# vim: fileencoding=utf-8
-
-# module info
-modinfo = {
- 'author': 'Multiple',
- 'license': 'unknown',
- 'compatible': [0], # compatible module API versions
- 'depends': [], # other modules required to work properly?
- 'softdeps': ['help'], # modules which are preferred but not required
-}
-# note: softdeps will be loaded before this module, IF not disabled in the configuration (autoload.module = 0) (and if it exists)
-# however, if it is disabled it will be silently ignored, and if it is unloaded at runtime it won't cause this one to unload.
-#
-# basically, softdeps are things this module will use if available, but does not require (no errors will occur if it's not loaded)
-# for example, @lib.help() will attempt to use the help module, but swallow errors if it is not loaded
-
-
-# global variables
-wants_to_stop = False
-runner = None
-last_update = 0
-last_topic = ""
-
-# preamble
-import modlib
-lib = modlib.modlib(__name__)
-def modstart(parent, *args, **kwargs):
- gotParent(parent)
- return lib.modstart(parent, *args, **kwargs)
-def modstop(*args, **kwargs):
- global wants_to_stop, runner
- if runner:
- debug("Stopping runner")
- wants_to_stop = True # tell the SSE thread to stop the next time it wakes up
- runner.join() # blocks the main thread til the next chunk received (or timeout)! oh well.
- debug("runner stopped")
- wants_to_stop = False
- return lib.modstop(*args, **kwargs)
-
-# module code
-from modules.contrib.sseclient import SSEClient
-import requests
-from bs4 import BeautifulSoup
-import threading, json, time, collections, re
-
-def chan():
- return lib.parent.channel(lib.parent.cfg.get('reddark', 'channel', default="##.test"))
-
-def bot():
- return chan().bot
-
-def chanmsg(message):
- return chan().msg(message, truncate=True, msgtype="NOTICE")
-
-def debug(message, send_to_owner=True):
- if lib.parent is None:
- print(message)
- return
- if lib.parent.cfg.getboolean('reddark', 'debug', True):
- lib.parent.log('Reddark', 'R', message)
- if send_to_owner and lib.parent.cfg.get('debug', 'owner'):
- bot().fastmsg(lib.parent.cfg.get('debug', 'owner'), message)
-
-def getText(subreddit):
- r = None
- e = None
- try:
- r = requests.get('https://old.reddit.com/' + subreddit, headers={'User-Agent': 'better-see-reason-bot/1.0'})
- except Exception as e2:
- e = e2
- if r is None:
- debug("Error getting text: " + repr(e), False)
- return ''
- if r.status_code != 403:
- debug("Error getting text: " + str(r.status_code) + " (403 expected)", False)
- return ''
- soup = BeautifulSoup(r.text, 'html.parser')
- elements = soup.find_all(class_='interstitial-subreddit-description')
- if len(elements):
- text = elements[0].get_text()
- text = re.sub(re.escape(subreddit), '', text, re.IGNORECASE).replace("\n", " ")
- return ' - ' + text
- return ''
-
-def handleDelta(message):
- message['state'] = message['state'].lower()
- message['previous_state'] = message['previous_state'].lower()
- if message['state'] == 'private':
- message['text'] = getText(message['name'])
- print(repr(message))
- chanmsg('[%(section)s] %(name)s went %(state)s (was: %(previous_state)s) (https://old.reddit.com/%(name)s)%(text)s' % message)
- elif message['state'] == 'public':
- chanmsg('[%(section)s] %(name)s went \x02%(state)s\x02 (was: %(previous_state)s) (https://old.reddit.com/%(name)s)' % message)
- else:
- chanmsg('[%(section)s] %(name)s went %(state)s (was: %(previous_state)s) (https://old.reddit.com/%(name)s)' % message)
-
-def handleState(message):
- global last_update, last_topic
- if time.time() < last_update + lib.parent.cfg.getint('reddark', 'update_interval', 600):
- return
- output = collections.defaultdict(int)
- output['totalSubs'] = len(message['subreddits'])
- for sub in message['subreddits']:
- if sub['state'] == 'PRIVATE':
- output['privateSubs'] += 1
- output['protestingSubs'] += 1
- elif sub['state'] == 'PUBLIC':
- output['publicSubs'] += 1
- else:
- output['restrictedSubs'] += 1
- output['protestingSubs'] += 1
- output['pct'] = round(output['protestingSubs']/output['totalSubs']*100, 2)
- output['pctPublic'] = round(output['publicSubs']/output['totalSubs']*100, 2)
- output['pctPrivate'] = round(output['privateSubs']/output['totalSubs']*100, 2)
- output['pctRestricted'] = round(output['restrictedSubs']/output['totalSubs']*100, 2)
- newTopic = 'subreddits protesting: %(protestingSubs)s out of %(totalSubs)s pledged (%(pct)s%%) | private: %(privateSubs)s (%(pctPrivate)s%%), restricted: %(restrictedSubs)s (%(pctRestricted)s%%), public: %(publicSubs)s (%(pctPublic)s%%)' % dict(output)
- debug(newTopic, False)
- if last_topic != newTopic:
- last_topic = newTopic
- last_update = time.time()
- bot().conn.send("TOPIC %(chan)s :%(topic)s %(suffix)s" % {'chan': chan(), 'topic': newTopic, 'suffix': lib.parent.cfg.get('reddark', 'topicsuffix', '| Reddark That Works™ https://reddark.rewby.archivete.am/ (https://github.com/reddark-remix/reddark-remix) | https://www.youtube.com/watch?v=xMaE6toi4mk')})
-
-def gotParent(parent):
- global runner
- def loop_messages():
- global wants_to_stop
- messages = SSEClient(parent.cfg.get('reddark', 'sse', default="https://reddark.rewby.archivete.am/sse"), timeout=60)
- debug("Connected to SSE", False)
- for msg in messages:
- try:
- if wants_to_stop:
- return
- if len(msg.data) == 0:
- continue
- data = json.loads(msg.data)
- debug(repr(data)[0:500], False)
- if data['type'] == 'Delta':
- handleDelta(data['content'])
- elif data['type'] == 'CurrentStateUpdate':
- handleState(data['content'])
- else:
- debug("Unknown event: " + msg, False)
- except Exception as e:
- debug("Failed to parse an event: " + repr(e))
-#{"type":"Delta","content":{"name":"r/TrainCrashSeries","section":"1k+","previous_state":"PRIVATE","state":"RESTRICTED"}}
-#{"type":"CurrentStateUpdate","content":{"sections":["40+ million","30+ million","20+ million","10+ million","5+ million","1+ million","500k+","250k+","100k+","50k+","5k+","1k+","1k and below"],"subreddits":[{"name":"r/032r4r","section":"1k+","state":"PRIVATE"},{"name":"r/0sanitymemes","section":"5k+","state":"PRIVATE"},{"name":"r/1022","section":"5k+","state":"PRIVATE"},{"name":"r/11foot8","section":"100k+","state":"PRIVATE"},{"name":"r/1200isjerky","section":"50k+","state":"PRIVATE"},{"name":"r
-
- runner = threading.Thread(target=loop_messages)
- runner.daemon = True
- runner.start()
-
-@lib.hook(needchan=False, glevel=50)
-@lib.help('[<suffix>]', 'sets reddark topic suffix')
-def topicsuffix(bot, user, chan, realtarget, *args):
- if chan is not None: replyto = chan
- else: replyto = user
-
- lib.parent.cfg.set('reddark', 'topicsuffix', ' '.join(args))
-
- bot.msg(replyto, "Updated topic suffix")
-
-@lib.hook(needchan=False, glevel=50)
-@lib.help('<seconds>', 'sets reddark topic max update interval')
-@lib.argsEQ(1)
-def updateinterval(bot, user, chan, realtarget, *args):
- if chan is not None: replyto = chan
- else: replyto = user
-
- lib.parent.cfg.set('reddark', 'update_interval', int(' '.join(args)))
-
- bot.msg(replyto, "Updated topic interval")