mirror of
https://github.com/Ranchero-Software/NetNewsWire
synced 2025-08-12 06:26:36 +00:00
Switch to new Parser.
This commit is contained in:
@@ -13,7 +13,7 @@ import UIKit
|
||||
import Foundation
|
||||
import RSCore
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSDatabase
|
||||
import ArticlesDatabase
|
||||
import RSWeb
|
||||
@@ -484,14 +484,14 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
delegate.accountWillBeDeleted(self)
|
||||
}
|
||||
|
||||
func addOPMLItems(_ items: [RSOPMLItem]) {
|
||||
func addOPMLItems(_ items: [OPMLItem]) {
|
||||
for item in items {
|
||||
if let feedSpecifier = item.feedSpecifier {
|
||||
addFeed(newFeed(with: feedSpecifier))
|
||||
} else {
|
||||
if let title = item.titleFromAttributes, let folder = ensureFolder(with: title) {
|
||||
folder.externalID = item.attributes?["nnw_externalID"] as? String
|
||||
item.children?.forEach { itemChild in
|
||||
item.items?.forEach { itemChild in
|
||||
if let feedSpecifier = itemChild.feedSpecifier {
|
||||
folder.addFeed(newFeed(with: feedSpecifier))
|
||||
}
|
||||
@@ -501,7 +501,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
}
|
||||
}
|
||||
|
||||
func loadOPMLItems(_ items: [RSOPMLItem]) {
|
||||
func loadOPMLItems(_ items: [OPMLItem]) {
|
||||
addOPMLItems(OPMLNormalizer.normalize(items))
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ public final class Account: DisplayNameProvider, UnreadCountProvider, Container,
|
||||
return folders?.first(where: { $0.externalID == externalID })
|
||||
}
|
||||
|
||||
func newFeed(with opmlFeedSpecifier: RSOPMLFeedSpecifier) -> Feed {
|
||||
func newFeed(with opmlFeedSpecifier: OPMLFeedSpecifier) -> Feed {
|
||||
let feedURL = opmlFeedSpecifier.feedURL
|
||||
let metadata = feedMetadata(feedURL: feedURL, feedID: feedURL)
|
||||
let feed = Feed(account: self, url: opmlFeedSpecifier.feedURL, metadata: metadata)
|
||||
|
||||
@@ -12,7 +12,7 @@ import SystemConfiguration
|
||||
import os.log
|
||||
import SyncDatabase
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import Articles
|
||||
import ArticlesDatabase
|
||||
import RSWeb
|
||||
@@ -147,21 +147,14 @@ final class CloudKitAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
|
||||
var opmlDocument: RSOPMLDocument?
|
||||
|
||||
do {
|
||||
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
let opmlDocument = OPMLParser.document(with: parserData)
|
||||
|
||||
guard let loadDocument = opmlDocument else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
guard let opmlItems = loadDocument.children, let rootExternalID = account.externalID else {
|
||||
guard let opmlItems = loadDocument.items, let rootExternalID = account.externalID else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSWeb
|
||||
import RSParser
|
||||
import Parser
|
||||
import CloudKit
|
||||
|
||||
enum CloudKitAccountZoneError: LocalizedError {
|
||||
@@ -55,11 +55,11 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
migrateChangeToken()
|
||||
}
|
||||
|
||||
func importOPML(rootExternalID: String, items: [RSOPMLItem], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
func importOPML(rootExternalID: String, items: [OPMLItem], completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
var records = [CKRecord]()
|
||||
var feedRecords = [String: CKRecord]()
|
||||
|
||||
func processFeed(feedSpecifier: RSOPMLFeedSpecifier, containerExternalID: String) {
|
||||
func processFeed(feedSpecifier: OPMLFeedSpecifier, containerExternalID: String) {
|
||||
if let feedRecord = feedRecords[feedSpecifier.feedURL], var containerExternalIDs = feedRecord[CloudKitFeed.Fields.containerExternalIDs] as? [String] {
|
||||
containerExternalIDs.append(containerExternalID)
|
||||
feedRecord[CloudKitFeed.Fields.containerExternalIDs] = containerExternalIDs
|
||||
@@ -77,7 +77,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
if let title = item.titleFromAttributes {
|
||||
let containerRecord = newContainerCKRecord(name: title)
|
||||
records.append(containerRecord)
|
||||
item.children?.forEach { itemChild in
|
||||
item.items?.forEach { itemChild in
|
||||
if let feedSpecifier = itemChild.feedSpecifier {
|
||||
processFeed(feedSpecifier: feedSpecifier, containerExternalID: containerRecord.externalID)
|
||||
}
|
||||
@@ -344,7 +344,7 @@ final class CloudKitAccountZone: CloudKitZone {
|
||||
|
||||
private extension CloudKitAccountZone {
|
||||
|
||||
func newFeedCKRecord(feedSpecifier: RSOPMLFeedSpecifier, containerExternalID: String) -> CKRecord {
|
||||
func newFeedCKRecord(feedSpecifier: OPMLFeedSpecifier, containerExternalID: String) -> CKRecord {
|
||||
let record = CKRecord(recordType: CloudKitFeed.recordType, recordID: generateRecordID())
|
||||
record[CloudKitFeed.Fields.url] = feedSpecifier.feedURL
|
||||
if let editedName = feedSpecifier.title {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import CloudKit
|
||||
import Articles
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import CloudKit
|
||||
import SyncDatabase
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
public extension Notification.Name {
|
||||
static let FeedSettingDidChange = Notification.Name(rawValue: "FeedSettingDidChangeNotification")
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import RSCore
|
||||
|
||||
@@ -44,7 +44,7 @@ class FeedFinder {
|
||||
return
|
||||
}
|
||||
|
||||
if FeedFinder.isFeed(data, url.absoluteString) {
|
||||
if FeedFinder.isFeed(data) {
|
||||
let feedSpecifier = FeedSpecifier(title: nil, urlString: url.absoluteString, source: .UserEntered, orderFound: 1)
|
||||
completion(.success(Set([feedSpecifier])))
|
||||
return
|
||||
@@ -149,7 +149,7 @@ private extension FeedFinder {
|
||||
group.enter()
|
||||
downloadUsingCache(url) { (data, response, error) in
|
||||
if let data = data, let response = response, response.statusIsOK, error == nil {
|
||||
if self.isFeed(data, downloadFeedSpecifier.urlString) {
|
||||
if self.isFeed(data) {
|
||||
addFeedSpecifier(downloadFeedSpecifier, feedSpecifiers: &resultFeedSpecifiers)
|
||||
}
|
||||
}
|
||||
@@ -163,8 +163,7 @@ private extension FeedFinder {
|
||||
}
|
||||
}
|
||||
|
||||
static func isFeed(_ data: Data, _ urlString: String) -> Bool {
|
||||
let parserData = ParserData(url: urlString, data: data)
|
||||
return FeedParser.canParse(parserData)
|
||||
static func isFeed(_ data: Data) -> Bool {
|
||||
return FeedParser.canParse(data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
private let feedURLWordsToMatch = ["feed", "xml", "rss", "atom", "json"]
|
||||
|
||||
@@ -20,18 +20,20 @@ class HTMLFeedFinder {
|
||||
private var feedSpecifiersDictionary = [String: FeedSpecifier]()
|
||||
|
||||
init(parserData: ParserData) {
|
||||
let metadata = RSHTMLMetadataParser.htmlMetadata(with: parserData)
|
||||
let metadata = HTMLMetadataParser.metadata(with: parserData)
|
||||
var orderFound = 0
|
||||
|
||||
for oneFeedLink in metadata.feedLinks {
|
||||
if let oneURLString = oneFeedLink.urlString?.normalizedURL {
|
||||
orderFound = orderFound + 1
|
||||
let oneFeedSpecifier = FeedSpecifier(title: oneFeedLink.title, urlString: oneURLString, source: .HTMLHead, orderFound: orderFound)
|
||||
addFeedSpecifier(oneFeedSpecifier)
|
||||
|
||||
if let feedLinks = metadata.feedLinks {
|
||||
for oneFeedLink in feedLinks {
|
||||
if let oneURLString = oneFeedLink.urlString?.normalizedURL {
|
||||
orderFound = orderFound + 1
|
||||
let oneFeedSpecifier = FeedSpecifier(title: oneFeedLink.title, urlString: oneURLString, source: .HTMLHead, orderFound: orderFound)
|
||||
addFeedSpecifier(oneFeedSpecifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let bodyLinks = RSHTMLLinkParser.htmlLinks(with: parserData)
|
||||
let bodyLinks = HTMLLinkParser.htmlLinks(with: parserData)
|
||||
for oneBodyLink in bodyLinks {
|
||||
if linkMightBeFeed(oneBodyLink), let normalizedURL = oneBodyLink.urlString?.normalizedURL {
|
||||
orderFound = orderFound + 1
|
||||
@@ -69,7 +71,7 @@ private extension HTMLFeedFinder {
|
||||
return false
|
||||
}
|
||||
|
||||
func linkMightBeFeed(_ link: RSHTMLLink) -> Bool {
|
||||
func linkMightBeFeed(_ link: HTMLLink) -> Bool {
|
||||
if let linkURLString = link.urlString, urlStringMightBeFeed(linkURLString) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSCore
|
||||
|
||||
final class FeedbinEntry: Decodable {
|
||||
@@ -29,7 +29,7 @@ final class FeedbinEntry: Decodable {
|
||||
// and letting the one date fail when parsed.
|
||||
lazy var parsedDatePublished: Date? = {
|
||||
if let datePublished = datePublished {
|
||||
return RSDateWithString(datePublished)
|
||||
return DateParser.date(string: datePublished)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
struct FeedbinSubscription: Hashable, Codable {
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
struct FeedlyEntryParser {
|
||||
let entry: FeedlyEntry
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
/// Get full entries for the entry identifiers.
|
||||
final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import os.log
|
||||
|
||||
protocol FeedlyEntryProviding {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSParser
|
||||
import Parser
|
||||
import SyncDatabase
|
||||
import Secrets
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import os.log
|
||||
|
||||
protocol FeedlyParsedItemsByFeedProviding {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSCore
|
||||
import RSWeb
|
||||
import Secrets
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import os.log
|
||||
|
||||
/// Combine the articles with their feeds for a specific account.
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
|
||||
struct InitialFeedDownloader {
|
||||
@@ -20,9 +20,11 @@ struct InitialFeedDownloader {
|
||||
return
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: url.absoluteString, data: data)
|
||||
FeedParser.parse(parserData) { (parsedFeed, error) in
|
||||
completion(parsedFeed)
|
||||
Task.detached {
|
||||
let parsedFeed = try? FeedParser.parse(urlString: url.absoluteString, data: data)
|
||||
Task { @MainActor in
|
||||
completion(parsedFeed)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import Articles
|
||||
import ArticlesDatabase
|
||||
import RSWeb
|
||||
@@ -96,21 +96,13 @@ final class LocalAccountDelegate: AccountDelegate {
|
||||
}
|
||||
|
||||
let parserData = ParserData(url: opmlFile.absoluteString, data: opmlData)
|
||||
var opmlDocument: RSOPMLDocument?
|
||||
|
||||
do {
|
||||
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
|
||||
} catch {
|
||||
completion(.failure(error))
|
||||
return
|
||||
}
|
||||
|
||||
let opmlDocument = OPMLParser.document(with: parserData)
|
||||
guard let loadDocument = opmlDocument else {
|
||||
completion(.success(()))
|
||||
return
|
||||
}
|
||||
|
||||
guard let children = loadDocument.children else {
|
||||
guard let children = loadDocument.items else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import Articles
|
||||
import ArticlesDatabase
|
||||
|
||||
@@ -7,10 +7,11 @@
|
||||
// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurFolder = NewsBlurFeedsResponse.Folder
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurStory = NewsBlurStoriesResponse.Story
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
typealias NewsBlurStoryHash = NewsBlurStoryHashesResponse.StoryHash
|
||||
|
||||
|
||||
@@ -6,10 +6,11 @@
|
||||
// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
final class OPMLFile {
|
||||
|
||||
@@ -82,18 +82,15 @@ private extension OPMLFile {
|
||||
return fileData
|
||||
}
|
||||
|
||||
func parsedOPMLItems(fileData: Data) -> [RSOPMLItem]? {
|
||||
let parserData = ParserData(url: fileURL.absoluteString, data: fileData)
|
||||
var opmlDocument: RSOPMLDocument?
|
||||
func parsedOPMLItems(fileData: Data) -> [OPMLItem]? {
|
||||
|
||||
do {
|
||||
opmlDocument = try RSOPMLParser.parseOPML(with: parserData)
|
||||
} catch {
|
||||
os_log(.error, log: log, "OPML Import failed: %@.", error.localizedDescription)
|
||||
let parserData = ParserData(url: fileURL.absoluteString, data: fileData)
|
||||
guard let opmlDocument = OPMLParser.document(with: parserData) else {
|
||||
os_log(.error, log: log, "OPML Import failed")
|
||||
return nil
|
||||
}
|
||||
|
||||
return opmlDocument?.children
|
||||
|
||||
return opmlDocument.items
|
||||
}
|
||||
|
||||
func opmlDocument() -> String {
|
||||
|
||||
@@ -7,20 +7,20 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
final class OPMLNormalizer {
|
||||
|
||||
var normalizedOPMLItems = [RSOPMLItem]()
|
||||
var normalizedOPMLItems = [OPMLItem]()
|
||||
|
||||
static func normalize(_ items: [RSOPMLItem]) -> [RSOPMLItem] {
|
||||
static func normalize(_ items: [OPMLItem]) -> [OPMLItem] {
|
||||
let opmlNormalizer = OPMLNormalizer()
|
||||
opmlNormalizer.normalize(items)
|
||||
return opmlNormalizer.normalizedOPMLItems
|
||||
}
|
||||
|
||||
private func normalize(_ items: [RSOPMLItem], parentFolder: RSOPMLItem? = nil) {
|
||||
var feedsToAdd = [RSOPMLItem]()
|
||||
private func normalize(_ items: [OPMLItem], parentFolder: OPMLItem? = nil) {
|
||||
var feedsToAdd = [OPMLItem]()
|
||||
|
||||
items.forEach { (item) in
|
||||
|
||||
@@ -33,14 +33,14 @@ final class OPMLNormalizer {
|
||||
|
||||
guard let _ = 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 {
|
||||
if let itemChildren = item.items {
|
||||
normalize(itemChildren, parentFolder: parentFolder)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
feedsToAdd.append(item)
|
||||
if let itemChildren = item.children {
|
||||
if let itemChildren = item.items {
|
||||
if let parentFolder = parentFolder {
|
||||
normalize(itemChildren, parentFolder: parentFolder)
|
||||
} else {
|
||||
@@ -51,8 +51,8 @@ final class OPMLNormalizer {
|
||||
|
||||
if let parentFolder = parentFolder {
|
||||
for feed in feedsToAdd {
|
||||
if !(parentFolder.children?.contains(where: { $0.feedSpecifier?.feedURL == feed.feedSpecifier?.feedURL}) ?? false) {
|
||||
parentFolder.addChild(feed)
|
||||
if !(parentFolder.items?.contains(where: { $0.feedSpecifier?.feedURL == feed.feedSpecifier?.feedURL}) ?? false) {
|
||||
parentFolder.add(feed)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSWeb
|
||||
import SyncDatabase
|
||||
import os.log
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSCore
|
||||
|
||||
struct ReaderAPIEntryWrapper: Codable {
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
/*
|
||||
|
||||
|
||||
Reference in New Issue
Block a user