Skip to content

Commit

Permalink
Text view. Needs a few tweaks and a premium only view.
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelclay committed Jan 9, 2013
1 parent 9303e3d commit 36028cc
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 46 deletions.
20 changes: 18 additions & 2 deletions apps/rss_feeds/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from mongoengine.base import ValidationError
from vendor.timezones.utilities import localtime_for_timezone
from apps.rss_feeds.tasks import UpdateFeeds, PushFeeds
from apps.rss_feeds.text_importer import TextImporter
from apps.search.models import SearchStarredStory, SearchFeed
from utils import json_functions as json
from utils import feedfinder, feedparser
Expand Down Expand Up @@ -1410,6 +1411,7 @@ class MStory(mongo.Document):
story_original_content_z = mongo.BinaryField()
story_latest_content = mongo.StringField()
story_latest_content_z = mongo.BinaryField()
original_text_z = mongo.BinaryField()
story_content_type = mongo.StringField(max_length=255)
story_author_name = mongo.StringField()
story_permalink = mongo.StringField()
Expand Down Expand Up @@ -1465,17 +1467,19 @@ def delete(self, *args, **kwargs):
super(MStory, self).delete(*args, **kwargs)

@classmethod
def find_story(cls, story_feed_id, story_id):
def find_story(cls, story_feed_id, story_id, original_only=False):
from apps.social.models import MSharedStory
original_found = True

story = cls.objects(story_feed_id=story_feed_id,
story_guid=story_id).limit(1).first()

if not story:
original_found = False
if not story and not original_only:
story = MSharedStory.objects.filter(story_feed_id=story_feed_id,
story_guid=story_id).limit(1).first()
if not story:
if not story and not original_only:
story = MStarredStory.objects.filter(story_feed_id=story_feed_id,
story_guid=story_id).limit(1).first()

Expand Down Expand Up @@ -1543,6 +1547,18 @@ def count_comments(self):
self.share_count = shares.count()
self.share_user_ids = [s['user_id'] for s in shares]
self.save()

def fetch_original_text(self, force=False, request=None):
original_text_z = self.original_text_z

if not original_text_z or force:
ti = TextImporter(self, request=request)
original_text = ti.fetch()
else:
logging.user(request, "~FYFetching ~FGoriginal~FY story text, ~SBfound.")
original_text = zlib.decompress(original_text_z)

return original_text


class MStarredStory(mongo.Document):
Expand Down
42 changes: 42 additions & 0 deletions apps/rss_feeds/text_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import requests
import zlib
from django.conf import settings
from vendor.readability import readability
from utils import log as logging


class TextImporter:

def __init__(self, story, request=None):
self.story = story
self.request = request

@property
def headers(self):
return {
'User-Agent': 'NewsBlur Content Fetcher - %s '
'(Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) '
'AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 '
'Safari/534.48.3)' % (
settings.NEWSBLUR_URL
),
'Connection': 'close',
}

def fetch(self):
html = requests.get(self.story.story_permalink, headers=self.headers)
original_text_doc = readability.Document(html.text)
content = original_text_doc.summary()
if content:
self.story.original_text_z = zlib.compress(content)
self.story.save()
logging.user(self.request, "~SN~FYFetched ~FGoriginal text~FY: now ~SB%s bytes~SN vs. was ~SB%s bytes" % (
len(unicode(content)),
len(zlib.decompress(self.story.story_content_z))
))
else:
logging.user(self.request, "~SN~FRFailed~FY to fetch ~FGoriginal text~FY: was ~SB%s bytes" % (
len(zlib.decompress(self.story.story_content_z))
))

return content
1 change: 1 addition & 0 deletions apps/rss_feeds/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@
url(r'^exception_change_feed_link', views.exception_change_feed_link, name='exception-change-feed-link'),
url(r'^status', views.status, name='status'),
url(r'^load_single_feed', views.load_single_feed, name='feed-canonical'),
url(r'^original_text', views.original_text, name='original-text'),
)
25 changes: 24 additions & 1 deletion apps/rss_feeds/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
from apps.rss_feeds.models import MFeedIcon
from apps.analyzer.models import get_classifiers_for_user
from apps.reader.models import UserSubscription
from apps.rss_feeds.models import MStory
from utils.user_functions import ajax_login_required
from utils import json_functions as json, feedfinder
from utils.feed_functions import relative_timeuntil, relative_timesince
from utils.user_functions import get_user
from utils.view_functions import get_argument_or_404
from utils.view_functions import required_params


@json.json_view
Expand Down Expand Up @@ -399,4 +401,25 @@ def status(request):
feeds = Feed.objects.filter(last_update__gte=hour_ago).order_by('-last_update')
return render_to_response('rss_feeds/status.xhtml', {
'feeds': feeds
}, context_instance=RequestContext(request))
}, context_instance=RequestContext(request))

@required_params('story_id', feed_id=int)
@json.json_view
def original_text(request):
story_id = request.GET['story_id']
feed_id = request.GET['feed_id']
force = request.GET.get('force', False)

story, _ = MStory.find_story(story_id=story_id, story_feed_id=feed_id)

if not story:
logging.user(request, "~FYFetching ~FGoriginal~FY story text: ~FRstory not found")
return {'code': -1, 'message': 'Story not found.'}

original_text = story.fetch_original_text(force=force, request=request)

