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