mirror of
https://github.com/evennia/evennia.git
synced 2026-03-23 08:16:30 +01:00
Added RSS feed support to Evennia. This uses the @rss2chan command to tie a feed to an in-game channel. Updates to the feed will henceforth be echoed to the channel. The reader requires the python-feedreader package to be installed.
This commit is contained in:
parent
b2d7f37e9c
commit
cdab5a240b
8 changed files with 286 additions and 25 deletions
|
|
@ -174,8 +174,6 @@ def connect_to_irc(connection):
|
|||
def connect_all():
|
||||
"""
|
||||
Activate all irc bots.
|
||||
|
||||
Returns a list of (key, TCPClient) tuples for server to properly set services.
|
||||
"""
|
||||
for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith='irc_'):
|
||||
connect_to_irc(connection)
|
||||
|
|
|
|||
156
src/comms/rss.py
Normal file
156
src/comms/rss.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
"""
|
||||
RSS parser for Evennia
|
||||
|
||||
This connects an RSS feed to an in-game Evennia channel, sending messages
|
||||
to the channel whenever the feed updates.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
from twisted.internet import task
|
||||
from django.conf import settings
|
||||
from src.comms.models import ExternalChannelConnection, Channel
|
||||
from src.utils import logger, utils
|
||||
from src.scripts.models import ScriptDB
|
||||
|
||||
RSS_ENABLED = settings.RSS_ENABLED
|
||||
RSS_UPDATE_INTERVAL = settings.RSS_UPDATE_INTERVAL
|
||||
INFOCHANNEL = Channel.objects.channel_search(settings.CHANNEL_MUDINFO[0])
|
||||
RETAG = re.compile(r'<[^>]*?>')
|
||||
|
||||
# holds rss readers they can be shut down at will.
|
||||
RSS_READERS = {}
|
||||
|
||||
def msg_info(message):
|
||||
"""
|
||||
Send info to default info channel
|
||||
"""
|
||||
message = '[%s][RSS]: %s' % (INFOCHANNEL[0].key, message)
|
||||
try:
|
||||
INFOCHANNEL[0].msg(message)
|
||||
except AttributeError:
|
||||
logger.log_infomsg("MUDinfo (rss): %s" % message)
|
||||
|
||||
if RSS_ENABLED:
|
||||
try:
|
||||
import feedparser
|
||||
except ImportError:
|
||||
raise ImportError("RSS requirs python-feedparser to be installed. Install or set RSS_ENABLED=False.")
|
||||
|
||||
class RSSReader(object):
|
||||
"""
|
||||
Reader script used to connect to each individual RSS feed
|
||||
"""
|
||||
def __init__(self, key, url, interval):
|
||||
"""
|
||||
The reader needs an rss url and It also needs an interval
|
||||
for how often it is to check for new updates (defaults
|
||||
to 10 minutes)
|
||||
"""
|
||||
self.key = key
|
||||
self.url = url
|
||||
self.interval = interval
|
||||
self.entries = {} # stored feeds
|
||||
self.task = None
|
||||
# first we do is to load the feed so we don't resend
|
||||
# old entries whenever the reader starts.
|
||||
self.update_feed()
|
||||
# start runner
|
||||
self.start()
|
||||
|
||||
def update_feed(self):
|
||||
"Read the url for new updated data and determine what's new."
|
||||
feed = feedparser.parse(self.url)
|
||||
new = []
|
||||
for entry in (e for e in feed['entries'] if e['id'] not in self.entries):
|
||||
txt = "[RSS] %s: %s" % (RETAG.sub("", entry['title']), entry['link'].replace('\n','').encode('utf-8'))
|
||||
self.entries[entry['id']] = txt
|
||||
new.append(txt)
|
||||
return new
|
||||
|
||||
def update(self):
|
||||
"""
|
||||
Called every self.interval seconds - tries to get new feed entries,
|
||||
and if so, uses the appropriate ExternalChannelConnection to send the
|
||||
data to subscribing channels.
|
||||
"""
|
||||
new = self.update_feed()
|
||||
if not new:
|
||||
return
|
||||
conns = ExternalChannelConnection.objects.filter(db_external_key=self.key)
|
||||
for conn in (conn for conn in conns if conn.channel):
|
||||
for txt in new:
|
||||
conn.to_channel("%s:%s" % (conn.channel.key, txt))
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starting the update task and store a reference in the
|
||||
global variable so it can be found and shut down later.
|
||||
"""
|
||||
global RSS_READERS
|
||||
self.task = task.LoopingCall(self.update)
|
||||
self.task.start(self.interval, now=False)
|
||||
RSS_READERS[self.key] = self
|
||||
|
||||
def build_connection_key(channel, url):
|
||||
"This is used to id the connection"
|
||||
if hasattr(channel, 'key'):
|
||||
channel = channel.key
|
||||
return "rss_%s>%s" % (url, channel)
|
||||
|
||||
def create_connection(channel, url, interval):
|
||||
"""
|
||||
This will create a new RSS->channel connection
|
||||
"""
|
||||
if not type(channel) == Channel:
|
||||
new_channel = Channel.objects.filter(db_key=channel)
|
||||
if not new_channel:
|
||||
logger.log_errmsg("Cannot attach RSS->Evennia: Evennia Channel '%s' not found." % channel)
|
||||
return False
|
||||
channel = new_channel[0]
|
||||
key = build_connection_key(channel, url)
|
||||
old_conns = ExternalChannelConnection.objects.filter(db_external_key=key)
|
||||
if old_conns:
|
||||
return False
|
||||
config = "%s|%i" % (url, interval)
|
||||
# There is no sendback from evennia to the rss, so we need not define any sendback code.
|
||||
conn = ExternalChannelConnection(db_channel=channel, db_external_key=key, db_external_config=config)
|
||||
conn.save()
|
||||
|
||||
connect_to_rss(conn)
|
||||
return True
|
||||
|
||||
def delete_connection(channel, url):
|
||||
"""
|
||||
Delete rss connection between channel and url
|
||||
"""
|
||||
key = build_connection_key(channel, url)
|
||||
try:
|
||||
conn = ExternalChannelConnection.objects.get(db_external_key=key)
|
||||
except Exception:
|
||||
return False
|
||||
conn.delete()
|
||||
reader = RSS_READERS.get(key, None)
|
||||
if reader and reader.task:
|
||||
reader.task.stop()
|
||||
return True
|
||||
|
||||
def connect_to_rss(connection):
|
||||
"""
|
||||
Create the parser instance and connect to RSS feed and channel
|
||||
"""
|
||||
global RSS_READERS
|
||||
key = utils.to_str(connection.external_key)
|
||||
url, interval = [utils.to_str(conf) for conf in connection.external_config.split('|')]
|
||||
# Create reader (this starts the running task and stores a reference in RSS_TASKS)
|
||||
RSSReader(key, url, int(interval))
|
||||
|
||||
def connect_all():
|
||||
"""
|
||||
Activate all rss feed parsers
|
||||
"""
|
||||
if not RSS_ENABLED:
|
||||
return
|
||||
for connection in ExternalChannelConnection.objects.filter(db_external_key__startswith="rss_"):
|
||||
print "connecting RSS: %s" % connection
|
||||
connect_to_rss(connection)
|
||||
Loading…
Add table
Add a link
Reference in a new issue