Add support for Reddit feed icons

This commit is contained in:
Maurice Parker 2020-05-04 18:13:15 -05:00
parent 78cefecaad
commit 143c102454
4 changed files with 66 additions and 15 deletions

View File

@ -47,6 +47,7 @@
5133BB47245FD8140001E3D0 /* RedditLinkListing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133BB46245FD8140001E3D0 /* RedditLinkListing.swift */; };
5133BB49246078910001E3D0 /* RedditLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133BB48246078910001E3D0 /* RedditLink.swift */; };
5133BB4B2460BDF30001E3D0 /* RedditSubreddit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133BB4A2460BDF30001E3D0 /* RedditSubreddit.swift */; };
5133BB4D2460CA0B0001E3D0 /* RedditMe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5133BB4C2460CA0B0001E3D0 /* RedditMe.swift */; };
5139A6382459822D004D960C /* CloudKitArticleStatusUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5139A6372459822D004D960C /* CloudKitArticleStatusUpdate.swift */; };
5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA48227B497600D19003 /* FeedbinAPICaller.swift */; };
5144EA4E227B829A00D19003 /* FeedbinAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */; };
@ -65,7 +66,6 @@
516896352448EBEA00185AC5 /* FeedProviderManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516896342448EBEA00185AC5 /* FeedProviderManager.swift */; };
5170743C232AEDB500A461A3 /* OPMLFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5170743B232AEDB500A461A3 /* OPMLFile.swift */; };
5193CD54245E3F7A0092735E /* RedditFeedProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5193CD53245E3F7A0092735E /* RedditFeedProvider.swift */; };
5193CD81245F295E0092735E /* RedditUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5193CD80245F295E0092735E /* RedditUser.swift */; };
519E84A62433D49000D238B0 /* OPMLNormalizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E84A52433D49000D238B0 /* OPMLNormalizer.swift */; };
519E84A82434C5EF00D238B0 /* CloudKitArticlesZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E84A72434C5EF00D238B0 /* CloudKitArticlesZone.swift */; };
519E84AC2435019100D238B0 /* CloudKitArticlesZoneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E84AB2435019100D238B0 /* CloudKitArticlesZoneDelegate.swift */; };
@ -306,6 +306,7 @@
5133BB46245FD8140001E3D0 /* RedditLinkListing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditLinkListing.swift; sourceTree = "<group>"; };
5133BB48246078910001E3D0 /* RedditLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditLink.swift; sourceTree = "<group>"; };
5133BB4A2460BDF30001E3D0 /* RedditSubreddit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditSubreddit.swift; sourceTree = "<group>"; };
5133BB4C2460CA0B0001E3D0 /* RedditMe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditMe.swift; sourceTree = "<group>"; };
5139A6372459822D004D960C /* CloudKitArticleStatusUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitArticleStatusUpdate.swift; sourceTree = "<group>"; };
5144EA48227B497600D19003 /* FeedbinAPICaller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAPICaller.swift; sourceTree = "<group>"; };
5144EA4D227B829A00D19003 /* FeedbinAccountDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbinAccountDelegate.swift; sourceTree = "<group>"; };
@ -324,7 +325,6 @@
516896342448EBEA00185AC5 /* FeedProviderManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedProviderManager.swift; sourceTree = "<group>"; };
5170743B232AEDB500A461A3 /* OPMLFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLFile.swift; sourceTree = "<group>"; };
5193CD53245E3F7A0092735E /* RedditFeedProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditFeedProvider.swift; sourceTree = "<group>"; };
5193CD80245F295E0092735E /* RedditUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditUser.swift; sourceTree = "<group>"; };
519E84A52433D49000D238B0 /* OPMLNormalizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLNormalizer.swift; sourceTree = "<group>"; };
519E84A72434C5EF00D238B0 /* CloudKitArticlesZone.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudKitArticlesZone.swift; sourceTree = "<group>"; };
519E84AB2435019100D238B0 /* CloudKitArticlesZoneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudKitArticlesZoneDelegate.swift; sourceTree = "<group>"; };
@ -642,7 +642,7 @@
5133BB48246078910001E3D0 /* RedditLink.swift */,
5133BB46245FD8140001E3D0 /* RedditLinkListing.swift */,
5133BB4A2460BDF30001E3D0 /* RedditSubreddit.swift */,
5193CD80245F295E0092735E /* RedditUser.swift */,
5133BB4C2460CA0B0001E3D0 /* RedditMe.swift */,
);
path = Reddit;
sourceTree = "<group>";
@ -1185,6 +1185,7 @@
9ECC9A85234DC16E009B5144 /* FeedlyAccountDelegateError.swift in Sources */,
9EA3133B231E368100268BA0 /* FeedlyAccountDelegate.swift in Sources */,
51E5959B228C781500FCC42B /* FeedbinStarredEntry.swift in Sources */,
5133BB4D2460CA0B0001E3D0 /* RedditMe.swift in Sources */,
846E77451F6EF9B900A165E2 /* Container.swift in Sources */,
9EA643D3239305680018A28C /* FeedlySearchOperation.swift in Sources */,
5150FFFE243823B800C1A442 /* CloudKitError.swift in Sources */,
@ -1229,7 +1230,6 @@
9E1D15512334282100F4944C /* FeedlyMirrorCollectionsAsFoldersOperation.swift in Sources */,
9E1773D7234575AB0056A5A8 /* FeedlyTag.swift in Sources */,
3B826DAB2385C81C00FC1ADB /* FeedWranglerConfig.swift in Sources */,
5193CD81245F295E0092735E /* RedditUser.swift in Sources */,
515E4EB62324FF8C0057B0E7 /* URLRequest+RSWeb.swift in Sources */,
51B36315244BCCA4000DEF2A /* TwitterSearchResult.swift in Sources */,
9EB1D576238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift in Sources */,

