mirror of
https://github.com/viq/NewsBlur.git
synced 2025-11-01 09:09:16 +00:00
Fixing a metric-ton of bugs: Google Reader import on badly parsed xml, refreshing toplevel feeds loses their manage menu, retrying exception feeds now de-dupes and correctly updates on the page. Plus a bunch of other bugs.
This commit is contained in:
parent
5afdaf6836
commit
4fd6a7cfe0
12 changed files with 256 additions and 91 deletions
|
|
@ -4,7 +4,8 @@ from django.contrib.auth.models import User
|
|||
from apps.rss_feeds.models import Feed, DuplicateFeed
|
||||
from apps.reader.models import UserSubscription, UserSubscriptionFolders
|
||||
import datetime
|
||||
import lxml.etree
|
||||
from StringIO import StringIO
|
||||
from lxml import etree
|
||||
from utils import json_functions as json, urlnorm
|
||||
import utils.opml as opml
|
||||
from utils import log as logging
|
||||
|
|
@ -114,7 +115,9 @@ class GoogleReaderImporter(Importer):
|
|||
|
||||
|
||||
def parse(self):
|
||||
self.feeds = lxml.etree.fromstring(self.feeds_xml).xpath('/object/list/object')
|
||||
parser = etree.XMLParser(recover=True)
|
||||
tree = etree.parse(StringIO(self.feeds_xml), parser)
|
||||
self.feeds = tree.xpath('/object/list/object')
|
||||
|
||||
def process_item(self, item, folders):
|
||||
feed_title = item.xpath('./string[@name="title"]') and \
|
||||
|
|
|
|||
15
apps/reader/managers.py
Normal file
15
apps/reader/managers.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
from django.db import models
|
||||
from apps.rss_feeds.models import DuplicateFeed
|
||||
from utils import log as logging
|
||||
|
||||
class UserSubscriptionManager(models.Manager):
|
||||
def get(self, *args, **kwargs):
|
||||
try:
|
||||
return super(UserSubscriptionManager, self).get(*args, **kwargs)
|
||||
except:
|
||||
dupe_feed = DuplicateFeed.objects.filter(duplicate_feed_id=kwargs['feed'].pk)
|
||||
if dupe_feed:
|
||||
feed = dupe_feed[0].feed
|
||||
kwargs['feed'] = feed
|
||||
logging.debug(" ---> [%s] ~BRFound dupe UserSubscription: ~SB%s" % (kwargs['user'].username, kwargs['feed']))
|
||||
return super(UserSubscriptionManager, self).get(*args, **kwargs)
|
||||
|
|
@ -6,12 +6,14 @@ from django.db import models, IntegrityError
|
|||
from django.conf import settings
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.cache import cache
|
||||
from apps.reader.managers import UserSubscriptionManager
|
||||
from apps.rss_feeds.models import Feed, MStory, DuplicateFeed
|
||||
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 utils import urlnorm
|
||||
from utils.feed_functions import fetch_address_from_page
|
||||
from utils.feed_functions import add_object_to_folder
|
||||
from utils.feed_functions import relative_timesince
|
||||
|
||||
class UserSubscription(models.Model):
|
||||
"""
|
||||
|
|
@ -37,10 +39,42 @@ class UserSubscription(models.Model):
|
|||
needs_unread_recalc = models.BooleanField(default=False)
|
||||
feed_opens = models.IntegerField(default=0)
|
||||
is_trained = models.BooleanField(default=False)
|
||||
|
||||
objects = UserSubscriptionManager()
|
||||
|
||||
def __unicode__(self):
|
||||
return '[' + self.feed.feed_title + '] '
|
||||
|
||||
def canonical(self, full=False):
|
||||
feed = {
|
||||
'id': self.feed.pk,
|
||||
'feed_title': self.user_title or self.feed.feed_title,
|
||||
'feed_address': self.feed.feed_address,
|
||||
'feed_link': self.feed.feed_link,
|
||||
'ps': self.unread_count_positive,
|
||||
'nt': self.unread_count_neutral,
|
||||
'ng': self.unread_count_negative,
|
||||
'updated': relative_timesince(self.feed.last_update),
|
||||
'subs': self.feed.num_subscribers,
|
||||
'active': self.active,
|
||||
'favicon': self.feed.icon.data,
|
||||
'favicon_color': self.feed.icon.color,
|
||||
'favicon_fetching': bool(not (self.feed.icon.not_found or self.feed.icon.data))
|
||||
}
|
||||
|
||||
if not self.feed.fetched_once:
|
||||
feed['not_yet_fetched'] = True
|
||||
if self.feed.has_page_exception or self.feed.has_feed_exception:
|
||||
feed['has_exception'] = True
|
||||
feed['exception_type'] = 'feed' if self.feed.has_feed_exception else 'page'
|
||||
feed['exception_code'] = self.feed.exception_code
|
||||
elif full:
|
||||
feed['has_exception'] = False
|
||||
feed['exception_type'] = None
|
||||
feed['exception_code'] = self.feed.exception_code
|
||||
|
||||
return feed
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
try:
|
||||
super(UserSubscription, self).save(*args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -140,30 +140,9 @@ 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] = {
|
||||
'id': sub.feed.pk,
|
||||
'feed_title': sub.user_title or sub.feed.feed_title,
|
||||
'feed_address': sub.feed.feed_address,
|
||||
'feed_link': sub.feed.feed_link,
|
||||
'ps': sub.unread_count_positive,
|
||||
'nt': sub.unread_count_neutral,
|
||||
'ng': sub.unread_count_negative,
|
||||
'updated': relative_timesince(sub.feed.last_update),
|
||||
'subs': sub.feed.num_subscribers,
|
||||
'active': sub.active,
|
||||
'favicon': sub.feed.icon.data,
|
||||
'favicon_color': sub.feed.icon.color,
|
||||
'favicon_fetching': bool(not (sub.feed.icon.not_found or sub.feed.icon.data))
|
||||
}
|
||||
|
||||
if not sub.feed.fetched_once:
|
||||
feeds[sub.feed.pk] = sub.canonical()
|
||||
if feeds[sub.feed.pk].get('not_yet_fetched'):
|
||||
not_yet_fetched = True
|
||||
feeds[sub.feed.pk]['not_yet_fetched'] = True
|
||||
if sub.feed.has_page_exception or sub.feed.has_feed_exception:
|
||||
feeds[sub.feed.pk]['has_exception'] = True
|
||||
feeds[sub.feed.pk]['exception_type'] = 'feed' if sub.feed.has_feed_exception else 'page'
|
||||
feeds[sub.feed.pk]['feed_address'] = sub.feed.feed_address
|
||||
feeds[sub.feed.pk]['exception_code'] = sub.feed.exception_code
|
||||
if not sub.feed.active and not sub.feed.has_feed_exception and not sub.feed.has_page_exception:
|
||||
sub.feed.count_subscribers()
|
||||
sub.feed.schedule_feed_fetch_immediately()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
# encoding: utf-8
|
||||
import datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
|
||||
# Removing unique constraint on 'DuplicateFeed', fields ['duplicate_address']
|
||||
db.delete_unique('rss_feeds_duplicatefeed', ['duplicate_address'])
|
||||
|
||||
# Changing field 'FeedData.feed_tagline'
|
||||
db.alter_column('rss_feeds_feeddata', 'feed_tagline', self.gf('django.db.models.fields.CharField')(max_length=1000, null=True))
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Adding unique constraint on 'DuplicateFeed', fields ['duplicate_address']
|
||||
db.create_unique('rss_feeds_duplicatefeed', ['duplicate_address'])
|
||||
|
||||
# Changing field 'FeedData.feed_tagline'
|
||||
db.alter_column('rss_feeds_feeddata', 'feed_tagline', self.gf('django.db.models.fields.CharField')(max_length=1024, null=True))
|
||||
|
||||
|
||||
models = {
|
||||
'rss_feeds.duplicatefeed': {
|
||||
'Meta': {'object_name': 'DuplicateFeed'},
|
||||
'duplicate_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'duplicate_feed_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True'}),
|
||||
'feed': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'duplicate_addresses'", 'to': "orm['rss_feeds.Feed']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
|
||||
},
|
||||
'rss_feeds.feed': {
|
||||
'Meta': {'ordering': "['feed_title']", 'object_name': 'Feed', 'db_table': "'feeds'"},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True', 'db_index': 'True'}),
|
||||
'active_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1', 'db_index': 'True'}),
|
||||
'average_stories_per_month': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'creation': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'days_to_trim': ('django.db.models.fields.IntegerField', [], {'default': '90'}),
|
||||
'etag': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'exception_code': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'feed_address': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '255'}),
|
||||
'feed_link': ('django.db.models.fields.URLField', [], {'default': "''", 'max_length': '1000', 'null': 'True', 'blank': 'True'}),
|
||||
'feed_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '255', 'null': 'True', 'blank': 'True'}),
|
||||
'fetched_once': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_feed_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
|
||||
'has_page_exception': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'db_index': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_load_time': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'last_modified': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'last_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
|
||||
'min_to_decay': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||
'next_scheduled_update': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
|
||||
'num_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
|
||||
'premium_subscribers': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
|
||||
'queued_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}),
|
||||
'stories_last_month': ('django.db.models.fields.IntegerField', [], {'default': '0'})
|
||||
},
|
||||
'rss_feeds.feeddata': {
|
||||
'Meta': {'object_name': 'FeedData'},
|
||||
'feed': ('utils.fields.AutoOneToOneField', [], {'related_name': "'data'", 'unique': 'True', 'to': "orm['rss_feeds.Feed']"}),
|
||||
'feed_tagline': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'popular_authors': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'null': 'True', 'blank': 'True'}),
|
||||
'popular_tags': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'null': 'True', 'blank': 'True'}),
|
||||
'story_count_history': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
|
||||
},
|
||||
'rss_feeds.feedicon': {
|
||||
'Meta': {'object_name': 'FeedIcon'},
|
||||
'color': ('django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
|
||||
'data': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
|
||||
'feed': ('utils.fields.AutoOneToOneField', [], {'related_name': "'icon'", 'unique': 'True', 'primary_key': 'True', 'to': "orm['rss_feeds.Feed']"}),
|
||||
'icon_url': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}),
|
||||
'not_found': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
'rss_feeds.feedloadtime': {
|
||||
'Meta': {'object_name': 'FeedLoadtime'},
|
||||
'date_accessed': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'feed': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['rss_feeds.Feed']"}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'loadtime': ('django.db.models.fields.FloatField', [], {})
|
||||
},
|
||||
'rss_feeds.feedupdatehistory': {
|
||||
'Meta': {'object_name': 'FeedUpdateHistory'},
|
||||
'average_per_feed': ('django.db.models.fields.DecimalField', [], {'max_digits': '4', 'decimal_places': '1'}),
|
||||
'fetch_date': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'number_of_feeds': ('django.db.models.fields.IntegerField', [], {}),
|
||||
'seconds_taken': ('django.db.models.fields.IntegerField', [], {})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['rss_feeds']
|
||||
|
|
@ -338,6 +338,7 @@ class Feed(models.Model):
|
|||
disp = feed_fetcher.Dispatcher(options, 1)
|
||||
disp.add_jobs([[self.pk]])
|
||||
disp.run_jobs()
|
||||
return self
|
||||
|
||||
def add_update_stories(self, stories, existing_stories):
|
||||
ret_values = {
|
||||
|
|
@ -910,7 +911,7 @@ class FeedLoadtime(models.Model):
|
|||
return "%s: %s sec" % (self.feed, self.loadtime)
|
||||
|
||||
class DuplicateFeed(models.Model):
|
||||
duplicate_address = models.CharField(max_length=255, unique=True)
|
||||
duplicate_address = models.CharField(max_length=255)
|
||||
duplicate_feed_id = models.CharField(max_length=255, null=True)
|
||||
feed = models.ForeignKey(Feed, related_name='duplicate_addresses')
|
||||
|
||||
|
|
|
|||
|
|
@ -88,11 +88,12 @@ def exception_retry(request):
|
|||
feed.fetched_once = True
|
||||
feed.save()
|
||||
|
||||
feed.update(force=True, compute_scores=False)
|
||||
feed = feed.update(force=True, compute_scores=False)
|
||||
usersub = UserSubscription.objects.get(user=request.user, feed=feed)
|
||||
usersub.calculate_feed_scores(silent=False)
|
||||
|
||||
return {'code': 1}
|
||||
feeds = {feed.pk: usersub.canonical(full=True)}
|
||||
return {'code': 1, 'feeds': feeds}
|
||||
|
||||
|
||||
@ajax_login_required
|
||||
|
|
@ -125,7 +126,11 @@ def exception_change_feed_address(request):
|
|||
logging.info(" ---> [%s] ~FRFixing feed exception by address: ~SB%s" % (request.user, retry_feed.feed_address))
|
||||
retry_feed.update()
|
||||
|
||||
return {'code': 1}
|
||||
usersub = UserSubscription.objects.get(user=request.user, feed=retry_feed)
|
||||
usersub.calculate_feed_scores(silent=False)
|
||||
|
||||
feeds = {feed.pk: usersub.canonical(full=True)}
|
||||
return {'code': 1, 'feeds': feeds}
|
||||
|
||||
@ajax_login_required
|
||||
@json.json_view
|
||||
|
|
@ -162,6 +167,10 @@ def exception_change_feed_link(request):
|
|||
logging.info(" ---> [%s] ~FRFixing feed exception by link: ~SB%s" % (request.user, retry_feed.feed_link))
|
||||
retry_feed.update()
|
||||
|
||||
return {'code': code}
|
||||
usersub = UserSubscription.objects.get(user=request.user, feed=retry_feed)
|
||||
usersub.calculate_feed_scores(silent=False)
|
||||
|
||||
feeds = {feed.pk: usersub.canonical(full=True)}
|
||||
return {'code': code, 'feeds': feeds}
|
||||
|
||||
|
||||
|
|
@ -331,37 +331,7 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
var self = this;
|
||||
|
||||
var pre_callback = function(data) {
|
||||
var updated_feeds = [];
|
||||
|
||||
for (var f in data.feeds) {
|
||||
if (!self.feeds[f]) continue;
|
||||
var updated = false;
|
||||
f = parseInt(f, 10);
|
||||
var feed = data.feeds[f];
|
||||
for (var k in feed) {
|
||||
if (self.feeds[f][k] != feed[k]) {
|
||||
// NEWSBLUR.log(['New Feed', self.feeds[f][k], feed[k], f, k]);
|
||||
self.feeds[f][k] = feed[k];
|
||||
NEWSBLUR.log(['Different', k, self.feeds[f], feed]);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if ((feed['has_exception'] && !self.feeds[f]['has_exception']) ||
|
||||
(self.feeds[f]['has_exception'] && !feed['has_exception'])) {
|
||||
updated = true;
|
||||
self.feeds[f]['has_exception'] = !!feed['has_exception'];
|
||||
}
|
||||
if (feed['favicon']) {
|
||||
self.feeds[f]['favicon'] = feed['favicon'];
|
||||
self.feeds[f]['favicon_color'] = feed['favicon_color'];
|
||||
self.feeds[f]['favicon_fetching'] = false;
|
||||
updated = true;
|
||||
}
|
||||
if (updated && !(f in updated_feeds)) {
|
||||
updated_feeds.push(f);
|
||||
}
|
||||
}
|
||||
callback(updated_feeds);
|
||||
self.post_refresh_feeds(data, callback);
|
||||
};
|
||||
|
||||
var data = {};
|
||||
|
|
@ -382,6 +352,44 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
post_refresh_feeds: function(data, callback) {
|
||||
var updated_feeds = [];
|
||||
|
||||
for (var f in data.feeds) {
|
||||
if (!this.feeds[f]) continue;
|
||||
var updated = false;
|
||||
f = parseInt(f, 10);
|
||||
var feed = data.feeds[f];
|
||||
if (feed.id && f != feed.id) {
|
||||
NEWSBLUR.log(['Dupe feed being refreshed', f, feed.id, this.feeds[f]]);
|
||||
this.feeds[feed.id] = this.feeds[f];
|
||||
}
|
||||
for (var k in feed) {
|
||||
if (this.feeds[f][k] != feed[k]) {
|
||||
// NEWSBLUR.log(['New Feed', this.feeds[f][k], feed[k], f, k]);
|
||||
this.feeds[f][k] = feed[k];
|
||||
NEWSBLUR.log(['Different', k, this.feeds[f], feed]);
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
if ((feed['has_exception'] && !this.feeds[f]['has_exception']) ||
|
||||
(this.feeds[f]['has_exception'] && !feed['has_exception'])) {
|
||||
updated = true;
|
||||
this.feeds[f]['has_exception'] = !!feed['has_exception'];
|
||||
}
|
||||
if (feed['favicon']) {
|
||||
this.feeds[f]['favicon'] = feed['favicon'];
|
||||
this.feeds[f]['favicon_color'] = feed['favicon_color'];
|
||||
this.feeds[f]['favicon_fetching'] = false;
|
||||
updated = true;
|
||||
}
|
||||
if (updated && !(f in updated_feeds)) {
|
||||
updated_feeds.push(f);
|
||||
}
|
||||
}
|
||||
callback(updated_feeds);
|
||||
},
|
||||
|
||||
refresh_feed: function(feed_id, callback, limit) {
|
||||
var self = this;
|
||||
|
||||
|
|
@ -637,11 +645,17 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
|
||||
save_exception_retry: function(feed_id, callback) {
|
||||
var self = this;
|
||||
|
||||
var pre_callback = function(data) {
|
||||
// NEWSBLUR.log(['refresh_feed pre_callback', data]);
|
||||
self.post_refresh_feeds(data, callback);
|
||||
};
|
||||
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
this.make_request('/rss_feeds/exception_retry', {
|
||||
'feed_id': feed_id,
|
||||
'reset_fetch': !!(this.feeds[feed_id].has_feed_exception || this.feeds[feed_id].has_page_exception)
|
||||
}, callback);
|
||||
}, pre_callback);
|
||||
} else {
|
||||
if ($.isFunction(callback)) callback();
|
||||
}
|
||||
|
|
@ -649,11 +663,18 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
|
||||
save_exception_change_feed_link: function(feed_id, feed_link, callback) {
|
||||
var self = this;
|
||||
|
||||
var pre_callback = function(data) {
|
||||
NEWSBLUR.log(['save_exception_change_feed_link pre_callback', feed_id, feed_link, data]);
|
||||
self.post_refresh_feeds(data, callback);
|
||||
NEWSBLUR.reader.force_feed_refresh(feed_id);
|
||||
};
|
||||
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
this.make_request('/rss_feeds/exception_change_feed_link', {
|
||||
'feed_id': feed_id,
|
||||
'feed_link': feed_link
|
||||
}, callback);
|
||||
}, pre_callback);
|
||||
} else {
|
||||
if ($.isFunction(callback)) callback();
|
||||
}
|
||||
|
|
@ -661,11 +682,18 @@ NEWSBLUR.AssetModel.Reader.prototype = {
|
|||
|
||||
save_exception_change_feed_address: function(feed_id, feed_address, callback) {
|
||||
var self = this;
|
||||
|
||||
var pre_callback = function(data) {
|
||||
NEWSBLUR.log(['save_exception_change_feed_address pre_callback', feed_id, feed_address, data]);
|
||||
self.post_refresh_feeds(data, callback);
|
||||
NEWSBLUR.reader.force_feed_refresh(feed_id);
|
||||
};
|
||||
|
||||
if (NEWSBLUR.Globals.is_authenticated) {
|
||||
this.make_request('/rss_feeds/exception_change_feed_address', {
|
||||
'feed_id': feed_id,
|
||||
'feed_address': feed_address
|
||||
}, callback);
|
||||
}, pre_callback);
|
||||
} else {
|
||||
if ($.isFunction(callback)) callback();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -704,22 +704,23 @@
|
|||
|
||||
make_feeds: function() {
|
||||
var self = this;
|
||||
var $feed_list = this.$s.$feed_list.empty();
|
||||
var $feed_list = this.$s.$feed_list;
|
||||
var folders = this.model.folders;
|
||||
var feeds = this.model.feeds;
|
||||
|
||||
// NEWSBLUR.log(['Making feeds', {'folders': folders, 'feeds': feeds}]);
|
||||
$feed_list.empty();
|
||||
|
||||
this.$s.$story_taskbar.css({'display': 'block'});
|
||||
|
||||
this.flags['has_chosen_feeds'] = this.detect_all_inactive_feeds();
|
||||
this.make_feeds_folder($feed_list, folders, 0);
|
||||
this.$s.$feed_list.css({
|
||||
$feed_list.css({
|
||||
'display': 'block',
|
||||
'opacity': 0
|
||||
}).animate({'opacity': 1}, {'duration': 500});
|
||||
this.hover_over_feed_titles();
|
||||
this.$s.$feed_list.prepend($.make('li', { className: 'feed NB-empty' }));
|
||||
$feed_list.prepend($.make('li', { className: 'feed NB-empty' }));
|
||||
this.$s.$feed_link_loader.fadeOut(250);
|
||||
|
||||
if (folders.length) {
|
||||
|
|
@ -739,8 +740,6 @@
|
|||
|
||||
if (folders.length) {
|
||||
this.load_sortable_feeds();
|
||||
$('.feed', $feed_list).tsort('.feed_title');
|
||||
$('.folder', $feed_list).tsort('.folder_title_text');
|
||||
this.update_header_counts();
|
||||
_.delay(_.bind(this.update_starred_count, this), 250);
|
||||
}
|
||||
|
|
@ -785,9 +784,7 @@
|
|||
$.make('div', { className: 'NB-feedlist-manage-icon' }),
|
||||
$.make('span', { className: 'folder_title_text' }, o)
|
||||
]),
|
||||
$.make('ul', { className: 'folder' }, [
|
||||
$.make('li', { className: 'feed NB-empty' })
|
||||
])
|
||||
$.make('ul', { className: 'folder' }, [])
|
||||
]);
|
||||
var is_collapsed = _.contains(NEWSBLUR.Preferences.collapsed_folders, o);
|
||||
|
||||
|
|
@ -821,6 +818,9 @@
|
|||
// 'opacity': 0
|
||||
// }).animate({'opacity': 1}, {'duration': 500});
|
||||
// }
|
||||
|
||||
// $('.feed', $feeds).tsort('.feed_title');
|
||||
// $('.folder', $feeds).tsort('.folder_title_text');
|
||||
self.hover_over_feed_titles($folder);
|
||||
};
|
||||
if (!self.flags['has_chosen_feeds']) {
|
||||
|
|
@ -833,9 +833,7 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('.feed', $feeds).tsort('.feed_title');
|
||||
$('.folder', $feeds).tsort('.folder_title_text');
|
||||
$feeds.append($.make('li', { className: 'feed NB-empty' }));
|
||||
},
|
||||
|
||||
make_feed_title_line: function(feed, list_item, type) {
|
||||
|
|
@ -1111,7 +1109,6 @@
|
|||
} else {
|
||||
$feeds = $('.feed, .folder_title', $folder);
|
||||
}
|
||||
|
||||
// $feeds.rightClick(function() {
|
||||
// var $this = $(this);
|
||||
// if ($this.is('.feed')) {
|
||||
|
|
@ -4043,6 +4040,7 @@
|
|||
|
||||
this.force_feeds_refresh(function(feeds) {
|
||||
var $new_feed = self.make_feed_title_line(feeds[feed_id], true, 'feed');
|
||||
if ($feed.hasClass('NB-toplevel')) $new_feed.addClass('NB-toplevel');
|
||||
$feed.replaceWith($new_feed);
|
||||
self.hover_over_feed_titles($new_feed);
|
||||
if (self.active_feed == feed_id) {
|
||||
|
|
@ -4056,7 +4054,7 @@
|
|||
var refresh_interval = this.FEED_REFRESH_INTERVAL;
|
||||
|
||||
if (new_feeds) {
|
||||
refresh_interval = (1000 * 60) * 1/4;
|
||||
refresh_interval = (1000 * 60) * 1/6;
|
||||
}
|
||||
|
||||
clearInterval(this.flags.feed_refresh);
|
||||
|
|
@ -4067,7 +4065,7 @@
|
|||
self.post_feed_refresh(updated_feeds);
|
||||
}, self), self.flags['has_unfetched_feeds']);
|
||||
}
|
||||
}, this.FEED_REFRESH_INTERVAL);
|
||||
}, refresh_interval);
|
||||
},
|
||||
|
||||
force_feeds_refresh: function(callback, update_all) {
|
||||
|
|
@ -4109,6 +4107,7 @@
|
|||
if (!this.flags['has_unfetched_feeds']) {
|
||||
NEWSBLUR.log(['UPDATING', feed.feed_title, $feed, $feed_on_page]);
|
||||
}
|
||||
if ($feed_on_page.hasClass('NB-toplevel')) $feed.addClass('NB-toplevel');
|
||||
$feed_on_page.replaceWith($feed);
|
||||
}
|
||||
this.hover_over_feed_titles($feed);
|
||||
|
|
@ -4481,7 +4480,7 @@
|
|||
|
||||
setTimeout(function() {
|
||||
if (self.flags['count_unreads_after_import_working']) {
|
||||
this.animate_progress_bar($bar, feeds_count / 10);
|
||||
self.animate_progress_bar($bar, feeds_count / 10);
|
||||
self.show_progress_bar();
|
||||
}
|
||||
}, 500);
|
||||
|
|
|
|||
|
|
@ -170,8 +170,8 @@ NEWSBLUR.ReaderFeedException.prototype = {
|
|||
$('.NB-modal-submit-retry', this.$modal).addClass('NB-disabled').attr('value', 'Fetching...');
|
||||
|
||||
this.model.save_exception_retry(this.feed_id, function() {
|
||||
NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
NEWSBLUR.reader.force_instafetch_stories(self.feed_id);
|
||||
// NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
// NEWSBLUR.reader.force_instafetch_stories(self.feed_id);
|
||||
$.modal.close();
|
||||
});
|
||||
},
|
||||
|
|
@ -201,8 +201,8 @@ NEWSBLUR.ReaderFeedException.prototype = {
|
|||
|
||||
if (feed_address.length) {
|
||||
this.model.save_exception_change_feed_address(feed_id, feed_address, function(code) {
|
||||
NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
NEWSBLUR.reader.load_feeds();
|
||||
// NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
// NEWSBLUR.reader.load_feeds();
|
||||
$.modal.close();
|
||||
});
|
||||
}
|
||||
|
|
@ -219,8 +219,8 @@ NEWSBLUR.ReaderFeedException.prototype = {
|
|||
|
||||
if (feed_link.length) {
|
||||
this.model.save_exception_change_feed_link(feed_id, feed_link, function(code) {
|
||||
NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
NEWSBLUR.reader.load_feeds();
|
||||
// NEWSBLUR.reader.flags['has_unfetched_feeds'] = true;
|
||||
// NEWSBLUR.reader.load_feeds();
|
||||
$.modal.close();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ from apps.rss_feeds.icon_importer import IconImporter
|
|||
from utils import feedparser
|
||||
from utils.story_functions import pre_process_story
|
||||
from utils import log as logging
|
||||
from utils.feed_functions import timelimit, TimeoutError, mail_error_to_admin
|
||||
from utils.feed_functions import timelimit, TimeoutError, mail_error_to_admin, utf8encode
|
||||
import time
|
||||
import datetime
|
||||
import traceback
|
||||
|
|
@ -186,7 +186,7 @@ class ProcessFeed:
|
|||
self.feed.feed_title = self.fpf.feed.get('title', self.feed.feed_title)
|
||||
tagline = self.fpf.feed.get('tagline', self.feed.data.feed_tagline)
|
||||
if tagline:
|
||||
self.feed.data.feed_tagline = tagline.encode('utf-8')
|
||||
self.feed.data.feed_tagline = utf8encode(tagline)
|
||||
self.feed.data.save()
|
||||
self.feed.feed_link = self.fpf.feed.get('link') or self.fpf.feed.get('id') or self.feed.feed_link
|
||||
|
||||
|
|
@ -281,7 +281,7 @@ class Dispatcher:
|
|||
ENTRY_ERR: 0
|
||||
}
|
||||
start_time = datetime.datetime.utcnow()
|
||||
|
||||
ret_feed = FEED_ERREXC
|
||||
try:
|
||||
feed = self.refresh_feed(feed_id)
|
||||
|
||||
|
|
@ -347,7 +347,6 @@ class Dispatcher:
|
|||
tb = traceback.format_exc()
|
||||
logging.error(tb)
|
||||
logging.debug('[%d] ! -------------------------' % (feed_id,))
|
||||
ret_feed = FEED_ERREXC
|
||||
feed.save_page_history(550, "Page Error", tb)
|
||||
fetched_feed = None
|
||||
mail_error_to_admin(feed, e)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ def timelimit(timeout):
|
|||
return _2
|
||||
return _1
|
||||
|
||||
def encode(tstr):
|
||||
def utf8encode(tstr):
|
||||
""" Encodes a unicode string in utf-8
|
||||
"""
|
||||
if not tstr:
|
||||
|
|
@ -50,7 +50,10 @@ def encode(tstr):
|
|||
return tstr.encode('utf-8', "xmlcharrefreplace")
|
||||
except UnicodeDecodeError:
|
||||
# it's already UTF8.. sigh
|
||||
return tstr.decode('utf-8').encode('utf-8')
|
||||
try:
|
||||
return tstr.decode('utf-8').encode('utf-8')
|
||||
except UnicodeDecodeError:
|
||||
return ''
|
||||
|
||||
# From: http://www.poromenos.org/node/87
|
||||
def levenshtein_distance(first, second):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue