Added realm

This commit is contained in:
Rasmus Krämer 2022-04-11 16:29:19 +02:00
parent 2f4b3050fd
commit c0ac3b7bb5
No known key found for this signature in database
GPG key ID: EC9E510611BFDAA2
14 changed files with 19001 additions and 377 deletions

View file

@ -0,0 +1,264 @@
//
// AudioPlayer.swift
// App
//
// Created by Rasmus Krämer on 07.03.22.
//
import Foundation
import AVFoundation
import UIKit
import MediaPlayer
class AudioPlayer: NSObject {
// enums and @objc are not compatible
@objc dynamic var status: Int
@objc dynamic var rate: Float
private var tmpRate: Float = 1.0
private var lastPlayTime: Double = 0.0
private var playerContext = 0
private var playerItemContext = 0
private var playWhenReady: Bool
private var audioPlayer: AVPlayer
public var audiobook: Audiobook
// MARK: - Constructor
init(audiobook: Audiobook, playWhenReady: Bool = false) {
self.playWhenReady = playWhenReady
self.audiobook = audiobook
self.audioPlayer = AVPlayer()
self.status = -1
self.rate = 0.0
super.init()
initAudioSession()
setupRemoteTransportControls()
NowPlayingInfo.setAudiobook(audiobook: audiobook)
// Listen to player events
self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.rate), options: .new, context: &playerContext)
self.audioPlayer.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem), options: .new, context: &playerContext)
let playerItem = AVPlayerItem(asset: createAsset())
playerItem.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: .new, context: &playerItemContext)
self.audioPlayer.replaceCurrentItem(with: playerItem)
seek(self.audiobook.startTime)
NSLog("Audioplayer ready")
}
deinit {
destroy()
}
public func destroy() {
pause()
audioPlayer.replaceCurrentItem(with: nil)
do {
try AVAudioSession.sharedInstance().setActive(false)
} catch {
NSLog("Failed to set AVAudioSession inactive")
print(error)
}
DispatchQueue.main.sync {
UIApplication.shared.endReceivingRemoteControlEvents()
}
}
// MARK: - Methods
public func play(allowSeekBack: Bool = false) {
if allowSeekBack {
let diffrence = Date.timeIntervalSinceReferenceDate - lastPlayTime
var time: Int?
if lastPlayTime == 0 {
time = 5
} else if diffrence < 6 {
time = 2
} else if diffrence < 12 {
time = 10
} else if diffrence < 30 {
time = 15
} else if diffrence < 180 {
time = 20
} else if diffrence < 3600 {
time = 25
} else {
time = 29
}
if time != nil {
seek(getCurrentTime() - Double(time!))
}
}
lastPlayTime = Date.timeIntervalSinceReferenceDate
self.audioPlayer.play()
self.status = 1
self.rate = self.tmpRate
self.audioPlayer.rate = self.tmpRate
updateNowPlaying()
}
public func pause() {
self.audioPlayer.pause()
self.status = 0
self.rate = 0.0
updateNowPlaying()
lastPlayTime = Date.timeIntervalSinceReferenceDate
}
public func seek(_ to: Double) {
let continuePlaing = rate > 0.0
pause()
self.audioPlayer.seek(to: CMTime(seconds: to, preferredTimescale: 1000)) { completed in
if !completed {
NSLog("WARNING: seeking not completed (to \(to)")
}
if continuePlaing {
self.play()
}
self.updateNowPlaying()
}
}
public func setPlaybackRate(_ rate: Float, observed: Bool = false) {
if self.audioPlayer.rate != rate {
self.audioPlayer.rate = rate
}
if rate > 0.0 && !(observed && rate == 1) {
self.tmpRate = rate
}
self.rate = rate
self.updateNowPlaying()
}
public func getCurrentTime() -> Double {
self.audioPlayer.currentTime().seconds
}
public func getDuration() -> Double {
self.audioPlayer.currentItem?.duration.seconds ?? 0
}
// MARK: - Private
private func createAsset() -> AVAsset {
let headers: [String: String] = [
"Authorization": "Bearer \(audiobook.token)"
]
return AVURLAsset(url: URL(string: audiobook.playlistUrl)!, options: ["AVURLAssetHTTPHeaderFieldsKey": headers])
}
private func initAudioSession() {
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .spokenAudio, options: [.allowAirPlay])
try AVAudioSession.sharedInstance().setActive(true)
} catch {
NSLog("Failed to set AVAudioSession category")
print(error)
}
}
// MARK: - Now playing
private func setupRemoteTransportControls() {
DispatchQueue.main.sync {
UIApplication.shared.beginReceivingRemoteControlEvents()
}
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true
commandCenter.playCommand.addTarget { [unowned self] event in
play(allowSeekBack: true)
return .success
}
commandCenter.pauseCommand.isEnabled = true
commandCenter.pauseCommand.addTarget { [unowned self] event in
pause()
return .success
}
commandCenter.skipForwardCommand.isEnabled = true
commandCenter.skipForwardCommand.preferredIntervals = [30]
commandCenter.skipForwardCommand.addTarget { [unowned self] event in
guard let command = event.command as? MPSkipIntervalCommand else {
return .noSuchContent
}
seek(getCurrentTime() + command.preferredIntervals[0].doubleValue)
return .success
}
commandCenter.skipBackwardCommand.isEnabled = true
commandCenter.skipBackwardCommand.preferredIntervals = [30]
commandCenter.skipBackwardCommand.addTarget { [unowned self] event in
guard let command = event.command as? MPSkipIntervalCommand else {
return .noSuchContent
}
seek(getCurrentTime() - command.preferredIntervals[0].doubleValue)
return .success
}
commandCenter.changePlaybackPositionCommand.isEnabled = true
commandCenter.changePlaybackPositionCommand.addTarget { event in
guard let event = event as? MPChangePlaybackPositionCommandEvent else {
return .noSuchContent
}
self.seek(event.positionTime)
return .success
}
commandCenter.changePlaybackRateCommand.isEnabled = true
commandCenter.changePlaybackRateCommand.supportedPlaybackRates = [0.5, 0.75, 1.0, 1.25, 1.5, 2]
commandCenter.changePlaybackRateCommand.addTarget { event in
guard let event = event as? MPChangePlaybackRateCommandEvent else {
return .noSuchContent
}
self.setPlaybackRate(event.playbackRate)
return .success
}
}
private func updateNowPlaying() {
NowPlayingInfo.update(duration: getDuration(), currentTime: getCurrentTime(), rate: rate)
}
// MARK: - Observer
public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if context == &playerItemContext {
if keyPath == #keyPath(AVPlayer.status) {
guard let playerStatus = AVPlayerItem.Status(rawValue: (change?[.newKey] as? Int ?? -1)) else { return }
if playerStatus == .readyToPlay {
self.updateNowPlaying()
self.status = 0
if self.playWhenReady {
self.playWhenReady = false
self.play()
}
}
}
} else if context == &playerContext {
if keyPath == #keyPath(AVPlayer.rate) {
self.setPlaybackRate(change?[.newKey] as? Float ?? 1.0, observed: true)
} else if keyPath == #keyPath(AVPlayer.currentItem) {
NSLog("WARNING: Item ended")
}
} else {
super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
return
}
}
public static var instance: AudioPlayer?
}

View file

@ -0,0 +1,17 @@
//
// PlayerHandler.swift
// App
//
// Created by Rasmus Krämer on 11.04.22.
//
import Foundation
class PlayerHandler {
private static var player: AudioPlayer?
// private static var item: any
public static func setItem() {
}
}