From 4c94b05023567a2bfa1b1dae480ce87618d03b48 Mon Sep 17 00:00:00 2001 From: Aurimas Vinckevicius Date: Thu, 6 Nov 2014 22:06:30 -0600 Subject: [PATCH] New feed data methods --- chrome/content/zotero/xpcom/data/feed.js | 111 +++++++++++++++++- chrome/content/zotero/xpcom/data/feeds.js | 36 ++++++ chrome/content/zotero/xpcom/data/libraries.js | 2 +- 3 files changed, 147 insertions(+), 2 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/feed.js b/chrome/content/zotero/xpcom/data/feed.js index e8e9a4cdf2..41633c15fb 100644 --- a/chrome/content/zotero/xpcom/data/feed.js +++ b/chrome/content/zotero/xpcom/data/feed.js @@ -270,4 +270,113 @@ Zotero.Feed.prototype._finalizeSave = Zotero.Promise.coroutine(function* (env) { Zotero.Feed.prototype._finalizeErase = Zotero.Promise.method(function(env) { Zotero.Feeds.unregister(this.libraryID); return Zotero.Feed._super.prototype._finalizeErase.apply(this, arguments); -}); \ No newline at end of file +}); + +Zotero.Feed.prototype.getExpiredFeedItemIDs = Zotero.Promise.coroutine(function* () { + let sql = "SELECT itemID AS id FROM feedItems " + + "WHERE readTimestamp IS NOT NULL " + + "AND (julianday(readTimestamp, 'utc') + (?) - julianday('now', 'utc')) > 0"; + let expiredIDs = yield Zotero.DB.queryAsync(sql, [{int: this.cleanupAfter}]); + return expiredIDs.map(row => row.id); +}); + +Zotero.Feed.prototype._updateFeed = Zotero.Promise.coroutine(function* () { + let errorMessage = ''; + try { + // Clear expired items + if (this.cleanupAfter) { + let expiredItems = yield this.getExpiredFeedItemIDs(); + Zotero.debug("Cleaning up read feed items..."); + if (expiredItems.length) { + Zotero.debug(expiredItems.join(', ')); + yield Zotero.FeedItems.erase(expiredItems); + } else { + Zotero.debug("No expired feed items"); + } + } + } catch(e) { + Zotero.debug("Error clearing expired feed items."); + Zotero.debug(e); + } + + try { + let fr = new Zotero.FeedReader(this.url); + let itemIterator = fr.createItemIterator(); + let item, toAdd = [], processedGUIDs = []; + while (item = yield itemIterator.next().value) { + if (item.dateModified && this.lastUpdate + && item.dateModified < this.lastUpdate + ) { + Zotero.debug("Item modification date before last update date (" + this._feedLastCheck + ")"); + Zotero.debug(item); + // We can stop now + fr.terminate(); + break; + } + + if (processedGUIDs.indexOf(item.guid) != -1) { + Zotero.debug("Feed item " + item.guid + " already processed from feed."); + continue; + } + processedGUIDs.push(item.guid); + + Zotero.debug("New feed item retrieved:"); + Zotero.debug(item); + + let feedItem = yield Zotero.FeedItems.getAsyncByGUID(item.guid); + if (!feedItem) { + feedItem = new Zotero.FeedItem(); + feedItem.guid = item.guid; + feedItem.setCollections([this.id]); + } else { + Zotero.debug("Feed item " + item.guid + " already in library."); + if (item.dateModified && feedItem.dateModified + && feedItem.dateModified == item.dateModified + ) { + Zotero.debug("Modification date has not changed. Skipping update."); + continue; + } + Zotero.debug("Updating metadata"); + yield feedItem.loadItemData(); + yield feedItem.loadCreators(); + feedItem.isRead = false; + } + + // Delete invalid data + delete item.guid; + + feedItem.fromJSON(item); + toAdd.push(feedItem); + } + + // Save in reverse order + let savePromises = new Array(toAdd.length); + for (let i=toAdd.length-1; i>=0; i--) { + yield toAdd[i].save({skipEditCheck: true, setDateModified: true}); + } + + this.lastUpdate = Zotero.Date.dateToSQL(new Date(), true); + } catch(e) { + Zotero.debug("Error processing feed from " + this.url); + Zotero.debug(e); + errorMessage = e.message || 'Error processing feed'; + } + + this.lastCheck = Zotero.Date.dateToSQL(new Date(), true); + this.lastCheckError = errorMessage || null; + yield this.save({skipEditCheck: true}); +}); + +Zotero.Feed.prototype.updateFeed = function() { + return this._updateFeed() + .finally(function() { + Zotero.Feeds.scheduleNextFeedCheck(); + }); +} + +Zotero.Feed.prototype.erase = Zotero.Promise.coroutine(function* () { + yield this.loadChildItems(); + let childItemIDs = this.getChildItems(true, true); + yield Zotero.FeedItems.erase(childItemIDs); + return Zotero.Feed._super.prototype.erase.call(this); // Don't tell it to delete child items. They're already gone +}) diff --git a/chrome/content/zotero/xpcom/data/feeds.js b/chrome/content/zotero/xpcom/data/feeds.js index 5a3e7f3480..94309b9d4b 100644 --- a/chrome/content/zotero/xpcom/data/feeds.js +++ b/chrome/content/zotero/xpcom/data/feeds.js @@ -110,4 +110,40 @@ Zotero.Feeds = new function() { return !!Object.keys(this._cache.urlByLibraryID).length } + + this.scheduleNextFeedCheck = Zotero.Promise.coroutine(function* () { + Zotero.debug("Scheduling next feed update."); + let sql = "SELECT ( CASE " + + "WHEN lastCheck IS NULL THEN 0 " + + "ELSE julianday(lastCheck, 'utc') + (refreshInterval/1440.0) - julianday('now', 'utc') " + + "END ) * 1440 AS nextCheck " + + "FROM feeds WHERE refreshInterval IS NOT NULL " + + "ORDER BY nextCheck ASC LIMIT 1"; + var nextCheck = yield Zotero.DB.valueQueryAsync(sql); + + if (this._nextFeedCheck) { + this._nextFeedCheck.cancel(); + this._nextFeedCheck = null; + } + + if (nextCheck !== false) { + nextCheck = nextCheck > 0 ? Math.ceil(nextCheck * 60000) : 0; + Zotero.debug("Next feed check in " + nextCheck/60000 + " minutes"); + this._nextFeedCheck = Zotero.Promise.delay(nextCheck).cancellable(); + Zotero.Promise.all([this._nextFeedCheck, globalFeedCheckDelay]) + .then(() => { + globalFeedCheckDelay = Zotero.Promise.delay(60000); // Don't perform auto-updates more than once per minute + return this.updateFeeds() + }) + .catch(e => { + if (e instanceof Zotero.Promise.CancellationError) { + Zotero.debug('Next update check cancelled'); + return; + } + throw e; + }); + } else { + Zotero.debug("No feeds with auto-update."); + } + }); } diff --git a/chrome/content/zotero/xpcom/data/libraries.js b/chrome/content/zotero/xpcom/data/libraries.js index 39cc8ea1c2..d0a5177ee6 100644 --- a/chrome/content/zotero/xpcom/data/libraries.js +++ b/chrome/content/zotero/xpcom/data/libraries.js @@ -298,7 +298,7 @@ Zotero.Libraries = new function () { this._ensureExists(libraryID); return Zotero.Libraries.get(libraryID).filesEditable; }; - + /** * @deprecated *