diff options
Diffstat (limited to 'app.py')
-rwxr-xr-x | app.py | 85 |
1 files changed, 73 insertions, 12 deletions
@@ -43,8 +43,7 @@ class RSSItem(DataObject): | |||
43 | def __init__(self, id, title, author, feed_title, feed_url, url, | 43 | def __init__(self, id, title, author, feed_title, feed_url, url, |
44 | publish_date, content, read): | 44 | publish_date, content, read): |
45 | self.id = id | 45 | self.id = id |
46 | self.feed_url = RSSFeed(feed_url, None, None).self_link | 46 | self.feed = RSSFeed(feed_url, None, feed_title) |
47 | self.feed_title = feed_title | ||
48 | self.title = title | 47 | self.title = title |
49 | self.author = author | 48 | self.author = author |
50 | self.url = url | 49 | self.url = url |
@@ -53,6 +52,10 @@ class RSSItem(DataObject): | |||
53 | self.read = not bool(read) | 52 | self.read = not bool(read) |
54 | self.no_content = len(content) < 100 | 53 | self.no_content = len(content) < 100 |
55 | 54 | ||
55 | def _update_json(self, data): | ||
56 | data['feed'] = self.feed.self_link | ||
57 | return data | ||
58 | |||
56 | 59 | ||
57 | class RSSFeed(DataObject): | 60 | class RSSFeed(DataObject): |
58 | 61 | ||
@@ -64,7 +67,16 @@ class RSSFeed(DataObject): | |||
64 | self.title = title | 67 | self.title = title |
65 | 68 | ||
66 | def _update_json(self, data): | 69 | def _update_json(self, data): |
67 | data['items'] = '/feed/{}/items'.format(self.id) | 70 | data['items'] = self.items |
71 | data['unread_items'] = self.unread_items | ||
72 | |||
73 | @property | ||
74 | def items(self): | ||
75 | return '/feed/{}/items'.format(self.id) | ||
76 | |||
77 | @property | ||
78 | def unread_items(self): | ||
79 | return '/feed/{}/items/unread'.format(self.id) | ||
68 | 80 | ||
69 | @property | 81 | @property |
70 | def id(self): | 82 | def id(self): |
@@ -77,6 +89,13 @@ class RSSFeed(DataObject): | |||
77 | '{}========'.format(token).encode('utf-8')).decode('utf-8') | 89 | '{}========'.format(token).encode('utf-8')).decode('utf-8') |
78 | 90 | ||
79 | 91 | ||
92 | class UnreadRSSFeed(RSSFeed): | ||
93 | |||
94 | def __init__(self, feed_url, url, title, unread_count): | ||
95 | super(UnreadRSSFeed, self).__init__(feed_url, url, title) | ||
96 | self.unread_count = unread_count | ||
97 | |||
98 | |||
80 | 99 | ||
81 | class DBReader(object): | 100 | class DBReader(object): |
82 | 101 | ||
@@ -95,6 +114,20 @@ class DBReader(object): | |||
95 | i.pubDate desc | 114 | i.pubDate desc |
96 | ''' | 115 | ''' |
97 | 116 | ||
117 | UNREAD_FEEDS = ''' | ||
118 | SELECT | ||
119 | f.rssurl, f.url, f.title, | ||
120 | count(*) as unread_count | ||
121 | FROM | ||
122 | rss_item i | ||
123 | LEFT JOIN rss_feed f | ||
124 | ON f.rssurl = i.feedurl | ||
125 | WHERE | ||
126 | i.unread = 1 | ||
127 | GROUP BY | ||
128 | i.feedurl | ||
129 | ''' | ||
130 | |||
98 | def __init__(self, db_path): | 131 | def __init__(self, db_path): |
99 | self.con = sqlite3.connect(db_path) | 132 | self.con = sqlite3.connect(db_path) |
100 | self.con.row_factory = RSSItem.from_db_row | 133 | self.con.row_factory = RSSItem.from_db_row |
@@ -120,17 +153,26 @@ class DBReader(object): | |||
120 | [1 if unread else 0, id]) | 153 | [1 if unread else 0, id]) |
121 | con.commit() | 154 | con.commit() |
122 | 155 | ||
156 | def update_feed_unread(self, token, unread=True): | ||
157 | with self.con as con: | ||
158 | con.execute( | ||
159 | 'UPDATE rss_item SET unread = ? WHERE feedurl = ?', | ||
160 | [1 if unread else 0, RSSFeed.parse_token(token)]) | ||
161 | con.commit() | ||
162 | |||
123 | def get_entry(self, id): | 163 | def get_entry(self, id): |
124 | return self._fetch("i.id = ?", [id])[0] | 164 | return self._fetch("i.id = ?", [id])[0] |
125 | 165 | ||
126 | def get_unread(self): | 166 | def get_unread(self): |
127 | data = defaultdict(list) | 167 | data = defaultdict(list) |
128 | unread = self._fetch("i.unread = ?", [1]) | 168 | return self._fetch("i.unread = ?", [1]) |
129 | |||
130 | for record in unread: | ||
131 | data[record.feed_title].append(record) | ||
132 | 169 | ||
133 | return sorted(data.items()) | 170 | def get_unread_feeds(self): |
171 | with self.con as con: | ||
172 | con.row_factory = UnreadRSSFeed.from_db_row | ||
173 | curs = con.cursor() | ||
174 | curs.execute(self.UNREAD_FEEDS) | ||
175 | return curs.fetchall() | ||
134 | 176 | ||
135 | def get_unread_for_feed(self, token, only_unread=False): | 177 | def get_unread_for_feed(self, token, only_unread=False): |
136 | if only_unread: | 178 | if only_unread: |
@@ -159,16 +201,21 @@ def json_list(data): | |||
159 | 201 | ||
160 | @app.route('/') | 202 | @app.route('/') |
161 | def index(): | 203 | def index(): |
162 | reader = DBReader(DB_PATH) | 204 | return render_template('items.html') |
163 | return render_template('items.html', items=reader.get_unread()) | ||
164 | 205 | ||
165 | 206 | ||
166 | @app.route('/feed/') | 207 | @app.route('/feed') |
167 | def feed_list(): | 208 | def feed_list(): |
168 | reader = DBReader(DB_PATH) | 209 | reader = DBReader(DB_PATH) |
169 | return jsonify({ 'feeds': json_list(reader.get_feeds()) }) | 210 | return jsonify({ 'feeds': json_list(reader.get_feeds()) }) |
170 | 211 | ||
171 | 212 | ||
213 | @app.route('/feed/unread') | ||
214 | def unread_feed_list(): | ||
215 | reader = DBReader(DB_PATH) | ||
216 | return jsonify({ 'feeds': json_list(reader.get_unread_feeds()) }) | ||
217 | |||
218 | |||
172 | @app.route('/feed/<token>') | 219 | @app.route('/feed/<token>') |
173 | def feed(token): | 220 | def feed(token): |
174 | reader = DBReader(DB_PATH) | 221 | reader = DBReader(DB_PATH) |
@@ -182,13 +229,27 @@ def feed_items(token): | |||
182 | return jsonify({ 'items': json_list(unread), "count": len(unread) }) | 229 | return jsonify({ 'items': json_list(unread), "count": len(unread) }) |
183 | 230 | ||
184 | 231 | ||
185 | @app.route('/feed/<token>/items/unread') | 232 | @app.route('/feed/<token>/items/unread', methods=["GET", "POST"]) |
186 | def unread_feed_items(token): | 233 | def unread_feed_items(token): |
187 | reader = DBReader(DB_PATH) | 234 | reader = DBReader(DB_PATH) |
235 | if request.method == 'POST': | ||
236 | try: | ||
237 | read = bool(int(request.form.get('read'))) | ||
238 | except: | ||
239 | return make_response('', 400) | ||
240 | |||
241 | reader.update_feed_unread(token, not read) | ||
242 | |||
188 | unread = reader.get_unread_for_feed(token, True) | 243 | unread = reader.get_unread_for_feed(token, True) |
189 | return jsonify({ 'items': json_list(unread), "count": len(unread) }) | 244 | return jsonify({ 'items': json_list(unread), "count": len(unread) }) |
190 | 245 | ||
191 | 246 | ||
247 | @app.route('/item/unread') | ||
248 | def unread_item_list(): | ||
249 | reader = DBReader(DB_PATH) | ||
250 | return jsonify({ 'items': json_list(reader.get_unread()) }) | ||
251 | |||
252 | |||
192 | @app.route("/item/<int:entry_id>", methods=["GET", "POST"]) | 253 | @app.route("/item/<int:entry_id>", methods=["GET", "POST"]) |
193 | def item(entry_id): | 254 | def item(entry_id): |
194 | #post read=1 | 255 | #post read=1 |