From 45ecce67705ee3018b2b1a67f5c24c764f75ad63 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 7 Jan 2023 22:14:03 +0400 Subject: [PATCH] Fix music art in lists and system now playing --- .../Sources/ListMessageFileItemNode.swift | 4 + .../ExternalMusicAlbumArtResources.swift | 99 ------------------- .../Sources/SemanticStatusNode.swift | 38 +++---- .../TelegramUI/Sources/MediaManager.swift | 21 +--- 4 files changed, 30 insertions(+), 132 deletions(-) diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index 6663053c28..dccb694f8a 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -1193,6 +1193,10 @@ public final class ListMessageFileItemNode: ListMessageNode { let _ = extensionTextApply() strongSelf.currentIconImage = iconImage + + if let updateIconImageSignal, let iconImage, case .albumArt = iconImage { + strongSelf.iconStatusNode.setBackgroundImage(updateIconImageSignal) + } if let iconImageApply = iconImageApply { if let updateImageSignal = updateIconImageSignal { diff --git a/submodules/MusicAlbumArtResources/Sources/ExternalMusicAlbumArtResources.swift b/submodules/MusicAlbumArtResources/Sources/ExternalMusicAlbumArtResources.swift index c7906f79d1..9949f1a771 100644 --- a/submodules/MusicAlbumArtResources/Sources/ExternalMusicAlbumArtResources.swift +++ b/submodules/MusicAlbumArtResources/Sources/ExternalMusicAlbumArtResources.swift @@ -60,103 +60,4 @@ public class ExternalMusicAlbumArtResource: Equatable { public func fetchExternalMusicAlbumArtResource(engine: TelegramEngine, file: FileMediaReference?, resource: ExternalMusicAlbumArtResource) -> Signal { return engine.resources.fetchAlbumCover(file: file, title: resource.title, performer: resource.performer, isThumbnail: resource.isThumbnail) - - /*return Signal { subscriber in - if resource.performer.isEmpty || resource.performer.lowercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) == "unknown artist" || resource.title.isEmpty { - subscriber.putError(.generic) - 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 title = resource.title.lowercased() - let isMix = title.contains("remix") || title.contains("mixed") - - 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.putError(.generic) - return - } - - guard let results = dict["results"] as? [Any] else { - subscriber.putError(.generic) - return - } - - var matchingResult: Any? - for result in results { - if let result = result as? [String: Any] { - let title = ((result["trackCensoredName"] as? String) ?? (result["trackName"] as? String))?.lowercased() ?? "" - let resultIsMix = title.contains("remix") || title.contains("mixed") - if isMix == resultIsMix { - matchingResult = result - break - } - } - } - - if matchingResult == nil { - matchingResult = results.first - } - - guard let result = matchingResult as? [String: Any] else { - subscriber.putError(.generic) - return - } - - guard var artworkUrl = result["artworkUrl100"] as? String else { - subscriber.putError(.generic) - return - } - - if !resource.isThumbnail { - artworkUrl = artworkUrl.replacingOccurrences(of: "100x100", with: "600x600") - } - - if artworkUrl.isEmpty { - subscriber.putError(.generic) - return - } else { - fetchDisposable.set(engine.resources.httpData(url: artworkUrl).start(next: { next in - let file = EngineTempBox.shared.tempFile(fileName: "image.jpg") - let _ = try? next.write(to: URL(fileURLWithPath: file.path)) - subscriber.putNext(.moveTempFile(file: file)) - }, completed: { - subscriber.putCompletion() - })) - } - } - }) - - return ActionDisposable { - disposable.dispose() - fetchDisposable.dispose() - } - } - }*/ } diff --git a/submodules/SemanticStatusNode/Sources/SemanticStatusNode.swift b/submodules/SemanticStatusNode/Sources/SemanticStatusNode.swift index 9852a8d08c..ca2d5d5a5d 100644 --- a/submodules/SemanticStatusNode/Sources/SemanticStatusNode.swift +++ b/submodules/SemanticStatusNode/Sources/SemanticStatusNode.swift @@ -857,6 +857,25 @@ public final class SemanticStatusNode: ASControlNode { self.setNeedsDisplay() } } + + public func setBackgroundImage(_ image: Signal<(TransformImageArguments) -> DrawingContext?, NoError>) { + let start = CACurrentMediaTime() + self.disposable = combineLatest(queue: Queue.mainQueue(), image, self.hasLayoutPromise.get()).start(next: { [weak self] transform, ready in + guard let strongSelf = self, ready else { + return + } + let context = transform(TransformImageArguments(corners: ImageCorners(radius: strongSelf.bounds.width / 2.0), imageSize: strongSelf.bounds.size, boundingSize: strongSelf.bounds.size, intrinsicInsets: UIEdgeInsets())) + + let previousAppearanceContext = strongSelf.appearanceContext + strongSelf.appearanceContext = strongSelf.appearanceContext.withUpdatedBackgroundImage(context?.generateImage()) + + if CACurrentMediaTime() - start > 0.3 { + strongSelf.transitionContext = SemanticStatusNodeTransitionContext(startTime: CACurrentMediaTime(), duration: 0.18, previousStateContext: nil, previousAppearanceContext: previousAppearanceContext, completion: {}) + strongSelf.updateAnimations() + } + strongSelf.setNeedsDisplay() + }) + } private var animator: ConstantDisplayLinkAnimator? @@ -889,23 +908,8 @@ public final class SemanticStatusNode: ASControlNode { self.isOpaque = false self.displaysAsynchronously = true - if let image = image { - let start = CACurrentMediaTime() - self.disposable = combineLatest(queue: Queue.mainQueue(), image, self.hasLayoutPromise.get()).start(next: { [weak self] transform, ready in - guard let strongSelf = self, ready else { - return - } - let context = transform(TransformImageArguments(corners: ImageCorners(radius: strongSelf.bounds.width / 2.0), imageSize: strongSelf.bounds.size, boundingSize: strongSelf.bounds.size, intrinsicInsets: UIEdgeInsets())) - - let previousAppearanceContext = strongSelf.appearanceContext - strongSelf.appearanceContext = strongSelf.appearanceContext.withUpdatedBackgroundImage(context?.generateImage()) - - if CACurrentMediaTime() - start > 0.3 { - strongSelf.transitionContext = SemanticStatusNodeTransitionContext(startTime: CACurrentMediaTime(), duration: 0.18, previousStateContext: nil, previousAppearanceContext: previousAppearanceContext, completion: {}) - strongSelf.updateAnimations() - } - strongSelf.setNeedsDisplay() - }) + if let image { + self.setBackgroundImage(image) } } diff --git a/submodules/TelegramUI/Sources/MediaManager.swift b/submodules/TelegramUI/Sources/MediaManager.swift index 725e33f801..d9068cfc74 100644 --- a/submodules/TelegramUI/Sources/MediaManager.swift +++ b/submodules/TelegramUI/Sources/MediaManager.swift @@ -2,6 +2,7 @@ import Foundation import SwiftSignalKit import AVFoundation import MobileCoreServices +import Display import Postbox import TelegramCore import MediaPlayer @@ -325,23 +326,11 @@ public final class MediaManagerImpl: NSObject, MediaManager { |> distinctUntilChanged(isEqual: { $0?.0 === $1?.0 && $0?.1 == $1?.1 }) |> mapToSignal { value -> Signal in if let (account, value) = value { - return albumArtThumbnailData(engine: TelegramEngine(account: account), thumbnail: value.fullSizeResource) - |> map { data -> UIImage? in - return data.flatMap(UIImage.init(data:)) + return playerAlbumArt(postbox: account.postbox, engine: TelegramEngine(account: account), fileReference: value.fullSizeResource.file, albumArt: value, thumbnail: false) + |> map { generator -> UIImage? in + let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: CGSize(width: 640, height: 640), boundingSize: CGSize(width: 640, height: 640), intrinsicInsets: .zero) + return generator(arguments)?.generateImage() } - /*return Signal { subscriber in - let fetched = account.postbox.mediaBox.fetchedResource(value.fullSizeResource, parameters: nil).start() - let data = account.postbox.mediaBox.resourceData(value.fullSizeResource, pathExtension: nil, option: .complete(waitUntilFetchStatus: false)).start(next: { data in - if data.complete, let value = try? Data(contentsOf: URL(fileURLWithPath: data.path)) { - subscriber.putNext(UIImage(data: value)) - subscriber.putCompletion() - } - }) - return ActionDisposable { - fetched.dispose() - data.dispose() - } - }*/ } else { return .single(nil) }