Add initial tweet retrieval.
This commit is contained in:
parent
660cf29305
commit
9be641c094
|
@ -39,6 +39,7 @@
|
|||
5132AAC42448BAD90077840A /* FeedProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132AAC12448BAD90077840A /* FeedProvider.swift */; };
|
||||
5132AAC52448BAD90077840A /* TwitterFeedProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132AAC32448BAD90077840A /* TwitterFeedProvider.swift */; };
|
||||
5132DE812449159100806ADE /* TwitterUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132DE802449159100806ADE /* TwitterUser.swift */; };
|
||||
5132DE832449306F00806ADE /* Tweet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5132DE822449306F00806ADE /* Tweet.swift */; };
|
||||
513323082281070D00C30F19 /* AccountFeedbinSyncTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 513323072281070C00C30F19 /* AccountFeedbinSyncTest.swift */; };
|
||||
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 */; };
|
||||
|
@ -278,6 +279,7 @@
|
|||
5132AAC12448BAD90077840A /* FeedProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedProvider.swift; sourceTree = "<group>"; };
|
||||
5132AAC32448BAD90077840A /* TwitterFeedProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwitterFeedProvider.swift; sourceTree = "<group>"; };
|
||||
5132DE802449159100806ADE /* TwitterUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwitterUser.swift; sourceTree = "<group>"; };
|
||||
5132DE822449306F00806ADE /* Tweet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tweet.swift; sourceTree = "<group>"; };
|
||||
513323072281070C00C30F19 /* AccountFeedbinSyncTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountFeedbinSyncTest.swift; sourceTree = "<group>"; };
|
||||
513323092281082F00C30F19 /* subscriptions_initial.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_initial.json; sourceTree = "<group>"; };
|
||||
5133230B2281088A00C30F19 /* subscriptions_add.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscriptions_add.json; sourceTree = "<group>"; };
|
||||
|
@ -566,6 +568,7 @@
|
|||
children = (
|
||||
5132AAC32448BAD90077840A /* TwitterFeedProvider.swift */,
|
||||
5132DE802449159100806ADE /* TwitterUser.swift */,
|
||||
5132DE822449306F00806ADE /* Tweet.swift */,
|
||||
);
|
||||
path = Twitter;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1127,6 +1130,7 @@
|
|||
552032FD229D5D5A009559E0 /* ReaderAPITagging.swift in Sources */,
|
||||
9EAEC62A23331EE70085D7C9 /* FeedlyOrigin.swift in Sources */,
|
||||
9E5EC15B23E01DEF00A4E503 /* FeedlyRTLTextSanitizer.swift in Sources */,
|
||||
5132DE832449306F00806ADE /* Tweet.swift in Sources */,
|
||||
511B9804237CD4270028BCAA /* FeedIdentifier.swift in Sources */,
|
||||
84F73CF1202788D90000BCEF /* ArticleFetcher.swift in Sources */,
|
||||
841974251F6DDCE4006346C4 /* AccountDelegate.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// Tweet.swift
|
||||
// Account
|
||||
//
|
||||
// Created by Maurice Parker on 4/16/20.
|
||||
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Tweet: Codable {
|
||||
|
||||
let createdAt: Date?
|
||||
let idStr: String?
|
||||
let text: String?
|
||||
let user: TwitterUser
|
||||
let truncated: Bool
|
||||
let extendedTweet: ExtendedTweet?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case createdAt = "created_at"
|
||||
case idStr = "id_str"
|
||||
case text = "text"
|
||||
case user = "user"
|
||||
case truncated = "truncated"
|
||||
case extendedTweet = "extended_tweet"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct ExtendedTweet: Codable {
|
||||
|
||||
let full_text: String?
|
||||
|
||||
}
|
|
@ -87,7 +87,7 @@ public struct TwitterFeedProvider: FeedProvider {
|
|||
|
||||
public func iconURL(_ urlComponents: URLComponents, completion: @escaping (Result<String, Error>) -> Void) {
|
||||
if let screenName = deriveScreenName(urlComponents) {
|
||||
fetchUser(screenName: screenName) { result in
|
||||
retrieveUser(screenName: screenName) { result in
|
||||
switch result {
|
||||
case .success(let user):
|
||||
if let avatarURL = user.avatarURL {
|
||||
|
@ -127,7 +127,7 @@ public struct TwitterFeedProvider: FeedProvider {
|
|||
|
||||
default:
|
||||
if let screenName = deriveScreenName(urlComponents) {
|
||||
fetchUser(screenName: screenName) { result in
|
||||
retrieveUser(screenName: screenName) { result in
|
||||
switch result {
|
||||
case .success(let user):
|
||||
if let userName = user.name {
|
||||
|
@ -149,7 +149,41 @@ public struct TwitterFeedProvider: FeedProvider {
|
|||
}
|
||||
|
||||
public func refresh(_ webFeed: WebFeed, completion: @escaping (Result<Set<ParsedItem>, Error>) -> Void) {
|
||||
// TODO: Finish implementation
|
||||
let api = "statuses/user_timeline.json"
|
||||
|
||||
retrieveTweets(api: api) { result in
|
||||
switch result {
|
||||
case .success(let tweets):
|
||||
|
||||
var parsedItems = Set<ParsedItem>()
|
||||
for tweet in tweets {
|
||||
guard let idStr = tweet.idStr, let userScreenName = tweet.user.screenName else { continue }
|
||||
let parsedItem = ParsedItem(syncServiceID: idStr,
|
||||
uniqueID: idStr,
|
||||
feedURL: webFeed.url,
|
||||
url: "https://twitter.com/\(userScreenName)/status/\(idStr)",
|
||||
externalURL: nil,
|
||||
title: nil,
|
||||
language: nil,
|
||||
contentHTML: tweet.text,
|
||||
contentText: tweet.text,
|
||||
summary: tweet.text,
|
||||
imageURL: nil,
|
||||
bannerImageURL: nil,
|
||||
datePublished: tweet.createdAt,
|
||||
dateModified: nil,
|
||||
authors: nil,
|
||||
tags: nil,
|
||||
attachments: nil)
|
||||
parsedItems.insert(parsedItem)
|
||||
}
|
||||
|
||||
completion(.success(parsedItems))
|
||||
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -185,7 +219,7 @@ private extension TwitterFeedProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func fetchUser(screenName: String, completion: @escaping (Result<TwitterUser, Error>) -> Void) {
|
||||
func retrieveUser(screenName: String, completion: @escaping (Result<TwitterUser, Error>) -> Void) {
|
||||
let url = "\(Self.apiBase)users/show.json"
|
||||
let parameters = ["screen_name": screenName]
|
||||
|
||||
|
@ -205,4 +239,27 @@ private extension TwitterFeedProvider {
|
|||
}
|
||||
}
|
||||
|
||||
func retrieveTweets(api: String, completion: @escaping (Result<[Tweet], Error>) -> Void) {
|
||||
let url = "\(Self.apiBase)\(api)"
|
||||
let parameters = [String: Any]()
|
||||
|
||||
client.get(url, parameters: parameters) { result in
|
||||
switch result {
|
||||
case .success(let response):
|
||||
let decoder = JSONDecoder()
|
||||
let dateFormatter = DateFormatter()
|
||||
dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
|
||||
decoder.dateDecodingStrategy = .formatted(dateFormatter)
|
||||
do {
|
||||
let tweets = try decoder.decode([Tweet].self, from: response.data)
|
||||
completion(.success(tweets))
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
}
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,10 +11,12 @@ import Foundation
|
|||
struct TwitterUser: Codable {
|
||||
|
||||
let name: String?
|
||||
let screenName: String?
|
||||
let avatarURL: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case name = "name"
|
||||
case screenName = "screen_name"
|
||||
case avatarURL = "profile_image_url_https"
|
||||
}
|
||||
|
||||
|
|
|
@ -141,6 +141,7 @@ final class LocalAccountDelegate: AccountDelegate {
|
|||
case .success(let parsedItems):
|
||||
account.update(urlString, with: parsedItems) { _ in
|
||||
container.addWebFeed(feed)
|
||||
completion(.success(feed))
|
||||
}
|
||||
case .failure:
|
||||
completion(.failure(AccountError.createErrorNotFound))
|
||||
|
|
Loading…
Reference in New Issue