2017-11-20 22:16:06 +01:00
|
|
|
|
//
|
|
|
|
|
// FaviconURLFinder.swift
|
|
|
|
|
// Evergreen
|
|
|
|
|
//
|
|
|
|
|
// Created by Brent Simmons on 11/20/17.
|
|
|
|
|
// Copyright © 2017 Ranchero Software. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
import RSParser
|
|
|
|
|
import RSWeb
|
2017-12-14 04:46:03 +01:00
|
|
|
|
import RSCore
|
2017-11-20 22:16:06 +01:00
|
|
|
|
|
|
|
|
|
// The favicon URL may be specified in the head section of the home page.
|
|
|
|
|
|
|
|
|
|
struct FaviconURLFinder {
|
|
|
|
|
|
2017-12-14 04:46:03 +01:00
|
|
|
|
static var metadataCache = [String: RSHTMLMetadata]()
|
|
|
|
|
static let serialDispatchQueue = DispatchQueue(label: "FaviconURLFinder")
|
|
|
|
|
|
2017-11-20 22:16:06 +01:00
|
|
|
|
static func findFaviconURL(_ homePageURL: String, _ callback: @escaping (String?) -> Void) {
|
|
|
|
|
|
|
|
|
|
guard let url = URL(string: homePageURL) else {
|
|
|
|
|
callback(nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-23 19:29:00 +01:00
|
|
|
|
downloadUsingCache(url) { (data, response, error) in
|
2017-11-20 22:16:06 +01:00
|
|
|
|
|
|
|
|
|
guard let data = data, let response = response, response.statusIsOK else {
|
|
|
|
|
callback(nil)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 22:46:48 +01:00
|
|
|
|
// Use the absoluteString of the response’s URL instead of the homePageURL,
|
|
|
|
|
// since the homePageURL might actually have been redirected.
|
|
|
|
|
// Example: Dr. Drang’s feed reports the homePageURL as http://www.leancrew.com/all-this —
|
|
|
|
|
// but it gets redirected to http://www.leancrew.com/all-this/ — which is correct.
|
|
|
|
|
// This way any relative link to a favicon in the page’s metadata
|
|
|
|
|
// will be made absolute correctly.
|
|
|
|
|
|
|
|
|
|
let urlToUse = response.url?.absoluteString ?? homePageURL
|
2017-12-14 04:46:03 +01:00
|
|
|
|
faviconURL(urlToUse, data, callback)
|
2017-11-20 22:16:06 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-14 04:46:03 +01:00
|
|
|
|
static private func faviconURL(_ url: String, _ webPageData: Data, _ callback: @escaping (String?) -> Void) {
|
|
|
|
|
|
|
|
|
|
serialDispatchQueue.async {
|
|
|
|
|
|
|
|
|
|
let md5String = (webPageData as NSData).rs_md5HashString()
|
|
|
|
|
if let md5String = md5String, let cachedMetadata = metadataCache[md5String] {
|
|
|
|
|
let cachedURL = cachedMetadata.faviconLink
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
callback(cachedURL)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-11-20 22:16:06 +01:00
|
|
|
|
|
2017-12-14 04:46:03 +01:00
|
|
|
|
let parserData = ParserData(url: url, data: webPageData)
|
|
|
|
|
let htmlMetadata = RSHTMLMetadataParser.htmlMetadata(with: parserData)
|
|
|
|
|
if let md5String = md5String {
|
|
|
|
|
metadataCache[md5String] = htmlMetadata
|
|
|
|
|
}
|
|
|
|
|
let url = htmlMetadata.faviconLink
|
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
|
callback(url)
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-20 22:16:06 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|