return {
'feed_id': feed_id,
'story_id': story_id,
'original_text': original_text,
}
25 changes: 4 additions & 21 deletions apps/social/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@
from apps.analyzer.models import MClassifierFeed, MClassifierAuthor, MClassifierTag, MClassifierTitle
from apps.analyzer.models import apply_classifier_titles, apply_classifier_feeds, apply_classifier_authors, apply_classifier_tags
from apps.rss_feeds.models import Feed, MStory
from apps.rss_feeds.text_importer import TextImporter
from apps.profile.models import Profile, MSentEmail
from vendor import facebook
from vendor import tweepy
from vendor import pynliner
from vendor.readability import readability
from utils import log as logging
from utils import json_functions as json
from utils.feed_functions import relative_timesince
Expand Down Expand Up @@ -1186,7 +1186,7 @@ class MSharedStory(mongo.Document):
story_content_z = mongo.BinaryField()
story_original_content = mongo.StringField()
story_original_content_z = mongo.BinaryField()
original_article_z = mongo.BinaryField()
original_text_z = mongo.BinaryField()
story_content_type = mongo.StringField(max_length=255)
story_author_name = mongo.StringField()
story_permalink = mongo.StringField()
Expand Down Expand Up @@ -1900,25 +1900,8 @@ def calculate_image_sizes(self, force=False):
return image_sizes

def fetch_original_text(self):
headers = {
'User-Agent': 'NewsBlur Content Fetcher - %s '
'(Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) '
'AppleWebKit/534.48.3 (KHTML, like Gecko) Version/5.1 '
'Safari/534.48.3)' % (
settings.NEWSBLUR_URL
),
'Connection': 'close',
}
html = requests.get(self.story_permalink, headers=headers).text
original_text_doc = readability.Document(html)
content = original_text_doc.content()
self.original_article_z = content and zlib.compress(content)
self.save()

logging.debug(" ---> ~SN~FGFetched original text on shared story: now ~SB%s bytes~SN vs. was ~SB%s bytes" % (
len(unicode(content)),
len(zlib.decompress(self.story_content_z))
))
ti = TextImporter(self)
original_text_doc = ti.fetch()

return original_text_doc

Expand Down
20 changes: 16 additions & 4 deletions media/css/reader.css
Original file line number Diff line number Diff line change
Expand Up @@ -1683,7 +1683,8 @@ background: transparent;
}

#story_pane .NB-feed-iframe,
#story_pane .NB-story-iframe {
#story_pane .NB-story-iframe,
#story_pane .NB-text-view {
width: 100%;
height: 100%;
border: 0;
Expand All @@ -1698,6 +1699,10 @@ background: transparent;
left: 200%;
top: 0;
}
#story_pane .NB-text-view {
left: 300%;
top: 0;
}

/* ================================ */
/* = Feed View Feed Title Floater = */
Expand Down Expand Up @@ -1881,10 +1886,14 @@ background: transparent;
/* text-shadow: 0 1px 0 #E0E0E0;*/
}

#story_pane .NB-feed-stories .NB-feed-story .NB-feed-story-content div {
.NB-feed-story .NB-feed-story-content div {
max-width: 100%;
}
#story_pane .NB-feed-stories .NB-feed-story .NB-feed-story-content img {
.NB-feed-story .NB-feed-story-content pre,
.NB-feed-story .NB-feed-story-content code {
white-space: normal;
}
.NB-feed-story .NB-feed-story-content img {
max-width: 100% !important;
width: auto;
height: auto !important;
Expand Down Expand Up @@ -2543,7 +2552,7 @@ background: transparent;
background: -moz-linear-gradient(center bottom, #bababa 0%, #dadada 100%);
}

#story_pane .NB-feed-stories .NB-feed-story {
.NB-feed-story {
margin: 0;
clear: both;
overflow: hidden;
Expand Down Expand Up @@ -3342,6 +3351,9 @@ background: transparent;
.NB-taskbar .task_button.task_view_story .NB-task-image {
background: transparent url('/media/embed/icons/silk/application_view_gallery.png') no-repeat 0 0;
}
.NB-taskbar .task_button.task_view_text .NB-task-image {
background: transparent url('/media/embed/icons/silk/application_view_columns.png') no-repeat 0 0;
}
.NB-taskbar .task_button.task_view_story.NB-disabled-page .NB-task-image {
background-image: url('/media/embed/icons/silk/error.png');
}
Expand Down
2 changes: 1 addition & 1 deletion media/ios/Resources/storyDetailView.css
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ body.NB-iphone {
.NB-story code {
overflow: auto;
clear: both;

white-space: normal;
}

.NB-story h1,
Expand Down
10 changes: 10 additions & 0 deletions media/js/newsblur/common/assetmodel.js
Original file line number Diff line number Diff line change
Expand Up @@ -1359,6 +1359,16 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
this.make_request('/oauth/unfollow_twitter_account', {'username': username}, callback);
},

fetch_original_text: function(story_id, feed_id, callback, error_callback) {
this.make_request('/rss_feeds/original_text', {
story_id: story_id,
feed_id: feed_id
}, callback, error_callback, {
request_type: 'GET',
ajax_group: 'feed'
});
},

recalculate_story_scores: function(feed_id, options) {
options = options || {};
this.stories.each(_.bind(function(story, i) {
Expand Down
Loading

0 comments on commit 36028cc

Please sign in to comment.