Search in sources :

Example 1 with FeedListUpdateEvent

use of de.danoeh.antennapod.event.FeedListUpdateEvent in project AntennaPod by AntennaPod.

the class DBTasks method updateFeed.

/**
 * Adds new Feeds to the database or updates the old versions if they already exists. If another Feed with the same
 * identifying value already exists, this method will add new FeedItems from the new Feed to the existing Feed.
 * These FeedItems will be marked as unread with the exception of the most recent FeedItem.
 * <p/>
 * This method can update multiple feeds at once. Submitting a feed twice in the same method call can result in undefined behavior.
 * <p/>
 * This method should NOT be executed on the GUI thread.
 *
 * @param context Used for accessing the DB.
 * @param newFeed The new Feed object.
 * @param removeUnlistedItems The item list in the new Feed object is considered to be exhaustive.
 *                            I.e. items are removed from the database if they are not in this item list.
 * @return The updated Feed from the database if it already existed, or the new Feed from the parameters otherwise.
 */
public static synchronized Feed updateFeed(Context context, Feed newFeed, boolean removeUnlistedItems) {
    Feed resultFeed;
    List<FeedItem> unlistedItems = new ArrayList<>();
    PodDBAdapter adapter = PodDBAdapter.getInstance();
    adapter.open();
    // Look up feed in the feedslist
    final Feed savedFeed = searchFeedByIdentifyingValueOrID(adapter, newFeed);
    if (savedFeed == null) {
        Log.d(TAG, "Found no existing Feed with title " + newFeed.getTitle() + ". Adding as new one.");
        // Add a new Feed
        // all new feeds will have the most recent item marked as unplayed
        FeedItem mostRecent = newFeed.getMostRecentItem();
        if (mostRecent != null) {
            mostRecent.setNew();
        }
        resultFeed = newFeed;
    } else {
        Log.d(TAG, "Feed with title " + newFeed.getTitle() + " already exists. Syncing new with existing one.");
        Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator());
        if (newFeed.getPageNr() == savedFeed.getPageNr()) {
            if (savedFeed.compareWithOther(newFeed)) {
                Log.d(TAG, "Feed has updated attribute values. Updating old feed's attributes");
                savedFeed.updateFromOther(newFeed);
            }
        } else {
            Log.d(TAG, "New feed has a higher page number.");
            savedFeed.setNextPageLink(newFeed.getNextPageLink());
        }
        if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) {
            Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences");
            savedFeed.getPreferences().updateFromOther(newFeed.getPreferences());
        }
        // get the most recent date now, before we start changing the list
        FeedItem priorMostRecent = savedFeed.getMostRecentItem();
        Date priorMostRecentDate = null;
        if (priorMostRecent != null) {
            priorMostRecentDate = priorMostRecent.getPubDate();
        }
        // Look for new or updated Items
        for (int idx = 0; idx < newFeed.getItems().size(); idx++) {
            final FeedItem item = newFeed.getItems().get(idx);
            FeedItem possibleDuplicate = searchFeedItemGuessDuplicate(newFeed.getItems(), item);
            if (!newFeed.isLocalFeed() && possibleDuplicate != null && item != possibleDuplicate) {
                // Canonical episode is the first one returned (usually oldest)
                DBWriter.addDownloadStatus(new DownloadStatus(savedFeed, item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false, "The podcast host appears to have added the same episode twice. " + "AntennaPod still refreshed the feed and attempted to repair it." + "\n\nOriginal episode:\n" + duplicateEpisodeDetails(item) + "\n\nSecond episode that is also in the feed:\n" + duplicateEpisodeDetails(possibleDuplicate), false));
                continue;
            }
            FeedItem oldItem = searchFeedItemByIdentifyingValue(savedFeed.getItems(), item);
            if (!newFeed.isLocalFeed() && oldItem == null) {
                oldItem = searchFeedItemGuessDuplicate(savedFeed.getItems(), item);
                if (oldItem != null) {
                    Log.d(TAG, "Repaired duplicate: " + oldItem + ", " + item);
                    DBWriter.addDownloadStatus(new DownloadStatus(savedFeed, item.getTitle(), DownloadError.ERROR_PARSER_EXCEPTION_DUPLICATE, false, "The podcast host changed the ID of an existing episode instead of just " + "updating the episode itself. AntennaPod still refreshed the feed and " + "attempted to repair it." + "\n\nOriginal episode:\n" + duplicateEpisodeDetails(oldItem) + "\n\nNow the feed contains:\n" + duplicateEpisodeDetails(item), false));
                    oldItem.setItemIdentifier(item.getItemIdentifier());
                    if (oldItem.isPlayed() && oldItem.getMedia() != null) {
                        EpisodeAction action = new EpisodeAction.Builder(oldItem, EpisodeAction.PLAY).currentTimestamp().started(oldItem.getMedia().getDuration() / 1000).position(oldItem.getMedia().getDuration() / 1000).total(oldItem.getMedia().getDuration() / 1000).build();
                        SynchronizationQueueSink.enqueueEpisodeActionIfSynchronizationIsActive(context, action);
                    }
                }
            }
            if (oldItem != null) {
                oldItem.updateFromOther(item);
            } else {
                // item is new
                item.setFeed(savedFeed);
                if (idx >= savedFeed.getItems().size()) {
                    savedFeed.getItems().add(item);
                } else {
                    savedFeed.getItems().add(idx, item);
                }
                // New items that do not have a pubDate set are always marked as new
                if (item.getPubDate() == null || priorMostRecentDate == null || priorMostRecentDate.before(item.getPubDate()) || priorMostRecentDate.equals(item.getPubDate())) {
                    Log.d(TAG, "Marking item published on " + item.getPubDate() + " new, prior most recent date = " + priorMostRecentDate);
                    item.setNew();
                }
            }
        }
        // identify items to be removed
        if (removeUnlistedItems) {
            Iterator<FeedItem> it = savedFeed.getItems().iterator();
            while (it.hasNext()) {
                FeedItem feedItem = it.next();
                if (searchFeedItemByIdentifyingValue(newFeed.getItems(), feedItem) == null) {
                    unlistedItems.add(feedItem);
                    it.remove();
                }
            }
        }
        // update attributes
        savedFeed.setLastUpdate(newFeed.getLastUpdate());
        savedFeed.setType(newFeed.getType());
        savedFeed.setLastUpdateFailed(false);
        resultFeed = savedFeed;
    }
    try {
        if (savedFeed == null) {
            DBWriter.addNewFeed(context, newFeed).get();
            // Update with default values that are set in database
            resultFeed = searchFeedByIdentifyingValueOrID(adapter, newFeed);
        } else {
            DBWriter.setCompleteFeed(savedFeed).get();
        }
        if (removeUnlistedItems) {
            DBWriter.deleteFeedItems(context, unlistedItems).get();
        }
    } catch (InterruptedException | ExecutionException e) {
        e.printStackTrace();
    }
    adapter.close();
    if (savedFeed != null) {
        EventBus.getDefault().post(new FeedListUpdateEvent(savedFeed));
    } else {
        EventBus.getDefault().post(new FeedListUpdateEvent(Collections.emptyList()));
    }
    return resultFeed;
}
Also used : ArrayList(java.util.ArrayList) Date(java.util.Date) EpisodeAction(de.danoeh.antennapod.net.sync.model.EpisodeAction) FeedItemPubdateComparator(de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator) FeedItem(de.danoeh.antennapod.model.feed.FeedItem) DownloadStatus(de.danoeh.antennapod.core.service.download.DownloadStatus) ExecutionException(java.util.concurrent.ExecutionException) FeedListUpdateEvent(de.danoeh.antennapod.event.FeedListUpdateEvent) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 2 with FeedListUpdateEvent

