commit 4c94b05023567a2bfa1b1dae480ce87618d03b48
parent ca36096bcf2401b59334fd58d27ada32d4184179
Author: Aurimas Vinckevicius <aurimas.dev@gmail.com>
Date: Thu, 6 Nov 2014 22:06:30 -0600
New feed data methods
Diffstat:
3 files changed, 147 insertions(+), 3 deletions(-)
diff --git 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
@@ -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
@@ -298,7 +298,7 @@ Zotero.Libraries = new function () {
this._ensureExists(libraryID);
return Zotero.Libraries.get(libraryID).filesEditable;
};
-
+
/**
* @deprecated
*