View File

@ -80,8 +80,25 @@ public final class RedditFeedProvider: FeedProvider {
}
public func iconURL(_ urlComponents: URLComponents, completion: @escaping (Result<String, Error>) -> Void) {
// TODO: call https://www.reddit.com/user/<USERNAME>/about.json to get the key "icon_img"
completion(.failure(RedditFeedProviderError.unknown))
guard urlComponents.path.hasPrefix("/r/"), let secondElement = extractSecondElement(path: urlComponents.path) else {
completion(.failure(RedditFeedProviderError.unknown))
return
}
let api = "/r/\(secondElement)/about.json"
fetch(api: api, parameters: [:], resultType: RedditSubreddit.self) { result in
switch result {
case .success(let subreddit):
if let iconURL = subreddit.data?.iconURL, !iconURL.isEmpty {
completion(.success(iconURL))
} else {
completion(.failure(RedditFeedProviderError.unknown))
}
case .failure(let error):
completion(.failure(error))
}
}
}
public func assignName(_ urlComponents: URLComponents, completion: @escaping (Result<String, Error>) -> Void) {
@ -106,7 +123,9 @@ public final class RedditFeedProvider: FeedProvider {
completion(.failure(TwitterFeedProviderError.unknown))
return
}
let api = "\(urlComponents.path).json"
fetch(api: api, parameters: [:], resultType: RedditLinkListing.self) { result in
switch result {
case .success(let linkListing):
@ -116,7 +135,6 @@ public final class RedditFeedProvider: FeedProvider {
completion(.failure(error))
}
}
}
public static func create(tokenSuccess: OAuthSwift.TokenSuccess, completion: @escaping (Result<RedditFeedProvider, Error>) -> Void) {
@ -124,7 +142,7 @@ public final class RedditFeedProvider: FeedProvider {
let oauthRefreshToken = tokenSuccess.credential.oauthRefreshToken
let redditFeedProvider = RedditFeedProvider(oauthToken: oauthToken, oauthRefreshToken: oauthRefreshToken)
redditFeedProvider.fetch(api: "/api/v1/me", resultType: RedditUser.self) { result in
redditFeedProvider.fetch(api: "/api/v1/me", resultType: RedditMe.self) { result in
switch result {
case .success(let user):
guard let username = user.name else {
@ -146,7 +164,6 @@ public final class RedditFeedProvider: FeedProvider {
}
}
}
// MARK: OAuth1SwiftProvider
@ -264,7 +281,7 @@ private extension RedditFeedProvider {
var urlComponents = URLComponents(string: "https://www.reddit.com")
urlComponents?.path = "/u/\(username)"
let userURL = urlComponents?.url?.absoluteString
return Set([ParsedAuthor(name: "u/\(username)", url: userURL, avatarURL: userURL, emailAddress: nil)])
return Set([ParsedAuthor(name: "u/\(username)", url: userURL, avatarURL: nil, emailAddress: nil)])
}
func handleFailure(error: OAuthSwiftError, completion: @escaping (Error?) -> Void) {
@ -299,10 +316,22 @@ private extension RedditFeedProvider {
}
}
func extractSecondElement(path: String) -> String? {
let scanner = Scanner(string: path)
if let _ = scanner.scanString("/"),
let _ = scanner.scanUpToString("/"),
let _ = scanner.scanString("/"),
let secondElement = scanner.scanUpToString("/") {
return secondElement
}
return nil
}
static func storeCredentials(username: String, oauthToken: String, oauthRefreshToken: String) throws {
let tokenCredentials = Credentials(type: .oauthAccessToken, username: username, secret: oauthToken)
try CredentialsManager.storeCredentials(tokenCredentials, server: Self.server)
let tokenSecretCredentials = Credentials(type: .oauthRefreshToken, username: username, secret: oauthRefreshToken)
try CredentialsManager.storeCredentials(tokenSecretCredentials, server: Self.server)
}
}

View File

@ -1,17 +1,17 @@
//
// RedditUser.swift
// RedditMe.swift
// Account
//
// Created by Maurice Parker on 5/3/20.
// Created by Maurice Parker on 5/4/20.
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
//
import Foundation
struct RedditUser: Codable {
struct RedditMe: Codable {
let name: String?
enum CodingKeys: String, CodingKey {
case name = "name"
}

View File

@ -10,10 +10,32 @@ import Foundation
struct RedditSubreddit: Codable {
let kind: String?
let data: RedditSubredditData?
enum CodingKeys: String, CodingKey {
case kind = "kind"
case data = "data"
}
}
struct RedditSubredditData: Codable {
let iconImg: String?
let communityIcon: String?
enum CodingKeys: String, CodingKey {
case iconImg = "iconImg"
case iconImg = "icon_img"
case communityIcon = "community_icon"
}
var iconURL: String? {
if let communityIcon = communityIcon, !communityIcon.isEmpty {
return communityIcon
} else {
return iconImg
}
}
}