diff --git a/apps/feed_import/views.py b/apps/feed_import/views.py index babf2cbe3..0784d95b9 100644 --- a/apps/feed_import/views.py +++ b/apps/feed_import/views.py @@ -108,7 +108,9 @@ def reader_callback(request): user_token = OAuthToken.objects.get(user=request.user) else: try: - user_token = OAuthToken.objects.get(uuid=request.COOKIES.get('newsblur_reader_uuid')) + user_uuid = request.COOKIES.get('newsblur_reader_uuid') + if not user_uuid: raise OAuthToken.DoesNotExist + user_token = OAuthToken.objects.get(uuid=user_uuid) except OAuthToken.DoesNotExist: user_token = OAuthToken.objects.get(session_id=request.session.session_key) except OAuthToken.DoesNotExist: diff --git a/apps/reader/models.py b/apps/reader/models.py index dba737742..a9330f788 100644 --- a/apps/reader/models.py +++ b/apps/reader/models.py @@ -42,8 +42,8 @@ class UserSubscription(models.Model): def __unicode__(self): return '[' + self.feed.feed_title + '] ' - def canonical(self, full=False): - feed = self.feed.canonical(full=full) + def canonical(self, full=False, include_favicon=True): + feed = self.feed.canonical(full=full, include_favicon=include_favicon) feed['feed_title'] = self.user_title or feed['feed_title'] feed['ps'] = self.unread_count_positive feed['nt'] = self.unread_count_neutral diff --git a/apps/reader/views.py b/apps/reader/views.py index 03f3e7f90..cb16a4363 100644 --- a/apps/reader/views.py +++ b/apps/reader/views.py @@ -128,9 +128,10 @@ def logout(request): @json.json_view def load_feeds(request): - user = get_user(request) - feeds = {} - not_yet_fetched = False + user = get_user(request) + feeds = {} + not_yet_fetched = False + include_favicons = request.REQUEST.get('include_favicons', True) try: folders = UserSubscriptionFolders.objects.get(user=user) @@ -144,7 +145,7 @@ def load_feeds(request): user_subs = UserSubscription.objects.select_related('feed', 'feed__feed_icon').filter(user=user) for sub in user_subs: - feeds[sub.feed.pk] = sub.canonical() + feeds[sub.feed.pk] = sub.canonical(include_favicon=include_favicons) if feeds[sub.feed.pk].get('not_yet_fetched'): not_yet_fetched = True if not sub.feed.active and not sub.feed.has_feed_exception and not sub.feed.has_page_exception: @@ -463,7 +464,7 @@ def load_river_stories(request): # if feed_counts[feed_id] > max_feed_count: # max_feed_count = feed_counts[feed_id] feed_last_reads[feed_id] = int(time.mktime(usersub.mark_read_date.timetuple())) - feed_counts = sorted(feed_counts.items(), key=itemgetter(1))[:25] + feed_counts = sorted(feed_counts.items(), key=itemgetter(1))[:50] feed_ids = [f[0] for f in feed_counts] feed_last_reads = dict([(str(feed_id), feed_last_reads[feed_id]) for feed_id in feed_ids]) feed_counts = dict(feed_counts) diff --git a/apps/rss_feeds/models.py b/apps/rss_feeds/models.py index c2c815b35..bc692f6b0 100644 --- a/apps/rss_feeds/models.py +++ b/apps/rss_feeds/models.py @@ -62,7 +62,7 @@ class Feed(models.Model): self.save() return self.feed_title - def canonical(self, full=False): + def canonical(self, full=False, include_favicon=True): feed = { 'id': self.pk, 'feed_title': self.feed_title, @@ -70,7 +70,7 @@ class Feed(models.Model): 'feed_link': self.feed_link, 'updated': relative_timesince(self.last_update), 'subs': self.num_subscribers, - 'favicon': self.icon.data, + 'favicon': self.icon.data if include_favicon else None, 'favicon_color': self.icon.color, 'favicon_fetching': bool(not (self.icon.not_found or self.icon.data)) } diff --git a/media/css/reader.css b/media/css/reader.css index 156d6db97..00a75f680 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -4971,4 +4971,24 @@ background: transparent; border-color:#C0C0C0 #A0A0A0 #A0A0A0 #C0C0C0; border-style:solid; border-width:1px; +} + +/* ======= */ +/* = API = */ +/* ======= */ + +.NB-static-api table { + width: 620px; +} + +.NB-static-api table th { + background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#FCFCFC), to(#E0E0E0)); + background: -moz-linear-gradient(center bottom, #FCFCFC 0%, #E0E0E0 100%); + border-bottom: 1px solid #BBB; + border-right: 1px solid #BBB; + padding: 7px 20px 7px 10px; + vertical-align: middle; + color: #222; + font-size: 10px; + text-transform: uppercase; } \ No newline at end of file diff --git a/templates/static/api.xhtml b/templates/static/api.xhtml index 0aa8f9b39..097633742 100644 --- a/templates/static/api.xhtml +++ b/templates/static/api.xhtml @@ -1,6 +1,6 @@ {% extends 'base.html' %} -{% block bodyclass %}NB-static{% endblock %} +{% block bodyclass %}NB-static NB-static-api{% endblock %} {% block content %} @@ -11,13 +11,21 @@
API Guidelines and Terms of Service
-

NewsBlur's API allows users to retrieve their feeds, feed counts, feed icons, feed statistics, and individual feed stories. No API key is required, but you are required to authenticate before using any of the API endpoints. Please be considerate, and don't hammer our servers.

- -

If your project or application allows users to interact with data from NewsBlur, you must cite NewsBlur as the source of your data.

- -

You may use the API commercially, by which we mean you may charge people money to use your project which itself uses the API. You may not, however, sell advertising against any data retrieved from NewsBlur's API. Essentially, you can charge money for your application or service, but not wrap NewsBlur in advertisements.

- -

We reserve the right to revise these guidelines. If you violate the spirit of these terms, expect to be blocked without advance warning.

+

NewsBlur's API allows users to retrieve their feeds, feed counts, feed icons, feed + statistics, and individual feed stories. No API key is required, but you are required + to authenticate before using any of the API endpoints. Please be considerate, and don't + hammer our servers.

+ +

If your project or application allows users to interact with data from NewsBlur, + you must cite NewsBlur as the source of your data.

+ +

You may use the API commercially, by which we mean you may charge people money to + use your project which itself uses the API. You may not, however, sell advertising + against any data retrieved from NewsBlur's API. Essentially, you can charge money for + your application or service, but not wrap NewsBlur in advertisements.

+ +

We reserve the right to revise these guidelines. If you violate the spirit of + these terms, expect to be blocked without advance warning.

@@ -25,6 +33,59 @@
Feed Management
+ +

GET /api/reader/feed_list

+ +

Retrieve a user's list of feeds. Includes the 3 unread counts, as well as optional + favicons.

+ + + + + + + + + + + + + + +
ParameterDescriptionDefaultExample
include_faviconsOption to not include favicons in the list of feeds, since they can be time + consuming to download. Use /api/feeds/favicons/ to retrieve the favicons + in a separate request.truetrue/false
+ +

Example Response

+ + + { + 'feeds': [] + } + + +

GET /api/feeds/favicons

+ +

Retrieve a list of favicons for a list of feeds. Used when combined with + /api/reader/feed_list and include_favicons=false, so the feed_list + request contains far less data. Useful for mobile devices, but requires a second + request.

+ + + + + + + + + + + + + + +
ParameterDescriptionDefaultExample
feedsREQUIRED Array of feed ids[1, 2, 3]
+