Switch to new Parser.
This commit is contained in:
parent
c3f063ae4a
commit
85d1a8fe7a
|
@ -19,7 +19,7 @@ let package = Package(
|
|||
.package(path: "../SyncDatabase"),
|
||||
.package(path: "../RSCore"),
|
||||
.package(path: "../RSDatabase"),
|
||||
.package(path: "../RSParser"),
|
||||
.package(path: "../Parser"),
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
|
@ -27,7 +27,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
"RSCore",
|
||||
"RSDatabase",
|
||||
"RSParser",
|
||||
"Parser",
|
||||
"RSWeb",
|
||||
"Articles",
|
||||
"ArticlesDatabase",
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
import RSParser
|
||||
import Parser
|
||||
import RSCore
|
||||
|
||||
class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
import RSParser
|
||||
import Parser
|
||||
import Secrets
|
||||
@testable import Account
|
||||
import os.log
|
||||
|
|
|
@ -13,7 +13,7 @@ let package = Package(
|
|||
],
|
||||
dependencies: [
|
||||
.package(path: "../RSDatabase"),
|
||||
.package(path: "../RSParser"),
|
||||
.package(path: "../Parser"),
|
||||
.package(path: "../RSCore"),
|
||||
.package(path: "../Articles"),
|
||||
],
|
||||
|
@ -23,7 +23,7 @@ let package = Package(
|
|||
dependencies: [
|
||||
"RSCore",
|
||||
"RSDatabase",
|
||||
"RSParser",
|
||||
"Parser",
|
||||
"Articles",
|
||||
],
|
||||
swiftSettings: [.unsafeFlags(["-warnings-as-errors"])]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import RSCore
|
||||
import RSDatabase
|
||||
import RSParser
|
||||
import Parser
|
||||
import Articles
|
||||
|
||||
// This file is the entirety of the public API for ArticlesDatabase.framework.
|
||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
|||
import RSCore
|
||||
import RSDatabase
|
||||
import RSDatabaseObjC
|
||||
import RSParser
|
||||
import Parser
|
||||
import Articles
|
||||
|
||||
final class ArticlesTable: DatabaseTable {
|
||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
|||
import RSDatabase
|
||||
import RSDatabaseObjC
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
extension Article {
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import Foundation
|
|||
import Articles
|
||||
import RSDatabase
|
||||
import RSDatabaseObjC
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
// MARK: - DatabaseObject
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import Articles
|
||||
|
||||
extension ParsedItem {
|
||||
|
|
|
@ -11,7 +11,7 @@ import RSCore
|
|||
import RSDatabase
|
||||
import RSDatabaseObjC
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
final class ArticleSearchInfo: Hashable {
|
||||
|
||||
|
@ -34,7 +34,7 @@ final class ArticleSearchInfo: Hashable {
|
|||
}
|
||||
|
||||
lazy var bodyForIndex: String = {
|
||||
let s = preferredText.rsparser_stringByDecodingHTMLEntities()
|
||||
let s = HTMLEntityDecoder.decodedString(preferredText)
|
||||
let sanitizedBody = s.strippingHTML().collapsingWhitespace
|
||||
|
||||
if let authorsNames = authorsNames {
|
||||
|
|
|
@ -12,7 +12,7 @@ import RSCoreResources
|
|||
import RSTree
|
||||
import Articles
|
||||
import Account
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
// Run add-feed sheet.
|
||||
// If it returns with URL and optional name,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
import Account
|
||||
import Articles
|
||||
|
||||
|
@ -95,7 +95,7 @@ class ScriptableFeed: NSObject, UniqueIdScriptingObject, ScriptingObjectContaine
|
|||
let container: Container = folder != nil ? folder! : account
|
||||
|
||||
// We need to download the feed and parse it.
|
||||
// RSParser does the callback for the download on the main thread.
|
||||
// Parser does the callback for the download on the main thread.
|
||||
// Because we can't wait here (on the main thread) for the callback, we have to return from this function.
|
||||
// Generally, returning from an AppleEvent handler function means that handling the Apple event is over,
|
||||
// but we don’t yet have the result of the event yet, so we prevent the Apple event from returning by calling
|
||||
|
|
|
@ -414,7 +414,6 @@
|
|||
84C1ECEB2CDFE49100C7456A /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||
membershipExceptions = (
|
||||
Images/FeaturedImageDownloader.swift,
|
||||
Resources/NewsFax.nnwtheme,
|
||||
Secrets.swift.gyb,
|
||||
ShareExtension/SafariExt.js,
|
||||
|
@ -433,7 +432,6 @@
|
|||
ExtensionPoints/SendToMarsEditCommand.swift,
|
||||
ExtensionPoints/SendToMicroBlogCommand.swift,
|
||||
"Extensions/NSView-Extensions.swift",
|
||||
Images/FeaturedImageDownloader.swift,
|
||||
Secrets.swift.gyb,
|
||||
ShareExtension/SafariExt.js,
|
||||
ShareExtension/ShareDefaultContainer.swift,
|
||||
|
@ -672,8 +670,8 @@
|
|||
51CD32C324D2CD57009ABAEF /* ArticlesDatabase */,
|
||||
51CD32C724D2E06C009ABAEF /* Secrets */,
|
||||
51CD32A824D2CB25009ABAEF /* SyncDatabase */,
|
||||
8417FA3E2CDF2E31005F989B /* RSDatabase */,
|
||||
849E61B82CE85D09008AF514 /* Parser */,
|
||||
8417FA3E2CDF2E31005F989B /* RSDatabase */,
|
||||
847C4C0C2CDF22DD008BF5FE /* RSTree */,
|
||||
8413878C2CDC78EE00E8490F /* RSWeb */,
|
||||
8413876B2CD896E000E8490F /* RSCore */,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// FeedParser.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
@ -50,6 +50,22 @@ public struct FeedParser {
|
|||
}
|
||||
}
|
||||
|
||||
public static func parse(_ parserData: ParserData, _ completion: @Sendable @escaping (ParsedFeed?, Error?) -> Void) {
|
||||
|
||||
Task {
|
||||
do {
|
||||
let parsedFeed = try await parseAsync(urlString: parserData.url, data: parserData.data)
|
||||
Task { @MainActor in
|
||||
completion(parsedFeed, nil)
|
||||
}
|
||||
} catch {
|
||||
Task { @MainActor in
|
||||
completion(nil, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func parseAsync(urlString: String, data: Data) async throws -> ParsedFeed? {
|
||||
|
||||
try parse(urlString: urlString, data: data)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// FeedParserError.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/24/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// FeedType.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// JSONFeedParser.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// RSSInJSONParser.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/24/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ParsedAttachment.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ParsedAuthor.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ParsedFeed.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ParsedHub.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ParsedItem.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/20/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AtomParser.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// RSSFeedTransformer.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// RSSParser.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// JSONDictionary.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/24/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// JSONUtilities.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 12/10/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// String+RSParser.swift
|
||||
// RSParser
|
||||
// String+Parser.swift
|
||||
// Parser
|
||||
//
|
||||
// Created by Nate Weaver on 2020-01-19.
|
||||
// Copyright © 2020 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// AtomParserTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/26/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// EntityDecodingTests.swift
|
||||
// RSParserTests
|
||||
// ParserTests
|
||||
//
|
||||
// Created by Brent Simmons on 12/30/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// FeedParserTypeTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// HTMLLinkTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// HTMLMetadataTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// JSONFeedParserTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/26/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// OPMLTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/25/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// RSSInJSONParserTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/26/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// RSSParserTests.swift
|
||||
// RSParser
|
||||
// Parser
|
||||
//
|
||||
// Created by Brent Simmons on 6/26/17.
|
||||
// Copyright © 2017 Ranchero Software, LLC. All rights reserved.
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Parser"
|
||||
BuildableName = "Parser"
|
||||
BlueprintName = "Parser"
|
||||
BlueprintIdentifier = "RSDatabase"
|
||||
BuildableName = "RSDatabase"
|
||||
BlueprintName = "RSDatabase"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
|
@ -50,9 +50,9 @@
|
|||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "Parser"
|
||||
BuildableName = "Parser"
|
||||
BlueprintName = "Parser"
|
||||
BlueprintIdentifier = "RSDatabase"
|
||||
BuildableName = "RSDatabase"
|
||||
BlueprintName = "RSDatabase"
|
||||
ReferencedContainer = "container:">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import Articles
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
struct ArticleStringFormatter {
|
||||
|
||||
|
@ -66,7 +66,7 @@ struct ArticleStringFormatter {
|
|||
s = s.replacingOccurrences(of: "\t", with: "")
|
||||
|
||||
if !forHTML {
|
||||
s = s.rsparser_stringByDecodingHTMLEntities()
|
||||
s = HTMLEntityDecoder.decodedString(s)
|
||||
}
|
||||
|
||||
s = s.trimmingWhitespace
|
||||
|
@ -98,7 +98,7 @@ struct ArticleStringFormatter {
|
|||
if let cachedBody = summaryCache[key] {
|
||||
return cachedBody
|
||||
}
|
||||
var s = body.rsparser_stringByDecodingHTMLEntities()
|
||||
var s = HTMLEntityDecoder.decodedString(body)
|
||||
s = s.strippingHTML(maxCharacters: 250)
|
||||
s = s.trimmingWhitespace
|
||||
s = s.collapsingWhitespace
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
#if canImport(AppKit)
|
||||
import AppKit
|
||||
|
@ -310,6 +310,6 @@ private struct CountedSet<Element> where Element: Hashable {
|
|||
private extension String {
|
||||
var decodedEntity: String {
|
||||
// It's possible the implementation will change, but for now it just calls this.
|
||||
(self as NSString).rsparser_stringByDecodingHTMLEntities() as String
|
||||
HTMLEntityDecoder.decodedString(self)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import Foundation
|
||||
import CoreServices
|
||||
import RSParser
|
||||
import Parser
|
||||
import UniformTypeIdentifiers
|
||||
|
||||
// The favicon URLs may be specified in the head section of the home page.
|
||||
|
@ -20,7 +20,7 @@ struct FaviconURLFinder {
|
|||
/// - homePageURL: The page to search.
|
||||
/// - completion: A closure called when the links have been found.
|
||||
/// - urls: An array of favicon URLs as strings.
|
||||
static func findFaviconURLs(with homePageURL: String, _ completion: @escaping (_ urls: [String]?) -> Void) {
|
||||
static func findFaviconURLs(with homePageURL: String, _ completion: @escaping ([String]?) -> Void) {
|
||||
|
||||
guard let _ = URL(string: homePageURL) else {
|
||||
completion(nil)
|
||||
|
@ -29,7 +29,13 @@ struct FaviconURLFinder {
|
|||
|
||||
// If the favicon has an explicit type, check that for an ignored type; otherwise, check the file extension.
|
||||
HTMLMetadataDownloader.downloadMetadata(for: homePageURL) { (htmlMetadata) in
|
||||
let faviconURLs = htmlMetadata?.favicons.compactMap {
|
||||
|
||||
guard let favicons = htmlMetadata?.favicons else {
|
||||
completion(nil)
|
||||
return
|
||||
}
|
||||
|
||||
let faviconURLs = favicons.compactMap {
|
||||
shouldAllowFavicon($0) ? $0.urlString : nil
|
||||
}
|
||||
|
||||
|
@ -39,7 +45,7 @@ struct FaviconURLFinder {
|
|||
|
||||
private static let ignoredTypes = [UTType.svg]
|
||||
|
||||
private static func shouldAllowFavicon(_ favicon: RSHTMLMetadataFavicon) -> Bool {
|
||||
private static func shouldAllowFavicon(_ favicon: HTMLMetadataFavicon) -> Bool {
|
||||
|
||||
// Check mime type.
|
||||
if let mimeType = favicon.type, let utType = UTType(mimeType: mimeType) {
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
import Foundation
|
||||
import RSWeb
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
struct HTMLMetadataDownloader {
|
||||
|
||||
static let serialDispatchQueue = DispatchQueue(label: "HTMLMetadataDownloader")
|
||||
|
||||
static func downloadMetadata(for url: String, _ completion: @escaping (RSHTMLMetadata?) -> Void) {
|
||||
static func downloadMetadata(for url: String, _ completion: @escaping (HTMLMetadata?) -> Void) {
|
||||
guard let actualURL = URL(string: url) else {
|
||||
completion(nil)
|
||||
return
|
||||
|
@ -32,9 +32,9 @@ struct HTMLMetadataDownloader {
|
|||
}
|
||||
}
|
||||
|
||||
private static func parseMetadata(with parserData: ParserData, _ completion: @escaping (RSHTMLMetadata?) -> Void) {
|
||||
private static func parseMetadata(with parserData: ParserData, _ completion: @escaping (HTMLMetadata?) -> Void) {
|
||||
serialDispatchQueue.async {
|
||||
let htmlMetadata = RSHTMLMetadataParser.htmlMetadata(with: parserData)
|
||||
let htmlMetadata = HTMLMetadataParser.metadata(with: parserData)
|
||||
DispatchQueue.main.async {
|
||||
completion(htmlMetadata)
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import Articles
|
|||
import Account
|
||||
import RSCore
|
||||
import RSWeb
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
extension Notification.Name {
|
||||
|
||||
|
@ -214,7 +214,7 @@ private extension FeedIconDownloader {
|
|||
}
|
||||
}
|
||||
|
||||
func pullIconURL(from metadata: RSHTMLMetadata, homePageURL: String, feed: Feed) {
|
||||
func pullIconURL(from metadata: HTMLMetadata, homePageURL: String, feed: Feed) {
|
||||
|
||||
if let url = metadata.bestWebsiteIconURL() {
|
||||
cacheIconURL(for: homePageURL, url)
|
||||
|
|
|
@ -7,65 +7,32 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
extension RSHTMLMetadata {
|
||||
|
||||
func largestOpenGraphImageURL() -> String? {
|
||||
let openGraphImages = openGraphProperties.images
|
||||
|
||||
guard !openGraphImages.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var bestImage: RSHTMLOpenGraphImage? = nil
|
||||
|
||||
for image in openGraphImages {
|
||||
if image.width / image.height > 2 {
|
||||
continue
|
||||
}
|
||||
if bestImage == nil {
|
||||
bestImage = image
|
||||
continue
|
||||
}
|
||||
if image.height > bestImage!.height && image.width > bestImage!.width {
|
||||
bestImage = image
|
||||
}
|
||||
}
|
||||
|
||||
guard let url = bestImage?.secureURL ?? bestImage?.url else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bad ones we should ignore.
|
||||
let badURLs = Set(["https://s0.wp.com/i/blank.jpg"])
|
||||
guard !badURLs.contains(url) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
extension HTMLMetadata {
|
||||
|
||||
func largestAppleTouchIcon() -> String? {
|
||||
|
||||
let icons = appleTouchIcons
|
||||
|
||||
guard !icons.isEmpty else {
|
||||
guard let icons = appleTouchIcons, !icons.isEmpty else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var bestImage: RSHTMLMetadataAppleTouchIcon? = nil
|
||||
var bestImage: HTMLMetadataAppleTouchIcon? = nil
|
||||
|
||||
for image in icons {
|
||||
if image.size.width / image.size.height > 2 {
|
||||
continue
|
||||
if let size = image.size {
|
||||
if size.width / size.height > 2 {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if bestImage == nil {
|
||||
bestImage = image
|
||||
continue
|
||||
}
|
||||
if image.size.height > bestImage!.size.height && image.size.width > bestImage!.size.width {
|
||||
bestImage = image;
|
||||
if let size = image.size, let bestImageSize = bestImage!.size {
|
||||
if size.height > bestImageSize.height && size.width > bestImageSize.width {
|
||||
bestImage = image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,19 +47,10 @@ extension RSHTMLMetadata {
|
|||
return appleTouchIcon
|
||||
}
|
||||
|
||||
if let openGraphImageURL = largestOpenGraphImageURL() {
|
||||
if let openGraphImageURL = openGraphProperties?.image?.url {
|
||||
return openGraphImageURL
|
||||
}
|
||||
|
||||
return twitterProperties.imageURL
|
||||
}
|
||||
|
||||
func bestFeaturedImageURL() -> String? {
|
||||
|
||||
if let openGraphImageURL = largestOpenGraphImageURL() {
|
||||
return openGraphImageURL
|
||||
}
|
||||
|
||||
return twitterProperties.imageURL
|
||||
return twitterProperties?.imageURL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import Foundation
|
||||
import os.log
|
||||
import RSCore
|
||||
import RSParser
|
||||
import Parser
|
||||
import Account
|
||||
|
||||
final class ExtensionContainersFile {
|
||||
|
|
|
@ -10,7 +10,7 @@ import UIKit
|
|||
import Account
|
||||
import RSCore
|
||||
import RSTree
|
||||
import RSParser
|
||||
import Parser
|
||||
|
||||
enum AddFeedType {
|
||||
case web
|
||||
|
|
Loading…
Reference in New Issue