mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
161 lines
6.5 KiB
Swift
161 lines
6.5 KiB
Swift
import Foundation
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
|
|
public struct ExternalMusicAlbumArtResourceId: MediaResourceId {
|
|
public let title: String
|
|
public let performer: String
|
|
public let isThumbnail: Bool
|
|
|
|
public var uniqueId: String {
|
|
return "ext-album-art-\(isThumbnail ? "thump" : "full")-\(self.title.replacingOccurrences(of: "/", with: "_"))-\(self.performer.replacingOccurrences(of: "/", with: "_"))"
|
|
}
|
|
|
|
public var hashValue: Int {
|
|
return self.title.hashValue &* 31 &+ self.performer.hashValue
|
|
}
|
|
|
|
public func isEqual(to: MediaResourceId) -> Bool {
|
|
if let to = to as? ExternalMusicAlbumArtResourceId {
|
|
return self.title == to.title && self.performer == to.performer && self.isThumbnail == to.isThumbnail
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ExternalMusicAlbumArtResource: TelegramMediaResource {
|
|
public let title: String
|
|
public let performer: String
|
|
public let isThumbnail: Bool
|
|
|
|
public init(title: String, performer: String, isThumbnail: Bool) {
|
|
self.title = title
|
|
self.performer = performer
|
|
self.isThumbnail = isThumbnail
|
|
}
|
|
|
|
public required init(decoder: PostboxDecoder) {
|
|
self.title = decoder.decodeStringForKey("t", orElse: "")
|
|
self.performer = decoder.decodeStringForKey("p", orElse: "")
|
|
self.isThumbnail = decoder.decodeInt32ForKey("th", orElse: 1) != 0
|
|
}
|
|
|
|
public func encode(_ encoder: PostboxEncoder) {
|
|
encoder.encodeString(self.title, forKey: "t")
|
|
encoder.encodeString(self.performer, forKey: "p")
|
|
encoder.encodeInt32(self.isThumbnail ? 1 : 0, forKey: "th")
|
|
}
|
|
|
|
public var id: MediaResourceId {
|
|
return ExternalMusicAlbumArtResourceId(title: self.title, performer: self.performer, isThumbnail: self.isThumbnail)
|
|
}
|
|
|
|
public func isEqual(to: TelegramMediaResource) -> Bool {
|
|
if let to = to as? ExternalMusicAlbumArtResource {
|
|
return self.title == to.title && self.performer == to.performer && self.isThumbnail == to.isThumbnail
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
private func urlEncodedStringFromString(_ string: String) -> String {
|
|
var nsString: NSString = string as NSString
|
|
if let value = nsString.replacingPercentEscapes(using: String.Encoding.utf8.rawValue) {
|
|
nsString = value as NSString
|
|
}
|
|
|
|
let result = CFURLCreateStringByAddingPercentEscapes(nil, nsString as CFString, nil, "?!@#$^&%*+=,:;'\"`<>()[]{}/\\|~ " as CFString, CFStringConvertNSStringEncodingToEncoding(String.Encoding.utf8.rawValue))!
|
|
return result as String
|
|
}
|
|
|
|
func fetchExternalMusicAlbumArtResource(account: Account, resource: ExternalMusicAlbumArtResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
|
return Signal { subscriber in
|
|
subscriber.putNext(.reset)
|
|
|
|
if resource.performer.isEmpty || resource.performer.lowercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "unknown artist" || resource.title.isEmpty {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return EmptyDisposable
|
|
} else {
|
|
let excludeWords: [String] = [
|
|
" vs. ",
|
|
" vs ",
|
|
" versus ",
|
|
" ft. ",
|
|
" ft ",
|
|
" featuring ",
|
|
" feat. ",
|
|
" feat ",
|
|
" presents ",
|
|
" pres. ",
|
|
" pres ",
|
|
" and ",
|
|
" & ",
|
|
" . "
|
|
]
|
|
|
|
var performer = resource.performer
|
|
|
|
for word in excludeWords {
|
|
performer = performer.replacingOccurrences(of: word, with: " ")
|
|
}
|
|
|
|
let metaUrl = "https://itunes.apple.com/search?term=\(urlEncodedStringFromString("\(performer) \(resource.title)"))&entity=song&limit=4"
|
|
|
|
let fetchDisposable = MetaDisposable()
|
|
|
|
let disposable = fetchHttpResource(url: metaUrl).start(next: { result in
|
|
if case let .dataPart(_, data, _, complete) = result, complete {
|
|
guard let dict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return
|
|
}
|
|
|
|
guard let results = dict["results"] as? [Any] else {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return
|
|
}
|
|
|
|
guard let result = results.first as? [String: Any] else {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return
|
|
}
|
|
|
|
guard var artworkUrl = result["artworkUrl100"] as? String else {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return
|
|
}
|
|
|
|
if !resource.isThumbnail {
|
|
artworkUrl = artworkUrl.replacingOccurrences(of: "100x100", with: "600x600")
|
|
}
|
|
|
|
if artworkUrl.isEmpty {
|
|
subscriber.putNext(.dataPart(resourceOffset: 0, data: Data(), range: 0 ..< 0, complete: true))
|
|
subscriber.putCompletion()
|
|
return
|
|
} else {
|
|
fetchDisposable.set(fetchHttpResource(url: artworkUrl).start(next: { next in
|
|
subscriber.putNext(next)
|
|
}, completed: {
|
|
subscriber.putCompletion()
|
|
}))
|
|
}
|
|
}
|
|
})
|
|
|
|
return ActionDisposable {
|
|
disposable.dispose()
|
|
fetchDisposable.dispose()
|
|
}
|
|
}
|
|
}
|
|
}
|