Search in sources :

Example 11 with Feed

use of de.danoeh.antennapod.model.feed.Feed in project AntennaPod by AntennaPod.

the class FeedParserTask method call.

@Override
public FeedHandlerResult call() {
    Feed feed = new Feed(request.getSource(), request.getLastModified());
    feed.setFile_url(request.getDestination());
    feed.setId(request.getFeedfileId());
    feed.setDownloaded(true);
    feed.setPreferences(new FeedPreferences(0, true, FeedPreferences.AutoDeleteAction.GLOBAL, VolumeAdaptionSetting.OFF, request.getUsername(), request.getPassword()));
    feed.setPageNr(request.getArguments().getInt(DownloadRequest.REQUEST_ARG_PAGE_NR, 0));
    DownloadError reason = null;
    String reasonDetailed = null;
    FeedHandler feedHandler = new FeedHandler();
    FeedHandlerResult result = null;
    try {
        result = feedHandler.parseFeed(feed);
        Log.d(TAG, feed.getTitle() + " parsed");
        checkFeedData(feed);
    } catch (SAXException | IOException | ParserConfigurationException e) {
        successful = false;
        e.printStackTrace();
        reason = DownloadError.ERROR_PARSER_EXCEPTION;
        reasonDetailed = e.getMessage();
    } catch (UnsupportedFeedtypeException e) {
        e.printStackTrace();
        successful = false;
        reason = DownloadError.ERROR_UNSUPPORTED_TYPE;
        if ("html".equalsIgnoreCase(e.getRootElement())) {
            reason = DownloadError.ERROR_UNSUPPORTED_TYPE_HTML;
        }
        reasonDetailed = e.getMessage();
    } catch (InvalidFeedException e) {
        e.printStackTrace();
        successful = false;
        reason = DownloadError.ERROR_PARSER_EXCEPTION;
        reasonDetailed = e.getMessage();
    } finally {
        File feedFile = new File(request.getDestination());
        if (feedFile.exists()) {
            boolean deleted = feedFile.delete();
            Log.d(TAG, "Deletion of file '" + feedFile.getAbsolutePath() + "' " + (deleted ? "successful" : "FAILED"));
        }
    }
    if (successful) {
        downloadStatus = new DownloadStatus(feed, feed.getHumanReadableIdentifier(), DownloadError.SUCCESS, successful, reasonDetailed, request.isInitiatedByUser());
        return result;
    } else {
        downloadStatus = new DownloadStatus(feed, feed.getTitle(), reason, successful, reasonDetailed, request.isInitiatedByUser());
        return null;
    }
}
Also used : FeedPreferences(de.danoeh.antennapod.model.feed.FeedPreferences) InvalidFeedException(de.danoeh.antennapod.core.util.InvalidFeedException) UnsupportedFeedtypeException(de.danoeh.antennapod.parser.feed.UnsupportedFeedtypeException) FeedHandlerResult(de.danoeh.antennapod.parser.feed.FeedHandlerResult) IOException(java.io.IOException) SAXException(org.xml.sax.SAXException) DownloadError(de.danoeh.antennapod.core.util.DownloadError) FeedHandler(de.danoeh.antennapod.parser.feed.FeedHandler) DownloadStatus(de.danoeh.antennapod.core.service.download.DownloadStatus) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException) File(java.io.File) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 12 with Feed

use of de.danoeh.antennapod.model.feed.Feed in project AntennaPod by AntennaPod.

the class PlaybackService method loadChildrenSynchronous.

private List<MediaBrowserCompat.MediaItem> loadChildrenSynchronous(@NonNull String parentId) throws InterruptedException {
    List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
    if (parentId.equals(getResources().getString(R.string.app_name))) {
        mediaItems.add(createBrowsableMediaItem(R.string.queue_label, R.drawable.ic_playlist_black, DBReader.getQueue().size()));
        mediaItems.add(createBrowsableMediaItem(R.string.downloads_label, R.drawable.ic_download_black, DBReader.getDownloadedItems().size()));
        List<Feed> feeds = DBReader.getFeedList();
        for (Feed feed : feeds) {
            mediaItems.add(createBrowsableMediaItemForFeed(feed));
        }
        return mediaItems;
    }
    List<FeedItem> feedItems;
    if (parentId.equals(getResources().getString(R.string.queue_label))) {
        feedItems = DBReader.getQueue();
    } else if (parentId.equals(getResources().getString(R.string.downloads_label))) {
        feedItems = DBReader.getDownloadedItems();
    } else if (parentId.startsWith("FeedId:")) {
        long feedId = Long.parseLong(parentId.split(":")[1]);
        feedItems = DBReader.getFeedItemList(DBReader.getFeed(feedId));
    } else {
        Log.e(TAG, "Parent ID not found: " + parentId);
        return null;
    }
    int count = 0;
    for (FeedItem feedItem : feedItems) {
        if (feedItem.getMedia() != null && feedItem.getMedia().getMediaItem() != null) {
            mediaItems.add(feedItem.getMedia().getMediaItem());
            if (++count >= MAX_ANDROID_AUTO_EPISODES_PER_FEED) {
                break;
            }
        }
    }
    return mediaItems;
}
Also used : FeedItem(de.danoeh.antennapod.model.feed.FeedItem) ArrayList(java.util.ArrayList) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 13 with Feed

