FIrst pass at OPML import. Broken.
This commit is contained in:
parent
a6e0cae377
commit
42203c0170
|
@ -49,10 +49,11 @@ final class GoogleReaderCompatibleAPICaller: NSObject {
|
|||
case editTag = "/reader/api/0/edit-tag"
|
||||
}
|
||||
|
||||
// private let GoogleReaderCompatibleBaseURL = URL(string: "https://api.GoogleReaderCompatible.com/v2/")!
|
||||
private var transport: Transport!
|
||||
|
||||
var credentials: Credentials?
|
||||
private var accessToken: String?
|
||||
|
||||
weak var accountMetadata: AccountMetadata?
|
||||
|
||||
var server: String? {
|
||||
|
@ -127,6 +128,13 @@ final class GoogleReaderCompatibleAPICaller: NSObject {
|
|||
}
|
||||
|
||||
func requestAuthorizationToken(endpoint: URL, completion: @escaping (Result<String, Error>) -> Void) {
|
||||
// If we have a token already, use it
|
||||
if let accessToken = accessToken {
|
||||
completion(.success(accessToken))
|
||||
return
|
||||
}
|
||||
|
||||
// Otherwise request one.
|
||||
guard let credentials = credentials else {
|
||||
completion(.failure(CredentialsError.incompleteCredentials))
|
||||
return
|
||||
|
@ -143,67 +151,19 @@ final class GoogleReaderCompatibleAPICaller: NSObject {
|
|||
}
|
||||
|
||||
// Convert the return data to UTF8 and then parse out the Auth token
|
||||
guard let rawData = String(data: resultData, encoding: .utf8) else {
|
||||
guard let accessToken = String(data: resultData, encoding: .utf8) else {
|
||||
completion(.failure(TransportError.noData))
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
completion(.success(rawData))
|
||||
self.accessToken = accessToken
|
||||
completion(.success(accessToken))
|
||||
case .failure(let error):
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func importOPML(opmlData: Data, completion: @escaping (Result<GoogleReaderCompatibleImportResult, Error>) -> Void) {
|
||||
|
||||
// let callURL = GoogleReaderCompatibleBaseURL.appendingPathComponent("imports.json")
|
||||
// var request = URLRequest(url: callURL, credentials: credentials)
|
||||
// request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: HTTPRequestHeader.contentType)
|
||||
//
|
||||
// transport.send(request: request, method: HTTPMethod.post, payload: opmlData) { result in
|
||||
//
|
||||
// switch result {
|
||||
// case .success(let (_, data)):
|
||||
//
|
||||
// guard let resultData = data else {
|
||||
// completion(.failure(TransportError.noData))
|
||||
// break
|
||||
// }
|
||||
//
|
||||
// do {
|
||||
// let result = try JSONDecoder().decode(GoogleReaderCompatibleImportResult.self, from: resultData)
|
||||
// completion(.success(result))
|
||||
// } catch {
|
||||
// completion(.failure(error))
|
||||
// }
|
||||
//
|
||||
// case .failure(let error):
|
||||
// completion(.failure(error))
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
func retrieveOPMLImportResult(importID: Int, completion: @escaping (Result<GoogleReaderCompatibleImportResult?, Error>) -> Void) {
|
||||
|
||||
// let callURL = GoogleReaderCompatibleBaseURL.appendingPathComponent("imports/\(importID).json")
|
||||
// let request = URLRequest(url: callURL, credentials: credentials)
|
||||
//
|
||||
// transport.send(request: request, resultType: GoogleReaderCompatibleImportResult.self) { result in
|
||||
//
|
||||
// switch result {
|
||||
// case .success(let (_, importResult)):
|
||||
// completion(.success(importResult))
|
||||
// case .failure(let error):
|
||||
// completion(.failure(error))
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
func retrieveTags(completion: @escaping (Result<[GoogleReaderCompatibleTag]?, Error>) -> Void) {
|
||||
guard let baseURL = APIBaseURL else {
|
||||
|
|
|
@ -210,31 +210,113 @@ final class GoogleReaderCompatibleAccountDelegate: AccountDelegate {
|
|||
return
|
||||
}
|
||||
|
||||
os_log(.debug, log: log, "Begin importing OPML...")
|
||||
opmlImportInProgress = true
|
||||
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
|
||||
var opmlDocument: RSOPMLDocument?
|
||||
|
||||
caller.importOPML(opmlData: opmlData) { result in
|
||||
switch result {
|
||||
case .success(let importResult):
|
||||
if importResult.complete {
|
||||
os_log(.debug, log: self.log, "Import OPML done.")
|
||||
self.opmlImportInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(()))
|
||||
}
|
||||
} else {
|
||||
self.checkImportResult(opmlImportResultID: importResult.importResultID, completion: completion)
|
||||
do {
|
||||
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let loadDocument = opmlDocument else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
// We use the same mechanism to load local accounts as we do to load the subscription
|
||||
// OPML all accounts.
|
||||
BatchUpdate.shared.perform {
|
||||
loadOPML(account: account, opmlDocument: loadDocument)
|
||||
}
|
||||
completion(.success(()))
|
||||
|
||||
}
|
||||
|
||||
func loadOPML(account: Account, opmlDocument: RSOPMLDocument) {
|
||||
|
||||
guard let children = opmlDocument.children else {
|
||||
return
|
||||
}
|
||||
loadOPMLItems(account: account, items: children, parentFolder: nil)
|
||||
}
|
||||
|
||||
func loadOPMLItems(account: Account, items: [RSOPMLItem], parentFolder: Folder?) {
|
||||
|
||||
var feedsToAdd = Set<String>()
|
||||
|
||||
items.forEach { (item) in
|
||||
|
||||
if let feedSpecifier = item.feedSpecifier {
|
||||
feedsToAdd.insert(feedSpecifier.feedURL)
|
||||
return
|
||||
}
|
||||
|
||||
guard let folderName = item.titleFromAttributes else {
|
||||
// Folder doesn’t have a name, so it won’t be created, and its items will go one level up.
|
||||
if let itemChildren = item.children {
|
||||
loadOPMLItems(account: account, items: itemChildren, parentFolder: parentFolder)
|
||||
}
|
||||
case .failure(let error):
|
||||
os_log(.debug, log: self.log, "Import OPML failed.")
|
||||
self.opmlImportInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
let wrappedError = AccountError.wrappedError(error: error, account: account)
|
||||
completion(.failure(wrappedError))
|
||||
return
|
||||
}
|
||||
|
||||
if let itemChildren = item.children, let folder = account.ensureFolder(with: folderName) {
|
||||
loadOPMLItems(account: account, items: itemChildren, parentFolder: folder)
|
||||
}
|
||||
}
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
if let parentFolder = parentFolder {
|
||||
for url in feedsToAdd {
|
||||
group.enter()
|
||||
caller.createSubscription(url: url) { result in
|
||||
group.leave()
|
||||
switch result {
|
||||
case .success(let subResult):
|
||||
switch subResult {
|
||||
case .created(let subscription):
|
||||
let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: String(subscription.feedID), homePageURL: subscription.homePageURL)
|
||||
feed.subscriptionID = String(subscription.feedID)
|
||||
account.addFeed(feed, to: parentFolder) { _ in }
|
||||
default:
|
||||
break
|
||||
}
|
||||
case .failure(_):
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for url in feedsToAdd {
|
||||
group.enter()
|
||||
caller.createSubscription(url: url) { result in
|
||||
group.leave()
|
||||
switch result {
|
||||
case .success(let subResult):
|
||||
switch subResult {
|
||||
case .created(let subscription):
|
||||
let feed = account.createFeed(with: subscription.name, url: subscription.url, feedID: String(subscription.feedID), homePageURL: subscription.homePageURL)
|
||||
feed.subscriptionID = String(subscription.feedID)
|
||||
account.addFeed(feed)
|
||||
default:
|
||||
break
|
||||
}
|
||||
case .failure(_):
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: DispatchQueue.main) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.refreshAll(for: account) { (_) in }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addFolder(for account: Account, name: String, completion: @escaping (Result<Folder, Error>) -> Void) {
|
||||
|
@ -498,41 +580,6 @@ private extension GoogleReaderCompatibleAccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func checkImportResult(opmlImportResultID: Int, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { timer in
|
||||
|
||||
os_log(.debug, log: self.log, "Checking status of OPML import...")
|
||||
|
||||
self.caller.retrieveOPMLImportResult(importID: opmlImportResultID) { result in
|
||||
switch result {
|
||||
case .success(let importResult):
|
||||
if let result = importResult, result.complete {
|
||||
os_log(.debug, log: self.log, "Checking status of OPML import successfully completed.")
|
||||
timer.invalidate()
|
||||
self.opmlImportInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
case .failure(let error):
|
||||
os_log(.debug, log: self.log, "Import OPML check failed.")
|
||||
timer.invalidate()
|
||||
self.opmlImportInProgress = false
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func syncFolders(_ account: Account, _ tags: [GoogleReaderCompatibleTag]?) {
|
||||
|
||||
guard let tags = tags else { return }
|
||||
|
|
Loading…
Reference in New Issue