File: rss_feed.lua

package info (click to toggle)
notion 4.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 4,656 kB
  • sloc: ansic: 47,365; sh: 2,093; makefile: 594; perl: 270
file content (204 lines) | stat: -rw-r--r-- 5,646 bytes parent folder | download | duplicates (4)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
-- Authors: Sadrul Habib Chowdhury <imadil@gmail.com>
-- License: Public domain
-- Last Changed: Unknown
--
-- rss_feed.lua
--
-- Use:
-- You have to dopath() this script for it to work. I have set a binding
-- META+F12 for a popup-menu. You can also add %rss to the statusbar, which
-- will show a scrolling list of titles. You might want to give it a try
-- before disabling. :)
--
-- NOTES:
-- This is not a useful script. This script was written just to demonstrate
-- what idle time can do to a man.
--
-- Author:
-- Sadrul Habib Chowdhury (Adil)
-- imadil at gmail dot com

if not rss_feed then
  rss_feed = {
    interval=250,       -- how often does the scroller update?
    width = 40,         -- the width of the scroller.. duh
    refresh = 30 * (60*1000),    -- how often to pull from the server?
    url = {             -- guess what
        {"Slashdot", "http://slashdot.org/index.rss"},
        {"CNN", "http://rss.cnn.com/rss/cnn_latest.rss"},
        {"BBC", "http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml"},
        -- add other sites
    }
  }
end

local scroller_timer = nil  -- the timer for the scroller
local rss_timer = nil       -- timer for the rss refresh
rss_desc = ""
local rss_string = ""
local current = 1
local rss_length = 0
local feeds = {}

--
-- remove html-entities
--
local function clean(s)
    s = string.gsub(s, "\r", "")
    s = string.gsub(s, "\n", "")
    s = string.gsub(s, "&amp;", "&")
    s = string.gsub(s, "&quot;", "\"")
    s = string.gsub(s, "&nbsp;", " ")
    s = string.gsub(s, "&gt;", ">")
    s = string.gsub(s, "&lt;", "<")
    -- add any other conversions necessary here
    return s
end

local function reconstruct_rss(src, tbl)
    for _, info in pairs(tbl) do
        rss_string = rss_string .. " --- "..src.."# "..clean(info[1])
    end
end

--
-- If you have been looking for the worst possible rss-parser ever,
-- it's your lucky day.
--
local function get_next(str)
    local t, d, r = nil,"",""

    if str == nil then return t,d,r end
    __, _ = string.find(str, "<item[^s]")
    if not __ then return t,d,r end

    r = string.sub(str, _)
    __, _ = string.find(r, "<title>")
    if not __ then return t,d,r end
    e, s = string.find(r, "</title>")
    if not e then return t,d,r end
    t = string.sub(r, _+1, e-1)
    r = string.sub(r, s+1)

    __, _ = string.find(r, "<description>")
    if not __ then return t,d,r end
    e, s = string.find(r, "</description>")
    if not e then return t,d,r end
    d = string.sub(r, _+1, e-1)
    r = string.sub(r, s+1)

    return t,d,r
end

local function parse_rss(str)
    local data = ""
    while str do
        data = data .. str
        str = coroutine.yield()
    end

    local src = ""
    local ret = ""
    local new = {}

    __, _ = string.find(data, "[^\n]+")
    if __ then src = string.sub(data, __, _) end

    -- for title, desc in string.gmatch(data,".-<item[^s].-<title>(.-)</title>.-<description>(.-)</description>.-</item>") do
    title, desc, data = get_next(data)
    while title do
        title = clean(title)
        desc = clean(desc)
        rss_desc = rss_desc .. "\nTitle: "..title.."\n"..desc.."\n"
        table.insert(new, {title, desc})
        title,desc,data = get_next(data)
    end
    feeds[src] = new
    rss_string = ""
    for k,v in pairs(feeds) do
       reconstruct_rss(k,v)
    end

    rss_length = string.len(rss_string)
    rss_string = rss_string .. string.sub(rss_string, 1, rss_feed.width)
    count = 1
    rss_timer:set(rss_feed.refresh, retrieve)
end

local function retrieve_rss(src, str)
    ioncore.popen_bgread("echo "..src.."&& curl " .. str .. " 2>/dev/null",
                    coroutine.wrap(parse_rss))
end

--
-- pull feed from each server
--
function retrieve()
    local str = ""
    for _, entry in pairs(rss_feed.url) do
        retrieve_rss(entry[1], entry[2])
    end
end

local function get_string()
    return rss_string
end

local function scroll()
    local st = get_string()
    local show = string.sub(st, current, current+rss_feed.width)

    mod_statusbar.inform("rss", "- "..show.." -")
    mod_statusbar.update()
    scroller_timer:set(rss_feed.interval, scroll)
    current = current + 1
    if current > rss_length then
        current = 1
    end
end

local function init_rss()
    rss_timer = ioncore.create_timer()
    rss_length = rss_feed.width
    rss_string = string.rep('- ', rss_length)
    if mod_statusbar then
        -- do this iff mod_statusbar is loaded
        scroller_timer = ioncore.create_timer()
        mod_statusbar.inform("rss_template", string.rep("x", rss_feed.width))
        scroll()
    end
    retrieve()
end

function show_menu()
    local ret = {}
    local count = 1
    local function sub_rss_menu(tbl)
        local ret = {}
        for q, d in pairs(tbl) do
            local title = clean(d[1])
            local desc = clean(d[2])
            table.insert(ret, menuentry(tostring(count)..". "..title,
                    "mod_query.message(_, '" .. string.gsub(desc, "'", "\\'") .. "')"))
            count = count + 1
        end
        if count == 1 then
            table.insert(ret, menuentry("No feed from server", "nil"))
        end
        return ret
    end
    table.insert(ret, menuentry("Re-read from server", "retrieve()"))
    for title, tbl in pairs(feeds) do
        count = 1
        table.insert(ret, submenu("RSS Feeds from "..title, sub_rss_menu(tbl)))
    end
    return ret
end

init_rss()

ioncore.defbindings("WScreen", {
    kpress(META.."Shift+D", "mod_query.message(_, rss_desc)"),
    kpress(META.."F12", 'mod_menu.bigmenu(_, _sub, show_menu)'),
})