From e2434e620c2af3f95ed6613018a424bad3e3f2fd Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 7 Nov 2019 19:07:10 -0600 Subject: [PATCH] Get extended subscription information from Feedbin. Issue #917 --- .../Account/Account.xcodeproj/project.pbxproj | 4 -- .../Account/Feedbin/FeedbinAPICaller.swift | 33 +++--------- .../Feedbin/FeedbinAccountDelegate.swift | 52 +++++-------------- Frameworks/Account/Feedbin/FeedbinIcon.swift | 21 -------- .../Account/Feedbin/FeedbinSubscription.swift | 16 ++++++ 5 files changed, 36 insertions(+), 90 deletions(-) delete mode 100644 Frameworks/Account/Feedbin/FeedbinIcon.swift diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index 040702ebc..e9264a54c 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 5133230A2281082F00C30F19 /* subscriptions_initial.json in Resources */ = {isa = PBXBuildFile; fileRef = 513323092281082F00C30F19 /* subscriptions_initial.json */; }; 5133230C2281088A00C30F19 /* subscriptions_add.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230B2281088A00C30F19 /* subscriptions_add.json */; }; 5133230E2281089500C30F19 /* icons.json in Resources */ = {isa = PBXBuildFile; fileRef = 5133230D2281089500C30F19 /* icons.json */; }; - 5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133230F22810E5700C30F19 /* FeedbinIcon.swift */; }; 5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; }; 5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; }; 5154367B228EEB28005E1CDF /* FeedbinImportResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */; }; @@ -118,7 +117,6 @@ 513323092281082F00C30F19 /* subscriptions_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_initial.json; sourceTree = ""; }; 5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = ""; }; 5133230D2281089500C30F19 /* icons.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = icons.json; sourceTree = ""; }; - 5133230F22810E5700C30F19 /* FeedbinIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinIcon.swift; sourceTree = ""; }; 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = ""; }; 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = ""; }; 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinImportResult.swift; sourceTree = ""; }; @@ -274,7 +272,6 @@ 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */, 51E490352288C37100C791F0 /* FeedbinDate.swift */, 84CAD7151FDF2E22000F0755 /* FeedbinEntry.swift */, - 5133230F22810E5700C30F19 /* FeedbinIcon.swift */, 5154367A228EEB28005E1CDF /* FeedbinImportResult.swift */, 51E5959A228C781500FCC42B /* FeedbinStarredEntry.swift */, 84245C841FDDD8CB0074AFBB /* FeedbinSubscription.swift */, @@ -550,7 +547,6 @@ 84B2D4D02238CD8A00498ADA /* FeedMetadata.swift in Sources */, 5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */, 84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */, - 5133231122810EB200C30F19 /* FeedbinIcon.swift in Sources */, 846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */, 51E3EB41229AF61B00645299 /* AccountError.swift in Sources */, 51E59599228C77BC00FCC42B /* FeedbinUnreadEntry.swift in Sources */, diff --git a/Frameworks/Account/Feedbin/FeedbinAPICaller.swift b/Frameworks/Account/Feedbin/FeedbinAPICaller.swift index 27282de5b..5d3c8c6fd 100644 --- a/Frameworks/Account/Feedbin/FeedbinAPICaller.swift +++ b/Frameworks/Account/Feedbin/FeedbinAPICaller.swift @@ -26,7 +26,6 @@ final class FeedbinAPICaller: NSObject { static let subscriptions = "subscriptions" static let tags = "tags" static let taggings = "taggings" - static let icons = "icons" static let unreadEntries = "unreadEntries" static let starredEntries = "starredEntries" } @@ -145,9 +144,11 @@ final class FeedbinAPICaller: NSObject { func retrieveSubscriptions(completion: @escaping (Result<[FeedbinSubscription]?, Error>) -> Void) { - let callURL = feedbinBaseURL.appendingPathComponent("subscriptions.json") + var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("subscriptions.json"), resolvingAgainstBaseURL: false)! + callComponents.queryItems = [URLQueryItem(name: "mode", value: "extended")] + let conditionalGet = accountMetadata?.conditionalGetInfo[ConditionalGetKeys.subscriptions] - let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet) + let request = URLRequest(url: callComponents.url!, credentials: credentials, conditionalGet: conditionalGet) transport.send(request: request, resultType: [FeedbinSubscription].self) { result in @@ -165,8 +166,10 @@ final class FeedbinAPICaller: NSObject { func createSubscription(url: String, completion: @escaping (Result) -> Void) { - let callURL = feedbinBaseURL.appendingPathComponent("subscriptions.json") - var request = URLRequest(url: callURL, credentials: credentials) + var callComponents = URLComponents(url: feedbinBaseURL.appendingPathComponent("subscriptions.json"), resolvingAgainstBaseURL: false)! + callComponents.queryItems = [URLQueryItem(name: "mode", value: "extended")] + + var request = URLRequest(url: callComponents.url!, credentials: credentials) request.addValue("application/json; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType) let payload: Data @@ -309,26 +312,6 @@ final class FeedbinAPICaller: NSObject { transport.send(request: request, method: HTTPMethod.delete, completion: completion) } - func retrieveIcons(completion: @escaping (Result<[FeedbinIcon]?, Error>) -> Void) { - - let callURL = feedbinBaseURL.appendingPathComponent("icons.json") - let conditionalGet = accountMetadata?.conditionalGetInfo[ConditionalGetKeys.icons] - let request = URLRequest(url: callURL, credentials: credentials, conditionalGet: conditionalGet) - - transport.send(request: request, resultType: [FeedbinIcon].self) { result in - - switch result { - case .success(let (response, icons)): - self.storeConditionalGet(key: ConditionalGetKeys.icons, headers: response.allHeaderFields) - completion(.success(icons)) - case .failure(let error): - completion(.failure(error)) - } - - } - - } - func retrieveEntries(articleIDs: [String], completion: @escaping (Result<([FeedbinEntry]?), Error>) -> Void) { guard !articleIDs.isEmpty else { diff --git a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift index 8a1f60535..5bd1b5c76 100644 --- a/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift +++ b/Frameworks/Account/Feedbin/FeedbinAccountDelegate.swift @@ -81,7 +81,7 @@ final class FeedbinAccountDelegate: AccountDelegate { func refreshAll(for account: Account, completion: @escaping (Result) -> Void) { - refreshProgress.addToNumberOfTasksAndRemaining(6) + refreshProgress.addToNumberOfTasksAndRemaining(5) refreshAccount(account) { result in switch result { @@ -592,26 +592,14 @@ private extension FeedbinAccountDelegate { switch result { case .success(let taggings): - self.refreshProgress.completeTask() - self.caller.retrieveIcons { result in - switch result { - case .success(let icons): - - BatchUpdate.shared.perform { - self.syncFolders(account, tags) - self.syncFeeds(account, subscriptions) - self.syncFeedFolderRelationship(account, taggings) - self.syncFavicons(account, icons) - } - - self.refreshProgress.completeTask() - completion(.success(())) - - case .failure(let error): - completion(.failure(error)) - } - + BatchUpdate.shared.perform { + self.syncFolders(account, tags) + self.syncFeeds(account, subscriptions) + self.syncFeedFolderRelationship(account, taggings) } + + self.refreshProgress.completeTask() + completion(.success(())) case .failure(let error): completion(.failure(error)) @@ -733,6 +721,8 @@ private extension FeedbinAccountDelegate { feed.editedName = nil feed.homePageURL = subscription.homePageURL feed.subscriptionID = String(subscription.subscriptionID) + feed.faviconURL = subscription.jsonFeed?.favicon + feed.iconURL = subscription.jsonFeed?.icon } else { subscriptionsToAdd.insert(subscription) @@ -816,25 +806,6 @@ private extension FeedbinAccountDelegate { } } - func syncFavicons(_ account: Account, _ icons: [FeedbinIcon]?) { - - guard let icons = icons else { return } - - os_log(.debug, log: log, "Syncing favicons with %ld icons.", icons.count) - - let iconDict = Dictionary(uniqueKeysWithValues: icons.map { ($0.host, $0.url) } ) - - for feed in account.flattenedFeeds() { - for (key, value) in iconDict { - if feed.homePageURL?.contains(key) ?? false { - feed.faviconURL = value - break - } - } - } - } - - func sendArticleStatuses(_ statuses: [SyncStatus], apiCall: ([Int], @escaping (Result) -> Void) -> Void, completion: @escaping (() -> Void)) { @@ -924,11 +895,12 @@ private extension FeedbinAccountDelegate { func createFeed( account: Account, subscription sub: FeedbinSubscription, name: String?, container: Container, completion: @escaping (Result) -> Void) { - DispatchQueue.main.async { let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL) feed.subscriptionID = String(sub.subscriptionID) + feed.iconURL = sub.jsonFeed?.icon + feed.faviconURL = sub.jsonFeed?.favicon account.addFeed(feed, to: container) { result in switch result { diff --git a/Frameworks/Account/Feedbin/FeedbinIcon.swift b/Frameworks/Account/Feedbin/FeedbinIcon.swift deleted file mode 100644 index cfb972641..000000000 --- a/Frameworks/Account/Feedbin/FeedbinIcon.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// FeedbinIcon.swift -// Account -// -// Created by Maurice Parker on 5/6/19. -// Copyright © 2019 Ranchero Software, LLC. All rights reserved. -// - -import Foundation - -struct FeedbinIcon: Codable { - - let host: String - let url: String - - enum CodingKeys: String, CodingKey { - case host - case url - } - -} diff --git a/Frameworks/Account/Feedbin/FeedbinSubscription.swift b/Frameworks/Account/Feedbin/FeedbinSubscription.swift index feac0e7dd..d789d1deb 100644 --- a/Frameworks/Account/Feedbin/FeedbinSubscription.swift +++ b/Frameworks/Account/Feedbin/FeedbinSubscription.swift @@ -17,6 +17,7 @@ struct FeedbinSubscription: Hashable, Codable { let name: String? let url: String let homePageURL: String? + let jsonFeed: FeedbinSubscriptionJSONFeed? enum CodingKeys: String, CodingKey { case subscriptionID = "id" @@ -24,11 +25,26 @@ struct FeedbinSubscription: Hashable, Codable { case name = "title" case url = "feed_url" case homePageURL = "site_url" + case jsonFeed = "json_feed" } public func hash(into hasher: inout Hasher) { hasher.combine(subscriptionID) } + + static func == (lhs: FeedbinSubscription, rhs: FeedbinSubscription) -> Bool { + return lhs.subscriptionID == rhs.subscriptionID + } + +} + +struct FeedbinSubscriptionJSONFeed: Codable { + let favicon: String? + let icon: String? + enum CodingKeys: String, CodingKey { + case favicon = "favicon" + case icon = "icon" + } } struct FeedbinCreateSubscription: Codable {