diff options
| -rw-r--r-- | .gitconfig | 1 | ||||
| -rw-r--r-- | chat_iface.py | 71 | ||||
| -rw-r--r-- | irc_iface.py | 43 | ||||
| -rw-r--r-- | rschat.ini | 10 | ||||
| -rwxr-xr-x | rschat.py | 72 | 
5 files changed, 197 insertions, 0 deletions
| diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..6c30242 --- /dev/null +++ b/.gitconfig @@ -0,0 +1 @@ +/rschat.ini diff --git a/chat_iface.py b/chat_iface.py new file mode 100644 index 0000000..c1fbc29 --- /dev/null +++ b/chat_iface.py @@ -0,0 +1,71 @@ +from __future__ import unicode_literals +import logging +import selenium.webdriver + +# set WebElement hash to default to use set(x) +selenium.webdriver.remote.webelement.WebElement.__hash__ = lambda self: hash(self.id) + +def diff(a, b): +  b = set(b) +  return [aa for aa in a if aa not in b] + +logger = logging.getLogger('rschat.' + __name__) + +class ChatInterface(): +  def __init__(self, chat_type, username, password): +    self.chat_type = chat_type +    self.username = username +    self.password = password +    self.browser = None + +  def __enter__(self): +    logger.info('Starting webdriver') +    options = selenium.webdriver.ChromeOptions() +    options.add_argument('--disable-file-system') + +    self.browser = selenium.webdriver.Chrome('/usr/lib64/chromium-browser/chromedriver', chrome_options=options) + +    self.browser.implicitly_wait(30) + +    logger.debug('Navigating to companion app') +    self.browser.get('http://www.runescape.com/companion/comapp.ws') + +    logger.debug('Switching to iframe') +    self.browser.switch_to_frame(self.browser.find_element_by_tag_name('iframe')) + +# login +    logger.debug('Logging in as %s' % self.username) +    self.browser.find_element_by_id('username').send_keys(self.username) +    self.browser.find_element_by_id('password').send_keys(self.password) +    self.browser.find_element_by_tag_name('form').submit() + +# decline remember login +    logger.debug('Declining remember login') +    self.browser.find_element_by_partial_link_text('No').click() + +    logger.debug('Switching to %s chat' % self.chat_type) +    self.browser.find_element_by_css_selector('.chat-nav .icon-%schat' % self.chat_type).click() + +    self.browser.implicitly_wait(0) + +    return self + +  lastmsgs = [] + +  def send(self, line): +    self.browser.find_element_by_id('message').send_keys(line) +    self.browser.find_element_by_tag_name('form').submit() + +  def poll(self): +    try: +      allmsgs = self.browser.find_elements_by_css_selector('#content-%s-chat .message:not(.my-message) .message-content' % self.chat_type) +      newmsgs = diff(allmsgs, self.lastmsgs) + +      self.lastmsgs = allmsgs + +      return [(e.find_element_by_class_name('author').text.replace(' -', ''), e.find_element_by_tag_name('p').text) for e in newmsgs] +    except selenium.webdriver.common.exceptions.NoSuchElementException: +      pass + +  def __exit__(self, *_): +    self.browser.quit() diff --git a/irc_iface.py b/irc_iface.py new file mode 100644 index 0000000..c70866c --- /dev/null +++ b/irc_iface.py @@ -0,0 +1,43 @@ +from __future__ import unicode_literals +import irc.client +import logging + +logger = logging.getLogger('rschat.' + __name__) + +class IRCInterface(irc.client.SimpleIRCClient): +  def __init__(self, server, port, nick, channel): +    logger.debug("Initializing IRCInterface") +    super(self.__class__, self).__init__() +    self.server = server +    self.port = port +    self.nick = nick +    self.channel = channel +    self.queue = [] + +  def __enter__(self): +    logger.info("Connecting to %s:%s as %s" % (self.server, self.port, self.nick)) +    self.connect(self.server, self.port, self.nick) +    return self + +  def on_welcome(self, connection, _): +    logger.info("Connected, joining %s" % self.channel) +    connection.join(self.channel) + +  def send(self, line): +    self.connection.privmsg(self.channel, line) + +  def on_pubmsg(self, _, event): +    source = event.source +    self.queue.append((source[:source.index('!')], event.arguments[0])) + +  def poll(self): +    self.ircobj.process_once() +    queue = self.queue +    self.queue = [] +    return queue + +  def send_raw(self, *args, **kwargs): +    return self.connection.send_raw(*args, **kwargs) + +  def __exit__(self, *_): +    self.connection.quit() diff --git a/rschat.ini b/rschat.ini new file mode 100644 index 0000000..53737fc --- /dev/null +++ b/rschat.ini @@ -0,0 +1,10 @@ +[IRC] +#server = irc.freenode.net +#port = 6667 +#nick = RSChat +#channel = #rswiki-cc + +[Chat] +#type = clan +user = +pass = diff --git a/rschat.py b/rschat.py new file mode 100755 index 0000000..b63fc48 --- /dev/null +++ b/rschat.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 + +from __future__ import unicode_literals, with_statement + +VERSION=(0, 1, 0) + +from chat_iface import ChatInterface +from irc_iface import IRCInterface +try: +  from configparser import SafeConfigParser +except ImportError: +  from ConfigParser import SafeConfigParser +import logging +import os +import select +import sys +import time + +logger = logging.getLogger('rschat') +logger.setLevel(logging.DEBUG) +ch = logging.StreamHandler() +ch.setLevel(logging.DEBUG) +formatter = logging.Formatter('<%(levelno)s>[%(asctime)s] %(name)s:%(funcName)s: %(message)s') +ch.setFormatter(formatter) +logger.addHandler(ch) + +logger.debug("Starting rschat version %d.%d.%d" % VERSION) + +try: +  xdg_config_home = os.environ['XDG_CONFIG_HOME'] +except KeyError: +  xdg_config_home = os.path.expanduser('~/.config') + +try: +  xdg_config_dirs = os.environ['XDG_CONFIG_DIRS'].split(':') +except KeyError: +  xdg_config_dirs = ['/etc/xdg'] + +cfg = SafeConfigParser({ +  'server': 'chat.freenode.net', +  'port': 6667, +  'nick': 'RSWBot', +  'channel': '#rswiki-cc', +  'chat': 'clan', +}) + +cfg.read([fldr + '/rschat.ini' for fldr in [xdg_config_home] + xdg_config_dirs + ['.']]) + +with IRCInterface(cfg.get('IRC', 'server'), cfg.get('IRC', 'port', raw=True), cfg.get('IRC', 'nick'), cfg.get('IRC', 'channel')) as irc, \ +     ChatInterface(cfg.get('Chat', 'Chat'), cfg.get('Chat', 'user'), cfg.get('Chat', 'pass')) as chat: + +  logger.debug('Primary initialization complete, processing IRC input') + +  irc.poll() + +  # poll for new messages +  logger.info('Initialization seems complete, starting main loop') + +  def poll(recv, send): +    msgs = recv.poll() +    if msgs: +      list(map(send.send, ['%s: %s' % msg for msg in msgs])) + +  while True: +    time.sleep(0.1) + +    # raw IRC commands +    if select.select([sys.stdin], [], [], 0)[0]: +      irc.send_raw(sys.stdin.readline()) + +    poll(irc, chat) +    poll(chat, irc) | 
