aboutsummaryrefslogtreecommitdiff
path: root/modules/rss.py
blob: 5cef8a721ca4b102f5fb40146eef4487143eb74c (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
from src import ModuleManager, utils
import feedparser

RSS_INTERVAL = 60 # 1 minute

def _format_entry(feed_title, entry):
    title = entry["title"]

    author = entry.get("author", None)
    author = " by %s" % author if author else ""

    link = entry.get("link", None)
    link = " - %s" % link if link else ""

    return "%s: %s%s%s" % (feed_title, title, author, link)

class Module(ModuleManager.BaseModule):
    _title = "RSS"
    def on_load(self):
        self.timers.add("rss", RSS_INTERVAL)

    @utils.hook("timer.rss")
    def timer(self, event):
        event["timer"].redo()
        hook_settings = self.bot.database.channel_settings.find_by_setting(
            "rss-hooks")
        hooks = {}
        for server_id, channel_name, urls in hook_settings:
            server = self.bot.get_server_by_id(server_id)
            if server and channel_name in server.channels:
                channel = server.channels.get(channel_name)
                for url in urls:
                    if not url in hooks:
                        hooks[url] = []
                    hooks[url].append(channel)

        for url, channels in hooks.items():
            try:
                feed = feedparser.parse(url)
            except:
                feed = None

            if not feed or not feed["feed"]:
                self.log.warn("Failed to parse rss for %s", [url],
                    exc_info=True)
                continue

            feed_title = feed["feed"]["title"]
            entry_formatted = {}

            for channel in channels:
                seen_ids = channel.get_setting("rss-seen-ids", [])
                new_ids = []
                valid = 1
                for entry in feed["entries"]:
                    if entry["id"] in seen_ids:
                        new_ids.append(entry["id"])
                        continue

                    if valid == 4:
                        continue
                    valid += 1

                    if not entry["id"] in entry_formatted:
                        output = _format_entry(feed_title, entry)
                        entry_formatted[entry["id"]] = output
                    else:
                        output = entry_formatted[entry["id"]]

                    self.events.on("send.stdout").call(target=channel,
                        module_name="RSS", server=server, message=output)
                    new_ids.append(entry["id"])

                channel.set_setting("rss-seen-ids", new_ids)

    @utils.hook("received.command.rss", min_args=1, channel_only=True)
    def rss(self, event):
        """
        :help: Modify RSS/Atom configuration for the current channel
        :usage: list
        :usage: add <url>
        :usage: remove <url>
        :permission: rss
        """
        changed = False
        message = None

        rss_hooks = event["target"].get_setting("rss-hooks", [])

        subcommand = event["args_split"][0].lower()
        if subcommand == "list":
            event["stdout"].write("RSS hooks: %s" % ", ".join(rss_hooks))
        elif subcommand == "add":
            if not len(event["args_split"]) > 1:
                raise utils.EventError("Please provide a URL")

            url = event["args_split"][1]
            if url in rss_hooks:
                raise utils.EventError("That URL is already being watched")
            rss_hooks.append(url)
            changed = True
            message = "Added RSS feed"
        elif subcommand == "remove":
            if not len(event["args_split"]) > 1:
                raise utils.EventError("Please provide a URL")

            url = event["args_split"][1]
            if not url in rss_hooks:
                raise utils.EventError("I'm not watching that URL")
            rss_hooks.remove(url)
            changed = True
            message = "Removed RSS feed"
        else:
            raise utils.EventError("Unknown subcommand '%s'" % subcommand)

        if changed:
            event["target"].set_setting("rss-hooks", rss_hooks)
            event["stdout"].write(message)