use of de.danoeh.antennapod.model.feed.Feed in project AntennaPod by AntennaPod.

the class DBReader method getNavDrawerData.

/**
 * Returns data necessary for displaying the navigation drawer. This includes
 * the list of subscriptions, the number of items in the queue and the number of unread
 * items.
 */
@NonNull
public static NavDrawerData getNavDrawerData() {
    Log.d(TAG, "getNavDrawerData() called with: " + "");
    PodDBAdapter adapter = PodDBAdapter.getInstance();
    adapter.open();
    final LongIntMap feedCounters = adapter.getFeedCounters();
    SubscriptionsFilter subscriptionsFilter = UserPreferences.getSubscriptionsFilter();
    List<Feed> feeds = subscriptionsFilter.filter(getFeedList(adapter), feedCounters);
    Comparator<Feed> comparator;
    int feedOrder = UserPreferences.getFeedOrder();
    if (feedOrder == UserPreferences.FEED_ORDER_COUNTER) {
        comparator = (lhs, rhs) -> {
            long counterLhs = feedCounters.get(lhs.getId());
            long counterRhs = feedCounters.get(rhs.getId());
            if (counterLhs > counterRhs) {
                // reverse natural order: podcast with most unplayed episodes first
                return -1;
            } else if (counterLhs == counterRhs) {
                return lhs.getTitle().compareToIgnoreCase(rhs.getTitle());
            } else {
                return 1;
            }
        };
    } else if (feedOrder == UserPreferences.FEED_ORDER_ALPHABETICAL) {
        comparator = (lhs, rhs) -> {
            String t1 = lhs.getTitle();
            String t2 = rhs.getTitle();
            if (t1 == null) {
                return 1;
            } else if (t2 == null) {
                return -1;
            } else {
                return t1.compareToIgnoreCase(t2);
            }
        };
    } else if (feedOrder == UserPreferences.FEED_ORDER_MOST_PLAYED) {
        final LongIntMap playedCounters = adapter.getPlayedEpisodesCounters();
        comparator = (lhs, rhs) -> {
            long counterLhs = playedCounters.get(lhs.getId());
            long counterRhs = playedCounters.get(rhs.getId());
            if (counterLhs > counterRhs) {
                // podcast with most played episodes first
                return -1;
            } else if (counterLhs == counterRhs) {
                return lhs.getTitle().compareToIgnoreCase(rhs.getTitle());
            } else {
                return 1;
            }
        };
    } else {
        final Map<Long, Long> recentPubDates = adapter.getMostRecentItemDates();
        comparator = (lhs, rhs) -> {
            long dateLhs = recentPubDates.containsKey(lhs.getId()) ? recentPubDates.get(lhs.getId()) : 0;
            long dateRhs = recentPubDates.containsKey(rhs.getId()) ? recentPubDates.get(rhs.getId()) : 0;
            return Long.compare(dateRhs, dateLhs);
        };
    }
    Collections.sort(feeds, comparator);
    int queueSize = adapter.getQueueSize();
    int numNewItems = adapter.getNumberOfNewItems();
    int numDownloadedItems = adapter.getNumberOfDownloadedEpisodes();
    List<NavDrawerData.DrawerItem> items = new ArrayList<>();
    Map<String, NavDrawerData.TagDrawerItem> folders = new HashMap<>();
    for (Feed feed : feeds) {
        for (String tag : feed.getPreferences().getTags()) {
            NavDrawerData.FeedDrawerItem drawerItem = new NavDrawerData.FeedDrawerItem(feed, feed.getId(), feedCounters.get(feed.getId()));
            if (FeedPreferences.TAG_ROOT.equals(tag)) {
                items.add(drawerItem);
                continue;
            }
            NavDrawerData.TagDrawerItem folder;
            if (folders.containsKey(tag)) {
                folder = folders.get(tag);
            } else {
                folder = new NavDrawerData.TagDrawerItem(tag);
                folders.put(tag, folder);
            }
            drawerItem.id |= folder.id;
            folder.children.add(drawerItem);
        }
    }
    List<NavDrawerData.TagDrawerItem> foldersSorted = new ArrayList<>(folders.values());
    Collections.sort(foldersSorted, (o1, o2) -> o1.getTitle().compareToIgnoreCase(o2.getTitle()));
    items.addAll(foldersSorted);
    NavDrawerData result = new NavDrawerData(items, queueSize, numNewItems, numDownloadedItems, feedCounters, UserPreferences.getEpisodeCleanupAlgorithm().getReclaimableItems());
    adapter.close();
    return result;
}
Also used : FeedItemPubdateComparator(de.danoeh.antennapod.core.util.comparator.FeedItemPubdateComparator) NonNull(androidx.annotation.NonNull) DownloadStatusComparator(de.danoeh.antennapod.core.util.comparator.DownloadStatusComparator) HashMap(java.util.HashMap) LongList(de.danoeh.antennapod.core.util.LongList) FeedPreferencesCursorMapper(de.danoeh.antennapod.core.storage.mapper.FeedPreferencesCursorMapper) ArrayList(java.util.ArrayList) UserPreferences(de.danoeh.antennapod.core.preferences.UserPreferences) FeedItemCursorMapper(de.danoeh.antennapod.core.storage.mapper.FeedItemCursorMapper) FeedPreferences(de.danoeh.antennapod.model.feed.FeedPreferences) FeedItemFilter(de.danoeh.antennapod.model.feed.FeedItemFilter) Map(java.util.Map) Chapter(de.danoeh.antennapod.model.feed.Chapter) DownloadStatus(de.danoeh.antennapod.core.service.download.DownloadStatus) Log(android.util.Log) Feed(de.danoeh.antennapod.model.feed.Feed) PlaybackCompletionDateComparator(de.danoeh.antennapod.core.util.comparator.PlaybackCompletionDateComparator) Cursor(android.database.Cursor) ArrayMap(androidx.collection.ArrayMap) FeedMediaCursorMapper(de.danoeh.antennapod.core.storage.mapper.FeedMediaCursorMapper) LongIntMap(de.danoeh.antennapod.core.util.LongIntMap) FeedMedia(de.danoeh.antennapod.model.feed.FeedMedia) FeedItem(de.danoeh.antennapod.model.feed.FeedItem) TextUtils(android.text.TextUtils) File(java.io.File) SubscriptionsFilter(de.danoeh.antennapod.core.feed.SubscriptionsFilter) List(java.util.List) Nullable(androidx.annotation.Nullable) ChapterCursorMapper(de.danoeh.antennapod.core.storage.mapper.ChapterCursorMapper) FeedCursorMapper(de.danoeh.antennapod.core.storage.mapper.FeedCursorMapper) Comparator(java.util.Comparator) Collections(java.util.Collections) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) LongIntMap(de.danoeh.antennapod.core.util.LongIntMap) SubscriptionsFilter(de.danoeh.antennapod.core.feed.SubscriptionsFilter) Feed(de.danoeh.antennapod.model.feed.Feed) NonNull(androidx.annotation.NonNull)

