Move local modules into a folder named Modules.

This commit is contained in:
Brent Simmons
2024-07-06 21:07:05 -07:00
parent 14bcef0f9a
commit d50b5818ac
491 changed files with 76 additions and 52 deletions

View File

@@ -0,0 +1,121 @@
//
// ArticleExtractor.swift
// NetNewsWire
//
// Created by Maurice Parker on 9/18/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import FoundationExtras
public enum ArticleExtractorState: Sendable {
case ready
case processing
case failedToParse
case complete
case cancelled
}
public protocol ArticleExtractorDelegate {
@MainActor func articleExtractionDidFail(with: Error)
@MainActor func articleExtractionDidComplete(extractedArticle: ExtractedArticle)
}
@MainActor public final class ArticleExtractor {
public var state: ArticleExtractorState!
public var article: ExtractedArticle?
public var delegate: ArticleExtractorDelegate?
public let articleLink: String?
private var dataTask: URLSessionDataTask? = nil
private let url: URL!
public init?(_ articleLink: String, clientID: String, clientSecret: String) {
self.articleLink = articleLink
let clientURL = "https://extract.feedbin.com/parser"
let username = clientID
let signature = articleLink.hmacUsingSHA1(key: clientSecret)
if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() {
let fullURL = "\(clientURL)/\(username)/\(signature)?base64_url=\(base64URL)"
if let url = URL(string: fullURL) {
self.url = url
return
}
}
return nil
}
public func process() {
state = .processing
dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
Task { @MainActor [weak self] in
guard let self else {
return
}
if let error {
self.noteDidFail(error: error)
return
}
guard let data else {
self.noteDidFail(error: URLError(.cannotDecodeContentData))
return
}
do {
let article = try decodeArticle(data: data)
self.article = article
if article.content == nil {
self.noteDidFail(error: URLError(.cannotDecodeContentData))
} else {
self.noteDidComplete(article: article)
}
} catch {
self.noteDidFail(error: error)
}
}
}
dataTask!.resume()
}
public func cancel() {
state = .cancelled
dataTask?.cancel()
}
}
private extension ArticleExtractor {
func decodeArticle(data: Data) throws -> ExtractedArticle {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let article = try decoder.decode(ExtractedArticle.self, from: data)
return article
}
func noteDidFail(error: Error) {
state = .failedToParse
delegate?.articleExtractionDidFail(with: error)
}
func noteDidComplete(article: ExtractedArticle) {
state = .complete
delegate?.articleExtractionDidComplete(extractedArticle: article)
}
}

View File

@@ -0,0 +1,44 @@
//
// ExtractedArticle.swift
// NetNewsWire
//
// Created by Maurice Parker on 9/18/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
public struct ExtractedArticle: Codable, Equatable, Sendable {
public let title: String?
public let author: String?
public let datePublished: String?
public let dek: String?
public let leadImageURL: String?
public let content: String?
public let nextPageURL: String?
public let url: String?
public let domain: String?
public let excerpt: String?
public let wordCount: Int?
public let direction: String?
public let totalPages: Int?
public let renderedPages: Int?
enum CodingKeys: String, CodingKey {
case title = "title"
case author = "author"
case datePublished = "date_published"
case dek = "dek"
case leadImageURL = "lead_image_url"
case content = "content"
case nextPageURL = "next_page_url"
case url = "url"
case domain = "domain"
case excerpt = "excerpt"
case wordCount = "word_count"
case direction = "direction"
case totalPages = "total_pages"
case renderedPages = "rendered_pages"
}
}