diff --git a/Sources/Response.swift b/Sources/Response.swift index d20f657..97156bb 100644 --- a/Sources/Response.swift +++ b/Sources/Response.swift @@ -20,7 +20,8 @@ public struct Response { public internal(set) var icon: String? public internal(set) var video: String? public internal(set) var price: String? - + public internal(set) var metaData: [String: String]? + public init() { } } diff --git a/Sources/SwiftLinkPreview.swift b/Sources/SwiftLinkPreview.swift index 58b4d86..ade1cb4 100644 --- a/Sources/SwiftLinkPreview.swift +++ b/Sources/SwiftLinkPreview.swift @@ -137,7 +137,8 @@ open class SwiftLinkPreview: NSObject { result.icon = $0.icon result.video = $0.video result.price = $0.price - + result.metaData = $0.metaData + self.cache.slp_setCachedResponse(url: unshortened.absoluteString, response: result) self.cache.slp_setCachedResponse(url: url.absoluteString, response: result) @@ -605,7 +606,7 @@ extension SwiftLinkPreview { result.description = value.decoded.extendedTrim } } - + result.metaData = self.parse(metadataFrom: htmlCode as String) return (htmlCode, result) } @@ -806,4 +807,38 @@ extension SwiftLinkPreview: URLSessionDataDelegate { completionHandler(request) } + private func parse(metadataFrom htmlString: String) -> [String: String] { + // Regex to extract meta tag regex. + let metatagRegex = try! NSRegularExpression(pattern: "", options: [.dotMatchesLineSeparators]) + let metaTagMatches = metatagRegex.matches(in: htmlString, options: [], range: NSRange(location: 0, length: htmlString.utf16.count)) + if metaTagMatches.isEmpty { return [:] } + // Regex to extract og property, content and theme colors. + let propertyRegex = try! NSRegularExpression(pattern: "\\sproperty=(?:\"|\')og:([a-zA_Z:]+?)(?:\"|\')", options: []) + let contentRegex = try! NSRegularExpression(pattern: "\\scontent=(?:\"|\')(.*?)(?:\"|\')", options: []) + let nsString = htmlString as NSString + // Create [ogProperty: content] dictionary. + return metaTagMatches.reduce([String: String]()) { attributes, result -> [String: String] in + var attributes = attributes + let property = { () -> (name: String, content: String)? in + let metaTag = nsString.substring(with: result.range(at: 0)) + let range = NSRange(location: 0, length: metaTag.utf16.count) + guard let contentMatch = contentRegex.matches(in: metaTag, options: [], range: range).first else { + return nil + } + let nsMetaTag = metaTag as NSString + let content = nsMetaTag.substring(with: contentMatch.range(at: 1)) + // Gets property="og:*" || property='og:*' value. + if let propertyMatch = propertyRegex.matches(in: metaTag, options: [], range: range).first { + let property = nsMetaTag.substring(with: propertyMatch.range(at: 1)) + return (name: property, content: content) + } + return nil + }() + if let property = property { + attributes[property.name] = property.content + } + return attributes + } + } + }