From 979633a50f11afbb6388ac0fd46e45aac64a286a Mon Sep 17 00:00:00 2001 From: Mike Crute Date: Wed, 29 Jul 2015 18:30:42 -0700 Subject: Add more features --- app.py | 85 +++++++++++++++--- templates/items.html | 250 ++++++++++++++++++++++++++++----------------------- 2 files changed, 213 insertions(+), 122 deletions(-) diff --git a/app.py b/app.py index 1740f51..1bc6d93 100755 --- a/app.py +++ b/app.py @@ -43,8 +43,7 @@ class RSSItem(DataObject): def __init__(self, id, title, author, feed_title, feed_url, url, publish_date, content, read): self.id = id - self.feed_url = RSSFeed(feed_url, None, None).self_link - self.feed_title = feed_title + self.feed = RSSFeed(feed_url, None, feed_title) self.title = title self.author = author self.url = url @@ -53,6 +52,10 @@ class RSSItem(DataObject): self.read = not bool(read) self.no_content = len(content) < 100 + def _update_json(self, data): + data['feed'] = self.feed.self_link + return data + class RSSFeed(DataObject): @@ -64,7 +67,16 @@ class RSSFeed(DataObject): self.title = title def _update_json(self, data): - data['items'] = '/feed/{}/items'.format(self.id) + data['items'] = self.items + data['unread_items'] = self.unread_items + + @property + def items(self): + return '/feed/{}/items'.format(self.id) + + @property + def unread_items(self): + return '/feed/{}/items/unread'.format(self.id) @property def id(self): @@ -77,6 +89,13 @@ class RSSFeed(DataObject): '{}========'.format(token).encode('utf-8')).decode('utf-8') +class UnreadRSSFeed(RSSFeed): + + def __init__(self, feed_url, url, title, unread_count): + super(UnreadRSSFeed, self).__init__(feed_url, url, title) + self.unread_count = unread_count + + class DBReader(object): @@ -95,6 +114,20 @@ class DBReader(object): i.pubDate desc ''' + UNREAD_FEEDS = ''' + SELECT + f.rssurl, f.url, f.title, + count(*) as unread_count + FROM + rss_item i + LEFT JOIN rss_feed f + ON f.rssurl = i.feedurl + WHERE + i.unread = 1 + GROUP BY + i.feedurl + ''' + def __init__(self, db_path): self.con = sqlite3.connect(db_path) self.con.row_factory = RSSItem.from_db_row @@ -120,17 +153,26 @@ class DBReader(object): [1 if unread else 0, id]) con.commit() + def update_feed_unread(self, token, unread=True): + with self.con as con: + con.execute( + 'UPDATE rss_item SET unread = ? WHERE feedurl = ?', + [1 if unread else 0, RSSFeed.parse_token(token)]) + con.commit() + def get_entry(self, id): return self._fetch("i.id = ?", [id])[0] def get_unread(self): data = defaultdict(list) - unread = self._fetch("i.unread = ?", [1]) - - for record in unread: - data[record.feed_title].append(record) + return self._fetch("i.unread = ?", [1]) - return sorted(data.items()) + def get_unread_feeds(self): + with self.con as con: + con.row_factory = UnreadRSSFeed.from_db_row + curs = con.cursor() + curs.execute(self.UNREAD_FEEDS) + return curs.fetchall() def get_unread_for_feed(self, token, only_unread=False): if only_unread: @@ -159,16 +201,21 @@ def json_list(data): @app.route('/') def index(): - reader = DBReader(DB_PATH) - return render_template('items.html', items=reader.get_unread()) + return render_template('items.html') -@app.route('/feed/') +@app.route('/feed') def feed_list(): reader = DBReader(DB_PATH) return jsonify({ 'feeds': json_list(reader.get_feeds()) }) +@app.route('/feed/unread') +def unread_feed_list(): + reader = DBReader(DB_PATH) + return jsonify({ 'feeds': json_list(reader.get_unread_feeds()) }) + + @app.route('/feed/') def feed(token): reader = DBReader(DB_PATH) @@ -182,13 +229,27 @@ def feed_items(token): return jsonify({ 'items': json_list(unread), "count": len(unread) }) -@app.route('/feed//items/unread') +@app.route('/feed//items/unread', methods=["GET", "POST"]) def unread_feed_items(token): reader = DBReader(DB_PATH) + if request.method == 'POST': + try: + read = bool(int(request.form.get('read'))) + except: + return make_response('', 400) + + reader.update_feed_unread(token, not read) + unread = reader.get_unread_for_feed(token, True) return jsonify({ 'items': json_list(unread), "count": len(unread) }) +@app.route('/item/unread') +def unread_item_list(): + reader = DBReader(DB_PATH) + return jsonify({ 'items': json_list(reader.get_unread()) }) + + @app.route("/item/", methods=["GET", "POST"]) def item(entry_id): #post read=1 diff --git a/templates/items.html b/templates/items.html index 22adbba..e138ece 100644 --- a/templates/items.html +++ b/templates/items.html @@ -8,120 +8,80 @@ font: 12px Georgia,serif; } - .entries li { - position: relative; + #feeds, #feed-items { + margin: 0; + padding: 0; list-style: none; - border: 1px solid #999; - margin: 0.5em 0; + width: 95%; } - .entries { + #feeds-container { margin: 0; padding: 0; + display: inline-block; + vertical-align: top; + border: 1px solid #999; } - .entries a.headline { - display: block; - background: #ddd; - padding: 1em; - color: black; - text-decoration: none; - font-weight: bolder; + #feeds li { + padding: 0.7em; + cursor: pointer; } - .entries .highlighted a.headline { - background-color: #FFFF99; + #minimize-feeds { + cursor: pointer; + padding: 0.7em; + background-color: #ccc; } - .entries li > input.read { - position: absolute; - top: 1em; - right: 1em; + #feed-items li { + position: relative; + border: 1px solid gray; + border-top: none; + width: 1000px; } - .entries .content { - padding: 1em; - display: none; + #feed-items li .title { + display: inline-block; + cursor: pointer; + padding: 0.5em; + margin: 0.1em; + line-height: 1.5em; } - h2 a.mark-all-read { - display: inline-block; - position: absolute; - right: 1em; + #feed-items li:first-child { + border-top: 1px solid gray; } - - + #feed-items li input { + margin: 0.5em; + } - + #feeds li.active { + background-color: #ff9; + border: 1px solid goldenrod; + border-right: none; + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; + } - + .content-iframe { + width: 100%; + border: none; + } + + .no-content { + background: url(http://www.famfamfam.com/lab/icons/silk/icons/tab.png) no-repeat 99% center; + } + + + + + + + + + + -

RSS Entries

- {% for feed, records in items %} -
-

{{ feed }} ({{ records|length }}) Mark All Read

-
    - {% for record in records %} -
  • - {{ record.title }} - -
    -
  • - {% endfor %} +
    +
    Feeds
    +
    - {% endfor %} +
  • + + + + + + + -- cgit v1.2.3