use of de.danoeh.antennapod.event.FeedListUpdateEvent in project AntennaPod by AntennaPod.

the class UITestUtils method addLocalFeedData.

/**
 * Adds feeds, images and episodes to the local database. This method will also call addHostedFeedData if it has not
 * been called yet.
 *
 * Adds one item of each feed to the queue and to the playback history.
 *
 * This method should NOT be called if the testing class wants to download the hosted feed data.
 *
 * @param downloadEpisodes true if episodes should also be marked as downloaded.
 */
public void addLocalFeedData(boolean downloadEpisodes) throws Exception {
    if (localFeedDataAdded) {
        Log.w(TAG, "addLocalFeedData was called twice on the same instance");
        // might be a flaky test, this is actually not that severe
        return;
    }
    if (!feedDataHosted) {
        addHostedFeedData();
    }
    List<FeedItem> queue = new ArrayList<>();
    for (Feed feed : hostedFeeds) {
        feed.setDownloaded(true);
        if (downloadEpisodes) {
            for (FeedItem item : feed.getItems()) {
                if (item.hasMedia()) {
                    FeedMedia media = item.getMedia();
                    int fileId = Integer.parseInt(StringUtils.substringAfter(media.getDownload_url(), "files/"));
                    media.setFile_url(server.accessFile(fileId).getAbsolutePath());
                    media.setDownloaded(true);
                }
            }
        }
        queue.add(feed.getItems().get(0));
        if (feed.getItems().get(1).hasMedia()) {
            feed.getItems().get(1).getMedia().setPlaybackCompletionDate(new Date());
        }
    }
    localFeedDataAdded = true;
    PodDBAdapter adapter = PodDBAdapter.getInstance();
    adapter.open();
    adapter.setCompleteFeed(hostedFeeds.toArray(new Feed[0]));
    adapter.setQueue(queue);
    adapter.close();
    EventBus.getDefault().post(new FeedListUpdateEvent(hostedFeeds));
    EventBus.getDefault().post(QueueEvent.setQueue(queue));
}
Also used : PodDBAdapter(de.danoeh.antennapod.core.storage.PodDBAdapter) FeedItem(de.danoeh.antennapod.model.feed.FeedItem) FeedMedia(de.danoeh.antennapod.model.feed.FeedMedia) ArrayList(java.util.ArrayList) FeedListUpdateEvent(de.danoeh.antennapod.event.FeedListUpdateEvent) Date(java.util.Date) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 3 with FeedListUpdateEvent

