mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-02 12:06:58 +01:00
Fix build errors triggered by moving NewsBlur to module.
This commit is contained in:
parent
8c2db159d2
commit
a51d161e35
@ -9,6 +9,7 @@
|
||||
import Foundation
|
||||
import Web
|
||||
import Secrets
|
||||
import NewsBlur
|
||||
|
||||
public extension URLRequest {
|
||||
|
||||
|
@ -9,36 +9,42 @@
|
||||
import Foundation
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurFolder = NewsBlurFeedsResponse.Folder
|
||||
public typealias NewsBlurFolder = NewsBlurFeedsResponse.Folder
|
||||
|
||||
struct NewsBlurFeed: Hashable, Codable {
|
||||
let name: String
|
||||
let feedID: Int
|
||||
let feedURL: String
|
||||
let homePageURL: String?
|
||||
let faviconURL: String?
|
||||
public struct NewsBlurFeed: Hashable, Codable, Sendable {
|
||||
|
||||
public let name: String
|
||||
public let feedID: Int
|
||||
public let feedURL: String
|
||||
public let homePageURL: String?
|
||||
public let faviconURL: String?
|
||||
}
|
||||
|
||||
struct NewsBlurFeedsResponse: Decodable {
|
||||
let feeds: [NewsBlurFeed]
|
||||
let folders: [Folder]
|
||||
public struct NewsBlurFeedsResponse: Decodable, Sendable {
|
||||
|
||||
struct Folder: Hashable, Codable {
|
||||
let name: String
|
||||
let feedIDs: [Int]
|
||||
public let feeds: [NewsBlurFeed]
|
||||
public let folders: [Folder]
|
||||
|
||||
public struct Folder: Hashable, Codable, Sendable {
|
||||
|
||||
public let name: String
|
||||
public let feedIDs: [Int]
|
||||
}
|
||||
}
|
||||
|
||||
struct NewsBlurAddURLResponse: Decodable {
|
||||
let feed: NewsBlurFeed?
|
||||
public struct NewsBlurAddURLResponse: Decodable, Sendable {
|
||||
|
||||
public let feed: NewsBlurFeed?
|
||||
}
|
||||
|
||||
struct NewsBlurFolderRelationship {
|
||||
let folderName: String
|
||||
let feedID: Int
|
||||
public struct NewsBlurFolderRelationship: Sendable {
|
||||
|
||||
public let folderName: String
|
||||
public let feedID: Int
|
||||
}
|
||||
|
||||
extension NewsBlurFeed {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case name = "feed_title"
|
||||
case feedID = "id"
|
||||
@ -49,13 +55,14 @@ extension NewsBlurFeed {
|
||||
}
|
||||
|
||||
extension NewsBlurFeedsResponse {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case feeds = "feeds"
|
||||
case folders = "flat_folders"
|
||||
// TODO: flat_folders_with_inactive
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Tricky part: Some feeds listed in `feeds` don't exist in `folders` for some reason
|
||||
@ -88,7 +95,8 @@ extension NewsBlurFeedsResponse {
|
||||
}
|
||||
|
||||
extension NewsBlurFeedsResponse.Folder {
|
||||
var asRelationships: [NewsBlurFolderRelationship] {
|
||||
|
||||
public var asRelationships: [NewsBlurFolderRelationship] {
|
||||
return feedIDs.map { NewsBlurFolderRelationship(folderName: name, feedID: $0) }
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum NewsBlurFeedChange {
|
||||
public enum NewsBlurFeedChange: Sendable {
|
||||
|
||||
case add(String, String?)
|
||||
case rename(String, String)
|
||||
case delete(String, String?)
|
||||
@ -16,7 +17,8 @@ enum NewsBlurFeedChange {
|
||||
}
|
||||
|
||||
extension NewsBlurFeedChange: NewsBlurDataConvertible {
|
||||
var asData: Data? {
|
||||
|
||||
public var asData: Data? {
|
||||
var postData = URLComponents()
|
||||
postData.queryItems = {
|
||||
switch self {
|
||||
|
@ -8,14 +8,16 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum NewsBlurFolderChange {
|
||||
public enum NewsBlurFolderChange: Sendable {
|
||||
|
||||
case add(String)
|
||||
case rename(String, String)
|
||||
case delete(String, [String])
|
||||
}
|
||||
|
||||
extension NewsBlurFolderChange: NewsBlurDataConvertible {
|
||||
var asData: Data? {
|
||||
|
||||
public var asData: Data? {
|
||||
var postData = URLComponents()
|
||||
postData.queryItems = {
|
||||
switch self {
|
||||
|
@ -8,18 +8,19 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NewsBlurGenericCodingKeys: CodingKey {
|
||||
var stringValue: String
|
||||
public struct NewsBlurGenericCodingKeys: CodingKey {
|
||||
|
||||
init?(stringValue: String) {
|
||||
public var stringValue: String
|
||||
|
||||
public init?(stringValue: String) {
|
||||
self.stringValue = stringValue
|
||||
}
|
||||
|
||||
var intValue: Int? {
|
||||
public var intValue: Int? {
|
||||
return nil
|
||||
}
|
||||
|
||||
init?(intValue: Int) {
|
||||
public init?(intValue: Int) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,20 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NewsBlurLoginResponse: Decodable {
|
||||
var code: Int
|
||||
var errors: LoginError?
|
||||
public struct NewsBlurLoginResponse: Decodable, Sendable {
|
||||
|
||||
struct LoginError: Decodable {
|
||||
var username: [String]?
|
||||
var others: [String]?
|
||||
public var code: Int
|
||||
public var errors: LoginError?
|
||||
|
||||
public struct LoginError: Decodable, Sendable {
|
||||
|
||||
public var username: [String]?
|
||||
public var others: [String]?
|
||||
}
|
||||
}
|
||||
|
||||
extension NewsBlurLoginResponse.LoginError {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case username = "username"
|
||||
case others = "__all__"
|
||||
|
@ -9,23 +9,25 @@
|
||||
import Foundation
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurStory = NewsBlurStoriesResponse.Story
|
||||
public typealias NewsBlurStory = NewsBlurStoriesResponse.Story
|
||||
|
||||
struct NewsBlurStoriesResponse: Decodable {
|
||||
let stories: [Story]
|
||||
public struct NewsBlurStoriesResponse: Decodable, Sendable {
|
||||
|
||||
struct Story: Decodable {
|
||||
let storyID: String
|
||||
let feedID: Int
|
||||
let title: String?
|
||||
let url: String?
|
||||
let authorName: String?
|
||||
let contentHTML: String?
|
||||
var imageURL: String? {
|
||||
public let stories: [Story]
|
||||
|
||||
public struct Story: Decodable, Sendable {
|
||||
|
||||
public let storyID: String
|
||||
public let feedID: Int
|
||||
public let title: String?
|
||||
public let url: String?
|
||||
public let authorName: String?
|
||||
public let contentHTML: String?
|
||||
public var imageURL: String? {
|
||||
return imageURLs?.first?.value
|
||||
}
|
||||
var tags: [String]?
|
||||
var datePublished: Date? {
|
||||
public var tags: [String]?
|
||||
public var datePublished: Date? {
|
||||
let interval = (publishedTimestamp as NSString).doubleValue
|
||||
return Date(timeIntervalSince1970: interval)
|
||||
}
|
||||
@ -36,12 +38,14 @@ struct NewsBlurStoriesResponse: Decodable {
|
||||
}
|
||||
|
||||
extension NewsBlurStoriesResponse {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case stories = "stories"
|
||||
}
|
||||
}
|
||||
|
||||
extension NewsBlurStoriesResponse.Story {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case storyID = "story_hash"
|
||||
case feedID = "story_feed_id"
|
||||
|
@ -9,27 +9,36 @@
|
||||
import Foundation
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurStoryHash = NewsBlurStoryHashesResponse.StoryHash
|
||||
public typealias NewsBlurStoryHash = NewsBlurStoryHashesResponse.StoryHash
|
||||
|
||||
struct NewsBlurStoryHashesResponse: Decodable {
|
||||
typealias StoryHashDictionary = [String: [StoryHash]]
|
||||
public struct NewsBlurStoryHashesResponse: Decodable, Sendable {
|
||||
|
||||
var unread: [StoryHash]?
|
||||
var starred: [StoryHash]?
|
||||
public typealias StoryHashDictionary = [String: [StoryHash]]
|
||||
|
||||
struct StoryHash: Hashable, Codable {
|
||||
var hash: String
|
||||
var timestamp: Date
|
||||
public var unread: [StoryHash]?
|
||||
public var starred: [StoryHash]?
|
||||
|
||||
public struct StoryHash: Hashable, Codable, Sendable {
|
||||
|
||||
public var hash: String
|
||||
public var timestamp: Date
|
||||
|
||||
public init(hash: String, timestamp: Date) {
|
||||
|
||||
self.hash = hash
|
||||
self.timestamp = timestamp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NewsBlurStoryHashesResponse {
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case unread = "unread_feed_story_hashes"
|
||||
case starred = "starred_story_hashes"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
// Parse unread
|
||||
|
@ -8,12 +8,14 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct NewsBlurStoryStatusChange {
|
||||
let hashes: [String]
|
||||
public struct NewsBlurStoryStatusChange: Sendable {
|
||||
|
||||
public let hashes: [String]
|
||||
}
|
||||
|
||||
extension NewsBlurStoryStatusChange: NewsBlurDataConvertible {
|
||||
var asData: Data? {
|
||||
|
||||
public var asData: Data? {
|
||||
var postData = URLComponents()
|
||||
postData.queryItems = hashes.map { URLQueryItem(name: "story_hash", value: $0) }
|
||||
|
||||
|
@ -9,16 +9,18 @@
|
||||
import Foundation
|
||||
import Web
|
||||
|
||||
protocol NewsBlurDataConvertible {
|
||||
public protocol NewsBlurDataConvertible {
|
||||
|
||||
var asData: Data? { get }
|
||||
}
|
||||
|
||||
enum NewsBlurError: LocalizedError {
|
||||
public enum NewsBlurError: LocalizedError, Sendable {
|
||||
|
||||
case general(message: String)
|
||||
case invalidParameter
|
||||
case unknown
|
||||
|
||||
var errorDescription: String? {
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .general(let message):
|
||||
return message
|
||||
|
@ -11,30 +11,31 @@ import Web
|
||||
import Secrets
|
||||
|
||||
@MainActor public final class NewsBlurAPICaller: NSObject {
|
||||
static let SessionIdCookie = "newsblur_sessionid"
|
||||
|
||||
public static let SessionIdCookie = "newsblur_sessionid"
|
||||
|
||||
let baseURL = URL(string: "https://www.newsblur.com/")!
|
||||
var transport: Transport!
|
||||
var suspended = false
|
||||
|
||||
var credentials: Credentials?
|
||||
public var credentials: Credentials?
|
||||
|
||||
init(transport: Transport!) {
|
||||
public init(transport: Transport!) {
|
||||
super.init()
|
||||
self.transport = transport
|
||||
}
|
||||
|
||||
/// Cancels all pending requests rejects any that come in later
|
||||
func suspend() {
|
||||
public func suspend() {
|
||||
transport.cancelAll()
|
||||
suspended = true
|
||||
}
|
||||
|
||||
func resume() {
|
||||
public func resume() {
|
||||
suspended = false
|
||||
}
|
||||
|
||||
func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
public func validateCredentials(completion: @escaping (Result<Credentials?, Error>) -> Void) {
|
||||
requestData(endpoint: "api/login", resultType: NewsBlurLoginResponse.self) { result in
|
||||
switch result {
|
||||
case .success((let response, let payload)):
|
||||
@ -67,11 +68,11 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func logout(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func logout(completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
requestData(endpoint: "api/logout", completion: completion)
|
||||
}
|
||||
|
||||
func retrieveFeeds(completion: @escaping (Result<([NewsBlurFeed]?, [NewsBlurFolder]?), Error>) -> Void) {
|
||||
public func retrieveFeeds(completion: @escaping (Result<([NewsBlurFeed]?, [NewsBlurFolder]?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/feeds")
|
||||
.appendingQueryItems([
|
||||
@ -111,21 +112,21 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveUnreadStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
public func retrieveUnreadStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
retrieveStoryHashes(
|
||||
endpoint: "reader/unread_story_hashes",
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
func retrieveStarredStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
public func retrieveStarredStoryHashes(completion: @escaping (Result<[NewsBlurStoryHash]?, Error>) -> Void) {
|
||||
retrieveStoryHashes(
|
||||
endpoint: "reader/starred_story_hashes",
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
func retrieveStories(feedID: String, page: Int, completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
public func retrieveStories(feedID: String, page: Int, completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/feed/\(feedID)")
|
||||
.appendingQueryItems([
|
||||
@ -146,7 +147,7 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func retrieveStories(hashes: [NewsBlurStoryHash], completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
public func retrieveStories(hashes: [NewsBlurStoryHash], completion: @escaping (Result<([NewsBlurStory]?, Date?), Error>) -> Void) {
|
||||
let url = baseURL
|
||||
.appendingPathComponent("reader/river_stories")
|
||||
.appendingQueryItem(.init(name: "include_hidden", value: "false"))?
|
||||
@ -164,7 +165,7 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func markAsUnread(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func markAsUnread(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_unread",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@ -172,7 +173,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func markAsRead(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func markAsRead(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hashes_as_read",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@ -180,7 +181,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func star(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func star(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_starred",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@ -188,7 +189,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func unstar(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func unstar(hashes: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/mark_story_hash_as_unstarred",
|
||||
payload: NewsBlurStoryStatusChange(hashes: hashes),
|
||||
@ -196,7 +197,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func addFolder(named name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func addFolder(named name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/add_folder",
|
||||
payload: NewsBlurFolderChange.add(name),
|
||||
@ -204,7 +205,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func renameFolder(with folder: String, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func renameFolder(with folder: String, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/rename_folder",
|
||||
payload: NewsBlurFolderChange.rename(folder, name),
|
||||
@ -212,7 +213,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func removeFolder(named name: String, feedIDs: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func removeFolder(named name: String, feedIDs: [String], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/delete_folder",
|
||||
payload: NewsBlurFolderChange.delete(name, feedIDs),
|
||||
@ -220,7 +221,7 @@ import Secrets
|
||||
)
|
||||
}
|
||||
|
||||
func addURL(_ url: String, folder: String?, completion: @escaping (Result<NewsBlurFeed?, Error>) -> Void) {
|
||||
public func addURL(_ url: String, folder: String?, completion: @escaping (Result<NewsBlurFeed?, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/add_url",
|
||||
payload: NewsBlurFeedChange.add(url, folder),
|
||||
@ -235,7 +236,7 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func renameFeed(feedID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func renameFeed(feedID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/rename_feed",
|
||||
payload: NewsBlurFeedChange.rename(feedID, newName)
|
||||
@ -249,7 +250,7 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func deleteFeed(feedID: String, folder: String? = nil, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func deleteFeed(feedID: String, folder: String? = nil, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/delete_feed",
|
||||
payload: NewsBlurFeedChange.delete(feedID, folder)
|
||||
@ -263,7 +264,7 @@ import Secrets
|
||||
}
|
||||
}
|
||||
|
||||
func moveFeed(feedID: String, from: String?, to: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
public func moveFeed(feedID: String, from: String?, to: String?, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendUpdates(
|
||||
endpoint: "reader/move_feed_to_folder",
|
||||
payload: NewsBlurFeedChange.move(feedID, from, to)
|
||||
|
Loading…
x
Reference in New Issue
Block a user