plugins/xkcd2.lua

changeset 112
08670c0cbb65
child 115
6498ca5ed831
equal deleted inserted replaced
111:a47a1de8993e 112:08670c0cbb65
1
2 require "net.httpclient_listener";
3 local http = require("net.http");
4 local json = require"util.json";
5 local bare_jid = require "util.jid".bare;
6
7 local current_url = "http://xkcd.com/info.0.json";
8 local numbered_url = "http://xkcd.com/%d/info.0.json";
9 local formatted_url = "http://xkcd.com/%d/";
10
11 local strips = {};
12 local latest, last_update;
13
14 function riddim.plugins.xkcd2(bot)
15 bot:hook("commands/xkcd", function(command)
16 local url = current_url;
17 local q = command.param;
18 local strip;
19
20 if q then
21 local t, num = q:match("^([#\"]?)(%d+)\"?$");
22 if t ~= '"' then
23 num = tonumber(num);
24 if num and num < 0 then
25 num = #strip + num;
26 end
27 end
28 strip = strips[num or q:lower()];
29 if strip == "" or strip == 404 then
30 strip = nil
31 end
32 if not strip and num then
33 url = numbered_url:format(num) or url;
34 end
35 elseif os.difftime(os.time(), last_update) <= 3 * 60 * 60 then
36 strip = latest;
37 end
38
39 if q and not strip then
40 local pat = q:lower():gsub("[-()%[]", "%%%0")
41 :gsub("%%(%b[])",function(s) return (#s > 2 and "" or "%") .. s end);
42 local results = {};
43
44 for i, strip in ipairs(strips) do
45 if strip:lower():match(pat) then
46 results[#results+1] = i;
47 end
48 end
49
50 if #results == 0 then
51 return "Sorry, I couldn't find a match";
52 elseif #results == 1 then
53 strip = results[1];
54 else
55 -- We have more than one match
56 local ret, title = "Multiple matches:";
57 for i, num in ipairs(results) do
58 title = strips[num];
59 ret = string.format("%s %s (%d)%s", ret, title, num, ((i < #results) and ",") or "");
60 if i > 5 then ret = ret .. " " .. (#results - 5) .. " more"; break; end
61 end
62 return ret;
63 end
64 end
65
66 if strip then
67 local t, n;
68 if type(strip) == "number" then
69 t, n = strips[strip], strip;
70 else
71 t, n = strip, strips[strip:lower()];
72 end
73 return ("%s, "..formatted_url.." "):format(t, n);
74 end
75
76 http.request(url, nil, function (data, code)
77 if code == 200 then
78 data = json.decode(data);
79 if not data then return end
80 local n, t = tonumber(data.num), data.safe_title;
81 strips[n], strips[t:lower()] = t, n;
82 if not q then
83 latest = n;
84 last_update = os.time();
85 end
86 command:reply(("%s, "..formatted_url.." "):format(t, n));
87 elseif code == 404 then
88 command:reply("Strip not found");
89 end
90 end);
91 return true;
92
93 end);
94
95 local admin = bot.config.admin;
96 bot:hook("commands/xkcdlist", function(command)
97
98 local actor = bare_jid(command.sender.real_jid or command.sender.jid);
99 if actor ~= admin then
100 return "I shall not";
101 end
102
103 local get_next;
104 local function handle_reply(data, code)
105 if code == 200 then
106 data = json.decode(data);
107 if not data then return end
108 local n, t = tonumber(data.num), data.safe_title;
109 strips[n], strips[t:lower()] = t, n;
110 if n > 1 then
111 return get_next(n - 1);
112 end
113 end
114 end
115 function get_next(i)
116 if strips[i] then return end
117 local url = i and numbered_url:format(i) or current_url;
118 http.request(url, nil, handle_reply);
119 end
120 get_next(tonumber(command.param));
121 return true;
122 end);
123
124 local function do_load()
125 local ok, loaded_strips = pcall(dofile,"xkcd-list.lua");
126 if ok then
127 strips = loaded_strips;
128 return true;
129 else
130 return nil, loaded_strips;
131 end
132 end
133
134
135 bot:hook("commands/xkcdsave", function(command)
136
137 local actor = bare_jid(command.sender.real_jid or command.sender.jid);
138 if actor ~= admin then
139 return "I shall not";
140 end
141
142 local dump = "return "..require"util.serialization".serialize(strips);
143 local f, err = io.open("xkcd-list.lua~", "w");
144 if f then
145 f:write(dump);
146 f:close();
147 os.rename("xkcd-list.lua~", "xkcd-list.lua");
148 return "Saved list of strips";
149 end
150 return err;
151 end);
152
153 bot:hook("commands/xkcdload", function(command)
154
155 local actor = bare_jid(command.sender.real_jid or command.sender.jid);
156 if actor ~= admin then
157 return "I shall not";
158 end
159
160 local ok, err = do_load()
161 if not ok then return err end
162 return "List of strips loaded"
163 end);
164
165 bot:hook("commands/xkcdreset", function(command)
166
167 local actor = bare_jid(command.sender.real_jid or command.sender.jid);
168 if actor ~= admin then
169 return "I shall not";
170 end
171
172 strips = {};
173 return "List of strips emptied";
174 end);
175
176 end

mercurial