diff --git a/apps/reader/views.py b/apps/reader/views.py
index c8ffee26b..529d049fd 100644
--- a/apps/reader/views.py
+++ b/apps/reader/views.py
@@ -432,7 +432,8 @@ def load_single_feed(request, feed_id):
feed_authors=feed_authors,
classifiers=classifiers,
last_update=last_update,
- feed_id=feed.pk)
+ feed_id=feed.pk,
+ elapsed_time=round(float(timediff), 2))
if dupe_feed_id: data['dupe_feed_id'] = dupe_feed_id
if not usersub:
@@ -486,13 +487,12 @@ def load_starred_stories(request):
def load_river_stories(request):
limit = 18
offset = 0
- start = datetime.datetime.utcnow()
+ start = time.time()
user = get_user(request)
feed_ids = [int(feed_id) for feed_id in request.REQUEST.getlist('feeds') if feed_id]
original_feed_ids = list(feed_ids)
page = int(request.REQUEST.get('page', 1))
read_stories_count = int(request.REQUEST.get('read_stories_count', 0))
- new_flag = request.REQUEST.get('new_flag', False)
bottom_delta = datetime.timedelta(days=settings.DAYS_OF_UNREAD)
if not feed_ids:
@@ -615,19 +615,15 @@ def load_river_stories(request):
'tags': apply_classifier_tags(classifier_tags[story['story_feed_id']], story),
'title': apply_classifier_titles(classifier_titles[story['story_feed_id']], story),
}
-
- diff = datetime.datetime.utcnow() - start
- timediff = float("%s.%.2s" % (diff.seconds, (diff.microseconds / 1000)))
+
+ diff = time.time() - start
+ timediff = round(float(diff), 2)
logging.user(request, "~FCLoading river stories: page %s - ~SB%s/%s "
"stories ~SN(%s/%s/%s feeds) ~FB(%s seconds)" %
(page, len(stories), len(mstories), len(found_feed_ids),
len(feed_ids), len(original_feed_ids), timediff))
- if new_flag:
- return dict(stories=stories, classifiers=classifiers)
- else:
- logging.user(request, "~BR~FCNo new flag on river")
- return dict(stories=stories)
+ return dict(stories=stories, classifiers=classifiers, elapsed_time=timediff)
@ajax_login_required
diff --git a/apps/rss_feeds/models.py b/apps/rss_feeds/models.py
index 7559c9756..5c434e7ba 100644
--- a/apps/rss_feeds/models.py
+++ b/apps/rss_feeds/models.py
@@ -619,13 +619,8 @@ class Feed(models.Model):
story = pre_process_story(story)
if story.get('title'):
- story_contents = story.get('content')
+ story_content = story.get('story_content')
story_tags = self.get_tags(story)
-
- if story_contents is not None:
- story_content = story_contents[0]['value']
- else:
- story_content = story.get('summary')
existing_story, story_has_changed = self._exists_story(story, story_content, existing_stories)
if existing_story is None:
diff --git a/fabfile.py b/fabfile.py
index 1829425d5..c9dbfeafc 100644
--- a/fabfile.py
+++ b/fabfile.py
@@ -289,7 +289,7 @@ def setup_psycopg():
def setup_python():
sudo('easy_install pip')
- sudo('easy_install fabric django celery django-celery django-compress South django-extensions pymongo BeautifulSoup pyyaml nltk==0.9.9 lxml oauth2 pytz boto seacucumber django_ses mongoengine redis')
+ sudo('easy_install fabric django celery django-celery django-compress South django-extensions pymongo BeautifulSoup pyyaml nltk==0.9.9 lxml oauth2 pytz boto seacucumber django_ses mongoengine redis requests')
put('config/pystartup.py', '.pystartup')
with cd(os.path.join(env.NEWSBLUR_PATH, 'vendor/cjson')):
diff --git a/local_settings.py.template b/local_settings.py.template
index 2970894bd..4e25452c9 100644
--- a/local_settings.py.template
+++ b/local_settings.py.template
@@ -42,6 +42,14 @@ OAUTH_SECRET = 'SECRET_KEY_FROM_GOOGLE'
# Celery RabbitMQ Broker
BROKER_HOST = "127.0.0.1"
+REDIS = {
+ 'host': '127.0.0.1',
+}
+
+# ===========
+# = Logging =
+# ===========
+
# Logging (setup for development)
LOG_TO_STREAM = True
diff --git a/media/js/jquery.newsblur.js b/media/js/jquery.newsblur.js
index a281e3978..fcc15d11b 100644
--- a/media/js/jquery.newsblur.js
+++ b/media/js/jquery.newsblur.js
@@ -35,13 +35,16 @@ NEWSBLUR.log = function(msg) {
autolink: function() {
return this.each(function(){
- var desc = $(this);
- desc.textNodes().each(function(){
+ var $desc = $(this);
+ $desc.textNodes().each(function(){
var text = $(this);
if(text && text.parent() && text.parent()[0] && text.parent()[0].nodeName != 'A') {
- text.replaceWith(this.data.replace(URL_REGEX, function($0, $1) {
- return '' + $0 + ' ';
- }));
+ if (this.data.indexOf('http') != -1) {
+ text.replaceWith(this.data.replace(URL_REGEX, function($0, $1) {
+ console.log(["Replacing text link", $0]);
+ return '' + $0 + ' ';
+ }));
+ }
}
});
});
diff --git a/media/js/newsblur/assetmodel.js b/media/js/newsblur/assetmodel.js
index 6f2535b88..f1143a26e 100644
--- a/media/js/newsblur/assetmodel.js
+++ b/media/js/newsblur/assetmodel.js
@@ -405,9 +405,7 @@ NEWSBLUR.AssetModel.Reader.prototype = {
this.make_request('/reader/river_stories', {
feeds: feeds,
page: page,
- read_stories_count: this.read_stories_river_count,
- // TODO: Remove new flag
- new_flag: true
+ read_stories_count: this.read_stories_river_count
}, pre_callback, error_callback, {
'ajax_group': (page ? 'feed_page' : 'feed'),
'request_type': 'GET'
diff --git a/media/js/newsblur/reader.js b/media/js/newsblur/reader.js
index 7d27659f3..0d0509b36 100644
--- a/media/js/newsblur/reader.js
+++ b/media/js/newsblur/reader.js
@@ -974,9 +974,9 @@
}
// NEWSBLUR.log(['page_in_story', this.$s.$story_pane, direction, page_height, scroll_height]);
if (this.story_view == 'page') {
- this.$s.$feed_iframe.scrollTo({top:dir+'='+scroll_height, left:'+=0'}, 260);
+ this.$s.$feed_iframe.scrollTo({top:dir+'='+scroll_height, left:'+=0'}, 230, {queue: false});
} else if (this.story_view == 'feed') {
- this.$s.$feed_stories.scrollTo({top:dir+'='+scroll_height, left:'+=0'}, 370);
+ this.$s.$feed_stories.scrollTo({top:dir+'='+scroll_height, left:'+=0'}, 340, {queue: false});
}
},
@@ -6649,7 +6649,7 @@
});
$document.bind('keydown', 'shift+space', function(e) {
e.preventDefault();
- self.page_in_story(0.6, -1);
+ self.page_in_story(0.65, -1);
});
$document.bind('keydown', 'u', function(e) {
e.preventDefault();
diff --git a/media/js/newsblur/reader_keyboard.js b/media/js/newsblur/reader_keyboard.js
index da7525215..89d039c59 100644
--- a/media/js/newsblur/reader_keyboard.js
+++ b/media/js/newsblur/reader_keyboard.js
@@ -88,7 +88,7 @@ NEWSBLUR.ReaderKeyboard.prototype = {
])
]),
$.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [
- $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Open Site'),
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Open in Story view'),
$.make('div', { className: 'NB-keyboard-shortcut-key' }, [
'enter'
]),
@@ -166,13 +166,43 @@ NEWSBLUR.ReaderKeyboard.prototype = {
])
]),
$.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [
- $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Mark site/folder as read'),
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Mark all as read'),
$.make('div', { className: 'NB-keyboard-shortcut-key' }, [
'shift',
$.make('span', '+'),
'a'
])
])
+ ]),
+ $.make('div', { className: 'NB-keyboard-group' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Return to dashboard'),
+ $.make('div', { className: 'NB-keyboard-shortcut-key' }, [
+ 'd'
+ ])
+ ]),
+ $.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Open Everything'),
+ $.make('div', { className: 'NB-keyboard-shortcut-key' }, [
+ 'shift',
+ $.make('span', '+'),
+ 'e'
+ ])
+ ])
+ ]),
+ $.make('div', { className: 'NB-keyboard-group' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'View keyboard shortcuts'),
+ $.make('div', { className: 'NB-keyboard-shortcut-key' }, [
+ '?'
+ ])
+ ]),
+ $.make('div', { className: 'NB-keyboard-shortcut NB-last' }, [
+ $.make('div', { className: 'NB-keyboard-shortcut-explanation' }, 'Find oldest unread story'),
+ $.make('div', { className: 'NB-keyboard-shortcut-key' }, [
+ 'm'
+ ])
+ ])
])
]);
},
diff --git a/utils/feed_fetcher.py b/utils/feed_fetcher.py
index b3ce5b79f..223f05e40 100644
--- a/utils/feed_fetcher.py
+++ b/utils/feed_fetcher.py
@@ -247,7 +247,7 @@ class ProcessFeed:
# ).order_by('-story_date')
ret_values = self.feed.add_update_stories(self.fpf.entries, existing_stories, verbose=self.options['verbose'])
- logging.debug(u' ---> [%-30s] ~FYParsed Feed: new~FG=~FG~SB%s~SN~FY up~FG=~FY~SB%s~SN same~FG=~FY%s err~FG=~FR~SB%s' % (
+ logging.debug(u' ---> [%-30s] ~FYParsed Feed: new=~FG~SB%s~SN~FY up=~FY~SB%s~SN same=~FY%s err=~FR~SB%s' % (
unicode(self.feed)[:30],
ret_values[ENTRY_NEW], ret_values[ENTRY_UPDATED], ret_values[ENTRY_SAME], ret_values[ENTRY_ERR]))
self.feed.update_all_statistics()
diff --git a/utils/story_functions.py b/utils/story_functions.py
index d78b21115..e2769b47f 100644
--- a/utils/story_functions.py
+++ b/utils/story_functions.py
@@ -67,18 +67,33 @@ def pre_process_story(entry):
entry['link'] = urlquote(entry_link)
if isinstance(entry.get('guid'), dict):
entry['guid'] = unicode(entry['guid'])
- entry_content = ""
+
+ # Normalize story content/summary
if entry.get('content'):
- entry_content = entry['content'][0]['value']
- if entry.get('media_content') and 'audio controls' not in entry_content:
- media_url = entry['media_content'][0].get('url') and entry['media_content'][0]['url']
- media_type = entry['media_content'][0].get('type') and entry['media_content'][0]['type']
- if media_url and media_type:
- entry['content'][0]['value'] += """
-
-
- %(media_url)s
- """ % {'media_url': media_url, 'media_type': media_type}
+ entry['story_content'] = entry['content'][0].get('value', '')
+ else:
+ entry['story_content'] = entry.get('summary', '')
+
+ # Add each media enclosure as a Download link
+ for media_content in entry.get('media_content', []):
+ media_url = media_content.get('url', '')
+ media_type = media_content.get('type', '')
+ if media_url and media_type and media_url not in entry['story_content']:
+ if 'audio' in media_type and media_url:
+ entry['story_content'] += """
+
+
+ """ % {
+ 'media_url': media_url,
+ 'media_type': media_type
+ }
+ elif 'image' in media_type and media_url:
+ entry['story_content'] += """ """ % media_url
+ entry['story_content'] += """
+ Download %(media_type)s: %(media_url)s """ % {
+ 'media_url': media_url,
+ 'media_type': media_type.split('/')[0]
+ }
entry['guid'] = entry.get('guid') or entry.get('id') or entry.get('link') or str(entry.get('published'))