public async Task AddFeedAsync(string feed_url) { var found_feed_urls = from url in await FeedReader.GetFeedUrlsFromUrlAsync(feed_url) select url.Url; if (found_feed_urls.Count() > 0) { var blog_url = found_feed_urls.First(); feed_url = blog_url.StartsWith('/') ? $"{feed_url.TrimEnd('/')}{blog_url}" : blog_url; } if (Feeds.Any(f => f.FeedLink == feed_url)) { throw new Exception("There's already a feed with that url."); } else { var parsed_feed = await FeedReader.ReadAsync(feed_url); var feed_uri = new Uri(parsed_feed.Link); var feed_title = string.IsNullOrWhiteSpace(parsed_feed.Title) ? feed_uri.Host : parsed_feed.Title; var feed_id = AvoidFeedIdCollision(MakeSafeId(feed_title)); string feed_image_path = await DownloadFeedImageAsync(feed_id, parsed_feed.ImageUrl, feed_uri.Host); var feed = new Feed(feed_id, feed_url) { Title = feed_title, Link = $"{feed_uri.Scheme}://{feed_uri.Host}", ImagePath = feed_image_path, DateLastUpdated = parsed_feed.LastUpdatedDate is null ? DateTime.Now : (DateTime)parsed_feed.LastUpdatedDate, Description = ExtractTextFromHtml(parsed_feed.Description) }; await WriteToFileAsync(Path.Combine(FeedDirectory, $"{feed_id}.feed"), feed.Serialize()); Directory.CreateDirectory(Path.Combine(FeedDirectory, feed_id)); await AddPostsToFeedAsync(feed, parsed_feed.Items); Feeds.Add(feed); } string AvoidFeedIdCollision(string id) { var pre_path = Path.Combine(FeedDirectory, id); if (Directory.Exists($"{pre_path}.feed")) { int suffix = 2; while (Directory.Exists($"{pre_path}_{suffix}.feed")) { suffix++; } id = $"{id}_{suffix}"; } return(id); } async Task <string> DownloadFeedImageAsync(string feed_id, string feed_image_url, string feed_host) { string feed_image_path = null; if (string.IsNullOrEmpty(feed_image_url)) { try { var web_client = new WebClient(); web_client.Headers.Add(HttpRequestHeader.UserAgent, "Fidd RSS Reader v1.0"); var favicon_api_response = await web_client.DownloadStringTaskAsync($"http://favicongrabber.com/api/grab/{feed_host}"); var deserialized_response = JsonConvert.DeserializeObject <FaviconGrabberResponse>(favicon_api_response); if (deserialized_response.Icons.Count > 0) { feed_image_url = deserialized_response.Icons.First().Source; } } catch (Exception e) {; } } if (!string.IsNullOrEmpty(feed_image_url)) { if (feed_image_url.StartsWith("data:image/")) { feed_image_url = feed_image_url.Substring(11); var image_extension = feed_image_url.Substring(0, feed_image_url.IndexOf(';')); feed_image_path = $"{feed_id}.{image_extension}"; var image_data_base64 = feed_image_url.Substring(feed_image_url.IndexOf(',') + 1); await File.WriteAllBytesAsync(Path.Combine(FeedDirectory, feed_image_path), Convert.FromBase64String(image_data_base64)); } else { var downloader = new WebClient(); string image_extension = ExtractExtensionFromUrl(feed_image_url); feed_image_path = $"{feed_id}{image_extension}"; await downloader.DownloadFileTaskAsync(feed_image_url, Path.Combine(FeedDirectory, feed_image_path)); } } return(feed_image_path); } }