2020-05-13 01:46:08 +00:00
|
|
|
//
|
2024-03-19 18:58:51 +00:00
|
|
|
// GifvController.swift
|
2020-05-13 01:46:08 +00:00
|
|
|
// Tusker
|
|
|
|
//
|
2024-03-19 18:58:51 +00:00
|
|
|
// Created by Shadowfacts on 3/18/24.
|
|
|
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
2020-05-13 01:46:08 +00:00
|
|
|
//
|
|
|
|
|
2024-03-19 18:58:51 +00:00
|
|
|
import Foundation
|
|
|
|
import AVKit
|
|
|
|
import Combine
|
2020-05-13 01:46:08 +00:00
|
|
|
|
2024-03-19 18:58:51 +00:00
|
|
|
@MainActor
|
|
|
|
class GifvController {
|
|
|
|
private let asset: AVAsset
|
2020-11-01 18:59:58 +00:00
|
|
|
private(set) var item: AVPlayerItem
|
2020-06-18 03:33:48 +00:00
|
|
|
let player: AVPlayer
|
2024-03-19 18:58:51 +00:00
|
|
|
|
2020-11-01 18:59:58 +00:00
|
|
|
private var isGrayscale = false
|
2020-05-13 01:46:08 +00:00
|
|
|
|
2024-03-19 18:58:51 +00:00
|
|
|
let presentationSizeSubject = PassthroughSubject<CGSize, Never>()
|
|
|
|
private var presentationSizeObservation: NSKeyValueObservation?
|
|
|
|
|
|
|
|
init(asset: AVAsset) {
|
2020-11-01 18:59:58 +00:00
|
|
|
self.asset = asset
|
2024-03-20 15:54:47 +00:00
|
|
|
self.item = GifvController.createItem(asset: asset)
|
2024-03-19 18:58:51 +00:00
|
|
|
self.player = AVPlayer(playerItem: item)
|
|
|
|
|
|
|
|
self.isGrayscale = Preferences.shared.grayscaleImages
|
2020-05-13 01:46:08 +00:00
|
|
|
|
2020-06-21 19:38:51 +00:00
|
|
|
player.isMuted = true
|
2024-04-15 13:49:42 +00:00
|
|
|
#if !os(visionOS)
|
2024-04-01 03:20:55 +00:00
|
|
|
player.preventsDisplaySleepDuringVideoPlayback = false
|
2024-04-15 13:49:42 +00:00
|
|
|
#endif
|
2024-03-19 18:58:51 +00:00
|
|
|
|
2020-05-13 01:46:08 +00:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(restartItem), name: .AVPlayerItemDidPlayToEndTime, object: item)
|
2020-11-01 18:59:58 +00:00
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(preferencesChanged), name: .preferencesChanged, object: nil)
|
2024-03-19 18:58:51 +00:00
|
|
|
|
|
|
|
updatePresentationSizeObservation()
|
|
|
|
}
|
|
|
|
|
|
|
|
func play() {
|
|
|
|
if player.rate == 0 {
|
|
|
|
player.play()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func pause() {
|
|
|
|
player.pause()
|
|
|
|
}
|
|
|
|
|
|
|
|
private func updatePresentationSizeObservation() {
|
|
|
|
presentationSizeObservation = item.observe(\.presentationSize, changeHandler: { [unowned self] item, _ in
|
|
|
|
self.presentationSizeSubject.send(item.presentationSize)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
@objc private func restartItem() {
|
|
|
|
item.seek(to: .zero) { (success) in
|
|
|
|
guard success else { return }
|
|
|
|
self.player.play()
|
|
|
|
}
|
2020-05-13 01:46:08 +00:00
|
|
|
}
|
|
|
|
|
2024-03-19 18:58:51 +00:00
|
|
|
@objc private func preferencesChanged() {
|
|
|
|
if isGrayscale != Preferences.shared.grayscaleImages {
|
|
|
|
isGrayscale = Preferences.shared.grayscaleImages
|
2024-04-01 00:51:28 +00:00
|
|
|
let oldItem = item
|
2024-03-19 18:58:51 +00:00
|
|
|
item = GifvController.createItem(asset: asset)
|
|
|
|
player.replaceCurrentItem(with: item)
|
|
|
|
self.updatePresentationSizeObservation()
|
|
|
|
player.play()
|
2024-04-01 00:51:28 +00:00
|
|
|
|
|
|
|
NotificationCenter.default.removeObserver(self, name: AVPlayerItem.didPlayToEndTimeNotification, object: oldItem)
|
|
|
|
NotificationCenter.default.addObserver(self, selector: #selector(restartItem), name: AVPlayerItem.didPlayToEndTimeNotification, object: item)
|
2024-03-19 18:58:51 +00:00
|
|
|
}
|
2020-05-13 01:46:08 +00:00
|
|
|
}
|
|
|
|
|
2020-11-01 18:59:58 +00:00
|
|
|
private static func createItem(asset: AVAsset) -> AVPlayerItem {
|
|
|
|
let item = AVPlayerItem(asset: asset)
|
|
|
|
if Preferences.shared.grayscaleImages {
|
2023-10-20 02:50:20 +00:00
|
|
|
#if os(visionOS)
|
|
|
|
#warning("Use async AVVideoComposition CIFilter initializer")
|
|
|
|
#else
|
2024-04-01 00:51:51 +00:00
|
|
|
let filter = CIFilter(name: "CIColorMonochrome")!
|
|
|
|
filter.setValue(CIColor(red: 0.85, green: 0.85, blue: 0.85), forKey: "inputColor")
|
|
|
|
filter.setValue(1.0, forKey: "inputIntensity")
|
|
|
|
|
2020-11-01 18:59:58 +00:00
|
|
|
item.videoComposition = AVVideoComposition(asset: asset, applyingCIFiltersWithHandler: { (request) in
|
|
|
|
filter.setValue(request.sourceImage, forKey: "inputImage")
|
|
|
|
request.finish(with: filter.outputImage!, context: nil)
|
|
|
|
})
|
2023-10-20 02:50:20 +00:00
|
|
|
#endif
|
2020-11-01 18:59:58 +00:00
|
|
|
}
|
|
|
|
return item
|
|
|
|
}
|
2020-05-13 01:46:08 +00:00
|
|
|
|
|
|
|
}
|