public static async Task<IList<Item>> UpdateFeedAsync(Feed feed, TimeSpan timeout) {
            using (var downloader = new DownloadHelper(timeout))
            using (var reader = await downloader.DownloadXmlAsync(feed.Url)) {
                var factory = GetFeedFactory(reader);

                if (factory != null) {
                    return factory.UpdateFeed(feed, reader);
                }

                return new Item[0];
            }
        }
        protected override Feed CreateFeed(XmlReader reader, string url) {
            var rssFeed = new RssFeed();
            rssFeed.Load(reader);

            var items = rssFeed.Channel.Items.OrderBy(i => GetPublishedDate(i)).Select(CreateFeedItem);

            var feed = new Feed {
                Title = rssFeed.Channel.Title,
                Url = url,
                SiteUrl = rssFeed.Channel.Link.ToString(),
                Description = rssFeed.Channel.Description,
                Items = new List<Item>(items)
            };

            var latest = items.LastOrDefault();
            if (latest != null) {
                feed.Updated = latest.Published;
            }

            return feed;
        }
        protected override Feed CreateFeed(XmlReader reader, string url) {
            var atomFeed = new AtomFeed();
            atomFeed.Load(reader);

            var items = atomFeed.Entries.OrderBy(e => GetPublishedDate(e)).Select(CreateFeedItem);

            var feed = new Feed {
                Title = atomFeed.Title.Content,
                Url = url,
                SiteUrl = atomFeed.Links.Any() ? atomFeed.Links[0].ToString() : String.Empty,
                Description = atomFeed.Subtitle == null ? String.Empty : atomFeed.Subtitle.Content,
                Items = new List<Item>(items)
            };

            var latest = items.LastOrDefault();
            if (latest != null) {
                feed.Updated = latest.Published;
            }

            return feed;
        }
        protected override IList<Item> UpdateFeed(Feed feed, XmlReader reader) {
            var rssFeed = new RssFeed();
            rssFeed.Load(reader);

            var items = (from i in rssFeed.Channel.Items
                         let date = GetPublishedDate(i)
                         orderby date
                         where date > feed.Updated
                         select CreateFeedItem(i)).ToList();

            feed.Items.AddRange(items);

            var latest = items.LastOrDefault();
            if (latest != null) {
                feed.Updated = latest.Published;
            }

            // OPML does not set full description so check for one when updating.
            if (String.IsNullOrEmpty(feed.Description)) {
                feed.Description = rssFeed.Channel.Description;
            }

            return items;
        }
        protected override IList<Item> UpdateFeed(Feed feed, XmlReader reader) {
            var atomFeed = new AtomFeed();
            atomFeed.Load(reader);

            var items = (from e in atomFeed.Entries
                         let date = GetPublishedDate(e)
                         orderby date
                         where date > feed.Updated
                         select CreateFeedItem(e)).ToList();

            feed.Items.AddRange(items);

            var latest = items.LastOrDefault();
            if (latest != null) {
                feed.Updated = latest.Published;
            }

            // OPML does not set full description so check for one when updating.
            if (String.IsNullOrEmpty(feed.Description) && atomFeed.Subtitle != null) {
                feed.Description = atomFeed.Subtitle.Content;
            }

            return items;
        }
 protected abstract IList<Item> UpdateFeed(Feed feed, XmlReader reader);
        public void LoadFeed() {
#if !DEBUG
            try {
#endif
                _feed = FeedFactory.DownloadFeed(Url, Settings.Default.DownloadTimeout);

                Title = _feed.Title;
#if !DEBUG
            }
            catch (Exception ex) {
                DialogHelper.ShowError("Load Feed Error", ex.Message);
            }
#endif
        }
        public void Add() {
            try {
                if (_feed == null) {
                    _feed = FeedFactory.DownloadFeed(Url, Settings.Default.DownloadTimeout);
                }

                _feed.Title = Title;
                _feed.Category = Category.Trim();

                Action(_feed);

                TryClose(true);
            }
            catch (Exception ex) {
                DialogHelper.ShowError("Load Feed Error", ex.Message);
            }
        }
        public static IEnumerable<Feed> LoadFeeds() {
            var filename = GetFeedsPath();

            if (!File.Exists(filename)) {
                yield break;
            }

            using (var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
            using (var reader = new BinaryReader(stream)) {
                if (reader.ReadString() != SaveHeader) {
                    throw new InvalidOperationException("header");
                }

                if (reader.ReadInt32() != SaveVersion) {
                    throw new InvalidOperationException("version");
                }

                int feedCount = reader.ReadInt32();
                for (int i = 0; i < feedCount; i++) {
                    var feed = new Feed {
                        Title = reader.ReadString(),
                        Url = reader.ReadString(),
                        SiteUrl = reader.ReadString(),
                        Description = reader.ReadString(),
                        Updated = DateTime.FromBinary(reader.ReadInt64()),
                        IsPreserved = reader.ReadBoolean(),
                        Category = reader.ReadString()
                    };

                    int itemCount = reader.ReadInt32();
                    feed.Items = new List<Item>(itemCount);
                    for (int j = 0; j < itemCount; j++) {
                        feed.Items.Add(new Item {
                            Title = reader.ReadString(),
                            Url = reader.ReadString(),
                            PodcastUrl = reader.ReadString(),
                            Published = DateTime.FromBinary(reader.ReadInt64()),
                            Summary = reader.ReadString(),
                            IsRead = reader.ReadBoolean()
                        });
                    }

                    yield return feed;
                }
            }
        }