Example 14 with Feed

use of de.danoeh.antennapod.model.feed.Feed in project AntennaPod by AntennaPod.

the class DBTasks method loadNextPageOfFeed.

/**
 * Queues the next page of this Feed for download. The given Feed has to be a paged
 * Feed (isPaged()=true) and must contain a nextPageLink.
 *
 * @param context      Used for requesting the download.
 * @param feed         The feed whose next page should be loaded.
 * @param loadAllPages True if any subsequent pages should also be loaded, false otherwise.
 */
public static void loadNextPageOfFeed(final Context context, Feed feed, boolean loadAllPages) {
    if (feed.isPaged() && feed.getNextPageLink() != null) {
        int pageNr = feed.getPageNr() + 1;
        Feed nextFeed = new Feed(feed.getNextPageLink(), null, feed.getTitle() + "(" + pageNr + ")");
        nextFeed.setPageNr(pageNr);
        nextFeed.setPaged(true);
        nextFeed.setId(feed.getId());
        DownloadRequest.Builder builder = DownloadRequestCreator.create(nextFeed);
        builder.loadAllPages(loadAllPages);
        DownloadService.download(context, false, builder.build());
    } else {
        Log.e(TAG, "loadNextPageOfFeed: Feed was either not paged or contained no nextPageLink");
    }
}
Also used : DownloadRequest(de.danoeh.antennapod.core.service.download.DownloadRequest) Feed(de.danoeh.antennapod.model.feed.Feed)

Example 15 with Feed

use of de.danoeh.antennapod.model.feed.Feed 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)

Aggregations

Feed (de.danoeh.antennapod.model.feed.Feed)125 FeedItem (de.danoeh.antennapod.model.feed.FeedItem)75 Test (org.junit.Test)61 ArrayList (java.util.ArrayList)43 Date (java.util.Date)37 File (java.io.File)31 FeedMedia (de.danoeh.antennapod.model.feed.FeedMedia)27 Cursor (android.database.Cursor)15 FeedPreferences (de.danoeh.antennapod.model.feed.FeedPreferences)12 NonNull (androidx.annotation.NonNull)10 Nullable (androidx.annotation.Nullable)8 View (android.view.View)7 DownloadStatus (de.danoeh.antennapod.core.service.download.DownloadStatus)7 Log (android.util.Log)6 R (de.danoeh.antennapod.R)6 DownloadRequest (de.danoeh.antennapod.core.service.download.DownloadRequest)6 List (java.util.List)6 ViewGroup (android.view.ViewGroup)5 AlertDialog (androidx.appcompat.app.AlertDialog)5 RequestOptions (com.bumptech.glide.request.RequestOptions)5