NetNewsWire/Shared/ArticleExtractor/ArticleExtractor.swift

112 lines
2.8 KiB
Swift
Raw Normal View History

2019-09-18 18:15:55 -05:00
//
// ArticleExtractor.swift
// NetNewsWire
//
// Created by Maurice Parker on 9/18/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import Foundation
import Account
2020-04-09 21:07:56 -05:00
import Secrets
2019-09-18 18:15:55 -05:00
public enum ArticleExtractorState {
case ready
case processing
case failedToParse
case complete
case cancelled
2019-09-18 18:15:55 -05:00
}
2025-01-23 22:17:28 -08:00
protocol ArticleExtractorDelegate: AnyObject {
2019-09-18 18:15:55 -05:00
func articleExtractionDidFail(with: Error)
func articleExtractionDidComplete(extractedArticle: ExtractedArticle)
}
class ArticleExtractor {
2025-01-22 22:20:08 -08:00
private var dataTask: URLSessionDataTask?
2019-09-18 18:15:55 -05:00
var state: ArticleExtractorState!
var article: ExtractedArticle?
2025-01-23 22:17:28 -08:00
weak var delegate: ArticleExtractorDelegate?
2019-09-18 18:15:55 -05:00
var articleLink: String?
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
private var url: URL!
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
public init?(_ articleLink: String) {
self.articleLink = articleLink
2025-01-22 22:20:08 -08:00
let clientURL = "https://extract.feedbin.com/parser"
let username = SecretKey.mercuryClientID
let signature = articleLink.hmacUsingSHA1(key: SecretKey.mercuryClientSecret)
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
if let base64URL = articleLink.data(using: .utf8)?.base64EncodedString() {
2024-12-06 18:06:27 +02:00
let fullURL = "\(clientURL)/\(username)/\(signature)?base64_url=\(base64URL)"
2019-09-18 18:15:55 -05:00
if let url = URL(string: fullURL) {
self.url = url
return
}
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
return nil
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
public func process() {
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
state = .processing
2025-01-22 22:20:08 -08:00
dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
2019-09-18 18:15:55 -05:00
guard let self = self else { return }
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
if let error = error {
self.state = .failedToParse
DispatchQueue.main.async {
self.delegate?.articleExtractionDidFail(with: error)
}
return
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
guard let data = data else {
self.state = .failedToParse
DispatchQueue.main.async {
self.delegate?.articleExtractionDidFail(with: URLError(.cannotDecodeContentData))
2019-09-18 18:15:55 -05:00
}
return
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
self.article = try decoder.decode(ExtractedArticle.self, from: data)
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
DispatchQueue.main.async {
if self.article?.content == nil {
self.state = .failedToParse
self.delegate?.articleExtractionDidFail(with: URLError(.cannotDecodeContentData))
} else {
self.state = .complete
self.delegate?.articleExtractionDidComplete(extractedArticle: self.article!)
}
2019-09-18 18:15:55 -05:00
}
} catch {
self.state = .failedToParse
DispatchQueue.main.async {
self.delegate?.articleExtractionDidFail(with: error)
}
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
}
2025-01-22 22:20:08 -08:00
dataTask!.resume()
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
}
2025-01-22 22:20:08 -08:00
public func cancel() {
state = .cancelled
dataTask?.cancel()
}
2025-01-22 22:20:08 -08:00
2019-09-18 18:15:55 -05:00
}