Merge pull request #1359 from Wevah/favicon-fix
Fix favicons not loading for certain feeds
This commit is contained in:
commit
18045f2e2b
|
@ -21,6 +21,8 @@ final class FaviconDownloader {
|
||||||
private let folder: String
|
private let folder: String
|
||||||
private let diskCache: BinaryDiskCache
|
private let diskCache: BinaryDiskCache
|
||||||
private var singleFaviconDownloaderCache = [String: SingleFaviconDownloader]() // faviconURL: SingleFaviconDownloader
|
private var singleFaviconDownloaderCache = [String: SingleFaviconDownloader]() // faviconURL: SingleFaviconDownloader
|
||||||
|
private var remainingFaviconURLs = [String: ArraySlice<String>]() // homePageURL: array of faviconURLs that haven't been checked yet
|
||||||
|
|
||||||
private var homePageToFaviconURLCache = [String: String]() //homePageURL: faviconURL
|
private var homePageToFaviconURLCache = [String: String]() //homePageURL: faviconURL
|
||||||
private var homePageURLsWithNoFaviconURL = Set<String>()
|
private var homePageURLsWithNoFaviconURL = Set<String>()
|
||||||
private let queue: DispatchQueue
|
private let queue: DispatchQueue
|
||||||
|
@ -49,11 +51,11 @@ final class FaviconDownloader {
|
||||||
|
|
||||||
assert(Thread.isMainThread)
|
assert(Thread.isMainThread)
|
||||||
|
|
||||||
|
var homePageURL = feed.homePageURL
|
||||||
if let faviconURL = feed.faviconURL {
|
if let faviconURL = feed.faviconURL {
|
||||||
return favicon(with: faviconURL)
|
return favicon(with: faviconURL, homePageURL: homePageURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
var homePageURL = feed.homePageURL
|
|
||||||
if homePageURL == nil {
|
if homePageURL == nil {
|
||||||
// Base homePageURL off feedURL if needed. Won’t always be accurate, but is good enough.
|
// Base homePageURL off feedURL if needed. Won’t always be accurate, but is good enough.
|
||||||
if let feedURL = URL(string: feed.url), let scheme = feedURL.scheme, let host = feedURL.host {
|
if let feedURL = URL(string: feed.url), let scheme = feedURL.scheme, let host = feedURL.host {
|
||||||
|
@ -83,9 +85,9 @@ final class FaviconDownloader {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func favicon(with faviconURL: String) -> RSImage? {
|
func favicon(with faviconURL: String, homePageURL: String?) -> RSImage? {
|
||||||
|
|
||||||
let downloader = faviconDownloader(withURL: faviconURL)
|
let downloader = faviconDownloader(withURL: faviconURL, homePageURL: homePageURL)
|
||||||
return downloader.image
|
return downloader.image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,17 +97,23 @@ final class FaviconDownloader {
|
||||||
if homePageURLsWithNoFaviconURL.contains(url) {
|
if homePageURLsWithNoFaviconURL.contains(url) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if let faviconURL = homePageToFaviconURLCache[url] {
|
if let faviconURL = homePageToFaviconURLCache[url] {
|
||||||
return favicon(with: faviconURL)
|
return favicon(with: faviconURL, homePageURL: url)
|
||||||
}
|
}
|
||||||
|
|
||||||
findFaviconURL(with: url) { (faviconURL) in
|
findFaviconURLs(with: url) { (faviconURLs) in
|
||||||
if let faviconURL = faviconURL {
|
var hasIcons = false
|
||||||
self.homePageToFaviconURLCache[url] = faviconURL
|
|
||||||
let _ = self.favicon(with: faviconURL)
|
if let faviconURLs = faviconURLs {
|
||||||
|
if let firstIconURL = faviconURLs.first {
|
||||||
|
hasIcons = true
|
||||||
|
let _ = self.favicon(with: firstIconURL, homePageURL: url)
|
||||||
|
self.remainingFaviconURLs[url] = faviconURLs.dropFirst()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if (!hasIcons) {
|
||||||
self.homePageURLsWithNoFaviconURL.insert(url)
|
self.homePageURLsWithNoFaviconURL.insert(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,9 +128,28 @@ final class FaviconDownloader {
|
||||||
guard let singleFaviconDownloader = note.object as? SingleFaviconDownloader else {
|
guard let singleFaviconDownloader = note.object as? SingleFaviconDownloader else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let _ = singleFaviconDownloader.image else {
|
guard let homePageURL = singleFaviconDownloader.homePageURL else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
guard let _ = singleFaviconDownloader.image else {
|
||||||
|
if let faviconURLs = remainingFaviconURLs[homePageURL] {
|
||||||
|
if let nextIconURL = faviconURLs.first {
|
||||||
|
let _ = favicon(with: nextIconURL, homePageURL: singleFaviconDownloader.homePageURL)
|
||||||
|
remainingFaviconURLs[homePageURL] = faviconURLs.dropFirst();
|
||||||
|
} else {
|
||||||
|
remainingFaviconURLs[homePageURL] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
remainingFaviconURLs[homePageURL] = nil
|
||||||
|
|
||||||
|
if let url = singleFaviconDownloader.homePageURL {
|
||||||
|
if self.homePageToFaviconURLCache[url] == nil {
|
||||||
|
self.homePageToFaviconURLCache[url] = singleFaviconDownloader.faviconURL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
postFaviconDidBecomeAvailableNotification(singleFaviconDownloader.faviconURL)
|
postFaviconDidBecomeAvailableNotification(singleFaviconDownloader.faviconURL)
|
||||||
}
|
}
|
||||||
|
@ -132,38 +159,40 @@ private extension FaviconDownloader {
|
||||||
|
|
||||||
static let localeForLowercasing = Locale(identifier: "en_US")
|
static let localeForLowercasing = Locale(identifier: "en_US")
|
||||||
|
|
||||||
func findFaviconURL(with homePageURL: String, _ completion: @escaping (String?) -> Void) {
|
func findFaviconURLs(with homePageURL: String, _ completion: @escaping ([String]?) -> Void) {
|
||||||
|
|
||||||
guard let url = URL(string: homePageURL) else {
|
guard let url = URL(string: homePageURL) else {
|
||||||
completion(nil)
|
completion(nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FaviconURLFinder.findFaviconURL(homePageURL) { (faviconURL) in
|
FaviconURLFinder.findFaviconURLs(homePageURL) { (faviconURLs) in
|
||||||
|
var defaultFaviconURL: String? = nil
|
||||||
|
|
||||||
if let faviconURL = faviconURL {
|
if let scheme = url.scheme, let host = url.host {
|
||||||
completion(faviconURL)
|
defaultFaviconURL = "\(scheme)://\(host)/favicon.ico".lowercased(with: FaviconDownloader.localeForLowercasing)
|
||||||
|
}
|
||||||
|
|
||||||
|
if var faviconURLs = faviconURLs {
|
||||||
|
if let defaultFaviconURL = defaultFaviconURL {
|
||||||
|
faviconURLs.append(defaultFaviconURL)
|
||||||
|
}
|
||||||
|
completion(faviconURLs)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let scheme = url.scheme, let host = url.host else {
|
completion(defaultFaviconURL != nil ? [defaultFaviconURL!] : nil)
|
||||||
completion(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let defaultFaviconURL = "\(scheme)://\(host)/favicon.ico".lowercased(with: FaviconDownloader.localeForLowercasing)
|
|
||||||
completion(defaultFaviconURL)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func faviconDownloader(withURL faviconURL: String) -> SingleFaviconDownloader {
|
func faviconDownloader(withURL faviconURL: String, homePageURL: String?) -> SingleFaviconDownloader {
|
||||||
|
|
||||||
if let downloader = singleFaviconDownloaderCache[faviconURL] {
|
if let downloader = singleFaviconDownloaderCache[faviconURL] {
|
||||||
downloader.downloadFaviconIfNeeded()
|
downloader.downloadFaviconIfNeeded()
|
||||||
return downloader
|
return downloader
|
||||||
}
|
}
|
||||||
|
|
||||||
let downloader = SingleFaviconDownloader(faviconURL: faviconURL, diskCache: diskCache, queue: queue)
|
let downloader = SingleFaviconDownloader(faviconURL: faviconURL, homePageURL: homePageURL, diskCache: diskCache, queue: queue)
|
||||||
singleFaviconDownloaderCache[faviconURL] = downloader
|
singleFaviconDownloaderCache[faviconURL] = downloader
|
||||||
return downloader
|
return downloader
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import RSParser
|
import RSParser
|
||||||
|
|
||||||
// The favicon URL may be specified in the head section of the home page.
|
// The favicon URLs may be specified in the head section of the home page.
|
||||||
|
|
||||||
struct FaviconURLFinder {
|
struct FaviconURLFinder {
|
||||||
|
|
||||||
static func findFaviconURL(_ homePageURL: String, _ callback: @escaping (String?) -> Void) {
|
static func findFaviconURLs(_ homePageURL: String, _ callback: @escaping ([String]?) -> Void) {
|
||||||
|
|
||||||
guard let _ = URL(string: homePageURL) else {
|
guard let _ = URL(string: homePageURL) else {
|
||||||
callback(nil)
|
callback(nil)
|
||||||
|
@ -21,7 +21,7 @@ struct FaviconURLFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
HTMLMetadataDownloader.downloadMetadata(for: homePageURL) { (htmlMetadata) in
|
HTMLMetadataDownloader.downloadMetadata(for: homePageURL) { (htmlMetadata) in
|
||||||
callback(htmlMetadata?.faviconLink)
|
callback(htmlMetadata?.faviconLinks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ final class SingleFaviconDownloader {
|
||||||
|
|
||||||
let faviconURL: String
|
let faviconURL: String
|
||||||
var image: RSImage?
|
var image: RSImage?
|
||||||
|
let homePageURL: String?
|
||||||
|
|
||||||
private var lastDownloadAttemptDate: Date
|
private var lastDownloadAttemptDate: Date
|
||||||
private var diskStatus = DiskStatus.unknown
|
private var diskStatus = DiskStatus.unknown
|
||||||
|
@ -36,9 +37,10 @@ final class SingleFaviconDownloader {
|
||||||
return (faviconURL as NSString).rs_md5Hash()
|
return (faviconURL as NSString).rs_md5Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(faviconURL: String, diskCache: BinaryDiskCache, queue: DispatchQueue) {
|
init(faviconURL: String, homePageURL: String?, diskCache: BinaryDiskCache, queue: DispatchQueue) {
|
||||||
|
|
||||||
self.faviconURL = faviconURL
|
self.faviconURL = faviconURL
|
||||||
|
self.homePageURL = homePageURL
|
||||||
self.diskCache = diskCache
|
self.diskCache = diskCache
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.lastDownloadAttemptDate = Date()
|
self.lastDownloadAttemptDate = Date()
|
||||||
|
@ -83,8 +85,9 @@ private extension SingleFaviconDownloader {
|
||||||
|
|
||||||
if let image = image {
|
if let image = image {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.postDidLoadFaviconNotification()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.postDidLoadFaviconNotification()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit f01129d762eba20cd11a680bbde651ca75639ef3
|
Subproject commit 81c400a7665309a08414bf43ca5161d90d072501
|
Loading…
Reference in New Issue