use of de.danoeh.antennapod.event.FeedListUpdateEvent in project AntennaPod by AntennaPod.

the class DBWriter method deleteFeed.

/**
 * Deletes a Feed and all downloaded files of its components like images and downloaded episodes.
 *
 * @param context A context that is used for opening a database connection.
 * @param feedId  ID of the Feed that should be deleted.
 */
public static Future<?> deleteFeed(final Context context, final long feedId) {
    return dbExec.submit(() -> {
        final Feed feed = DBReader.getFeed(feedId);
        if (feed == null) {
            return;
        }
        // delete stored media files and mark them as read
        if (feed.getItems() == null) {
            DBReader.getFeedItemList(feed);
        }
        deleteFeedItemsSynchronous(context, feed.getItems());
        // delete feed
        PodDBAdapter adapter = PodDBAdapter.getInstance();
        adapter.open();
        adapter.removeFeed(feed);
        adapter.close();
        if (!feed.isLocalFeed()) {
            SynchronizationQueueSink.enqueueFeedRemovedIfSynchronizationIsActive(context, feed.getDownload_url());
        }
        EventBus.getDefault().post(new FeedListUpdateEvent(feed));
    });
}
Also used : FeedListUpdateEvent(de.danoeh.antennapod.event.FeedListUpdateEvent) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 4 with FeedListUpdateEvent

use of de.danoeh.antennapod.event.FeedListUpdateEvent in project AntennaPod by AntennaPod.

the class DBWriter method setFeedCustomTitle.

public static Future<?> setFeedCustomTitle(Feed feed) {
    return dbExec.submit(() -> {
        PodDBAdapter adapter = PodDBAdapter.getInstance();
        adapter.open();
        adapter.setFeedCustomTitle(feed.getId(), feed.getCustomTitle());
        adapter.close();
        EventBus.getDefault().post(new FeedListUpdateEvent(feed));
    });
}
Also used : FeedListUpdateEvent(de.danoeh.antennapod.event.FeedListUpdateEvent)

Example 5 with FeedListUpdateEvent

use of de.danoeh.antennapod.event.FeedListUpdateEvent in project AntennaPod by AntennaPod.

the class DBWriter method setFeedPreferences.

/**
 * Saves a FeedPreferences object in the database. The Feed ID of the FeedPreferences-object MUST NOT be 0.
 *
 * @param preferences The FeedPreferences object.
 */
public static Future<?> setFeedPreferences(final FeedPreferences preferences) {
    return dbExec.submit(() -> {
        PodDBAdapter adapter = PodDBAdapter.getInstance();
        adapter.open();
        adapter.setFeedPreferences(preferences);
        adapter.close();
        EventBus.getDefault().post(new FeedListUpdateEvent(preferences.getFeedID()));
    });
}
Also used : FeedListUpdateEvent(de.danoeh.antennapod.event.FeedListUpdateEvent)

Aggregations

FeedListUpdateEvent (de.danoeh.antennapod.event.FeedListUpdateEvent)6 Feed (de.danoeh.antennapod.model.feed.Feed)3 FeedItem (de.danoeh.antennapod.model.feed.FeedItem)2 ArrayList (java.util.ArrayList)2 Date (java.util.Date)2 DownloadStatus (de.danoeh.antennapod.core.service.download.DownloadStatus)1 PodDBAdapter (de.danoeh.antennapod.core.storage.PodDBAdapter)1 FeedItemPubdateComparator (de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator)1 FeedMedia (de.danoeh.antennapod.model.feed.FeedMedia)1 EpisodeAction (de.danoeh.antennapod.net.sync.model.EpisodeAction)1 ExecutionException (java.util.concurrent.ExecutionException)1