Merge branch 'master' into feed_settings

* master:
  Revert "Switching to requests from urllib2/httplib. Bring on the page errors."
  Fixing #41: Adding REDIS to local_settings.py.template.
  Revert "Revert "Switching to requests from urllib2/httplib. Bring on the page errors.""
  Revert "Switching to requests from urllib2/httplib. Bring on the page errors."
  Switching to requests from urllib2/httplib. Bring on the page errors.
  Adding a bunch fo keyboard shortcuts.
  Adding elapsed time field to river and feed view.
  Fixing autolinking of text links to no longer indiscriminately replace text, causing double encoding of html entities.
  Fixing the space bar key to not queue, so it's actually useful now!
  Refining media enclosures by adding all types and linking to their source.
  Refining media enclosure detection.
This commit is contained in:
Samuel Clay 2011-11-27 02:41:40 -05:00
commit 36105bf851
10 changed files with 88 additions and 43 deletions

View file

@ -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

View file

@ -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:

2
fabfile.py vendored
View file

@ -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')):

View file

@ -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

View file

@ -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 '<a href="' + $0 +'">' + $0 + '</a>';
}));
if (this.data.indexOf('http') != -1) {
text.replaceWith(this.data.replace(URL_REGEX, function($0, $1) {
console.log(["Replacing text link", $0]);
return '<a href="' + $0 +'">' + $0 + '</a>';
}));
}
}
});
});

View file

@ -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'

View file

@ -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();

View file

@ -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'
])
])
])
]);
},

View file

@ -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()

View file

@ -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'] += """<br><br>
<audio controls="controls">
<source src="%(media_url)s" type="%(media_type)s" />
<a href="%(media_url)s">%(media_url)s</a>
</audio>""" % {'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'] += """<br><br>
<audio controls="controls">
<source src="%(media_url)s" type="%(media_type)s" />
</audio>""" % {
'media_url': media_url,
'media_type': media_type
}
elif 'image' in media_type and media_url:
entry['story_content'] += """<br><br><img src="%s" />""" % media_url
entry['story_content'] += """<br><br>
Download %(media_type)s: <a href="%(media_url)s">%(media_url)s</a>""" % {
'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'))