Add OPML import for Feedbin.
This commit is contained in:
parent
6f92cd1a73
commit
51c2527da2
|
@ -341,6 +341,18 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
|||
return ensureFolder(with: folderName)
|
||||
}
|
||||
|
||||
func newFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> Feed {
|
||||
let feedURL = opmlFeedSpecifier.feedURL
|
||||
let metadata = feedMetadata(feedURL: feedURL, feedID: feedURL)
|
||||
let feed = Feed(account: self, url: opmlFeedSpecifier.feedURL, metadata: metadata)
|
||||
if let feedTitle = opmlFeedSpecifier.title {
|
||||
if feed.name == nil {
|
||||
feed.name = feedTitle
|
||||
}
|
||||
}
|
||||
return feed
|
||||
}
|
||||
|
||||
func addFeed(container: Container, feed: Feed, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
delegate.addFeed(for: self, to: container, with: feed, completion: completion)
|
||||
}
|
||||
|
@ -905,18 +917,6 @@ private extension Account {
|
|||
feedDictionaryNeedsUpdate = false
|
||||
}
|
||||
|
||||
func ensureFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> Feed {
|
||||
let feedURL = opmlFeedSpecifier.feedURL
|
||||
let metadata = feedMetadata(feedURL: feedURL, feedID: feedURL)
|
||||
let feed = Feed(account: self, url: opmlFeedSpecifier.feedURL, metadata: metadata)
|
||||
if let feedTitle = opmlFeedSpecifier.title {
|
||||
if feed.name == nil {
|
||||
feed.name = feedTitle
|
||||
}
|
||||
}
|
||||
return feed
|
||||
}
|
||||
|
||||
func loadOPMLItems(_ items: [RSOPMLItem], parentFolder: Folder?) {
|
||||
|
||||
var feedsToAdd = Set<Feed>()
|
||||
|
@ -924,7 +924,7 @@ private extension Account {
|
|||
items.forEach { (item) in
|
||||
|
||||
if let feedSpecifier = item.feedSpecifier {
|
||||
let feed = ensureFeed(with: feedSpecifier)
|
||||
let feed = newFeed(with: feedSpecifier)
|
||||
feedsToAdd.insert(feed)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import UIKit
|
|||
import RSCore
|
||||
#endif
|
||||
import RSCore
|
||||
import RSParser
|
||||
import RSWeb
|
||||
import os.log
|
||||
|
||||
|
@ -64,6 +65,39 @@ final class FeedbinAccountDelegate: AccountDelegate {
|
|||
|
||||
func importOPML(for account:Account, opmlFile: URL, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
||||
var fileData: Data?
|
||||
|
||||
do {
|
||||
fileData = try Data(contentsOf: opmlFile)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let opmlData = fileData else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
|
||||
var opmlDocument: RSOPMLDocument?
|
||||
|
||||
do {
|
||||
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
guard let loadDocument = opmlDocument, let children = loadDocument.children else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
importOPMLItems(account, items: children, parentFolder: nil)
|
||||
|
||||
completion(.success(()))
|
||||
|
||||
}
|
||||
|
||||
func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
|
@ -342,6 +376,109 @@ private extension FeedbinAccountDelegate {
|
|||
|
||||
}
|
||||
|
||||
func importOPMLItems(_ account: Account, items: [RSOPMLItem], parentFolder: Folder?) {
|
||||
|
||||
items.forEach { (item) in
|
||||
|
||||
if let feedSpecifier = item.feedSpecifier {
|
||||
importFeedSpecifier(account, feedSpecifier: feedSpecifier, parentFolder: parentFolder)
|
||||
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 {
|
||||
importOPMLItems(account, items: itemChildren, parentFolder: parentFolder)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if let folder = account.ensureFolder(with: folderName) {
|
||||
if let itemChildren = item.children {
|
||||
importOPMLItems(account, items: itemChildren, parentFolder: folder)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func importFeedSpecifier(_ account: Account, feedSpecifier: RSOPMLFeedSpecifier, parentFolder: Folder?) {
|
||||
|
||||
caller.createSubscription(url: feedSpecifier.feedURL) { [weak self] result in
|
||||
|
||||
switch result {
|
||||
case .success(let subResult):
|
||||
switch subResult {
|
||||
case .created(let sub):
|
||||
|
||||
DispatchQueue.main.async {
|
||||
|
||||
let feed = account.createFeed(with: sub.name, url: sub.url, feedID: String(sub.feedID), homePageURL: sub.homePageURL)
|
||||
feed.subscriptionID = String(sub.subscriptionID)
|
||||
|
||||
self?.importFeedSpecifierPostProcess(account: account, sub: sub, feedSpecifier: feedSpecifier, feed: feed, parentFolder: parentFolder)
|
||||
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
case .failure(let error):
|
||||
guard let self = self else { return }
|
||||
os_log(.error, log: self.log, "Create feed on OPML import failed: %@.", error.localizedDescription)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func importFeedSpecifierPostProcess(account: Account, sub: FeedbinSubscription, feedSpecifier: RSOPMLFeedSpecifier, feed: Feed, parentFolder: Folder?) {
|
||||
|
||||
// Rename the feed if its name in the OPML file doesn't match the found name
|
||||
if sub.name != feedSpecifier.title, let newName = feedSpecifier.title {
|
||||
|
||||
self.caller.renameSubscription(subscriptionID: String(sub.subscriptionID), newName: newName) { [weak self] result in
|
||||
switch result {
|
||||
case .success:
|
||||
DispatchQueue.main.async {
|
||||
feed.editedName = newName
|
||||
}
|
||||
case .failure(let error):
|
||||
guard let self = self else { return }
|
||||
os_log(.error, log: self.log, "Rename feed on OPML import failed: %@.", error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Move the new feed if it is in a folder
|
||||
if let folder = parentFolder, let feedID = Int(feed.feedID) {
|
||||
|
||||
self.caller.createTagging(feedID: feedID, name: folder.name ?? "") { [weak self] result in
|
||||
switch result {
|
||||
case .success(let taggingID):
|
||||
DispatchQueue.main.async {
|
||||
self?.saveFolderRelationship(for: feed, withFolderName: folder.name ?? "", id: String(taggingID))
|
||||
folder.addFeed(feed)
|
||||
}
|
||||
case .failure(let error):
|
||||
guard let self = self else { return }
|
||||
os_log(.error, log: self.log, "Move feed to folder on OPML import failed: %@.", error.localizedDescription)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
DispatchQueue.main.async {
|
||||
account.addFeed(feed)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func syncFolders(_ account: Account, _ tags: [FeedbinTag]?) {
|
||||
|
||||
guard let tags = tags else { return }
|
||||
|
@ -606,7 +743,9 @@ private extension FeedbinAccountDelegate {
|
|||
account.addFeed(feed)
|
||||
}
|
||||
|
||||
if editedName != nil {
|
||||
processRestoredFeedName(for: account, feed: feed, editedName: editedName!, completion: completion)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue