// // MPPositive_PlayerLoadViewModel.swift // MusicPlayer // // Created by Mr.Zhou on 2024/5/9. // import UIKit ///播放器管理ViewModel class MPPositive_PlayerLoadViewModel: NSObject { /// 单曲常规列表 var songVideos:[MPPositive_SongItemModel]! ///随机播放列表 var randomVideos:[MPPositive_SongItemModel]! ///当前播放音乐ViewModel var currentVideo:MPPositive_SongViewModel!{ didSet{ DispatchQueue.main.async { [weak self] in guard let self = self else {return} if currentVideo != nil { print("当前播放音乐是:\(currentVideo?.song?.title ?? "")") //启动监听器 startObservingCurrentVideoItem() //当值变化时通知播放器页面,更新UI NotificationCenter.notificationKey.post(notificationName: .positive_player_reload) } } } } //当前播放音乐 var currentVideoId:String? //监听器 private var itemObservation: NSKeyValueObservation? // private var loadQueue:DispatchQueue! ///异步请求组 // private var group:DispatchGroup! ///单曲播放队列ViewModel var listViewVideos:[MPPositive_SongViewModel]! ///palyer管理model初始化方法 /// - Parameters: /// - songs: 全部歌曲列表 /// - firstVideoId: 需要播放的第一首歌 init(_ songs:[MPPositive_SongItemModel], currentVideoId: String) { super.init() self.songVideos = songs //根据列表生成一份随机播放列表 self.randomVideos = self.songVideos.shuffled() self.listViewVideos = [] self.currentVideoId = currentVideoId } //启动对于当前音乐的监听器 private func startObservingCurrentVideoItem() { itemObservation?.invalidate() // 先移除旧的监听 //判断当前currentVideo是否已经加载完数据了 if currentVideo?.resourcePlayerItem != nil { //数据已经加载完毕了 postNoticeAction() }else { //添加新的监听 itemObservation = currentVideo?.observe(\.resourcePlayerItem, options: [.new], changeHandler: { [weak self] video, change in guard let self = self else {return} if change.newValue != nil { // 在这里处理 newItem 的值变化 postNoticeAction() }else { //获取到值是nil print("无效更新") } }) } } //发起通知告诉播放器已经切换了播放音乐 private func postNoticeAction() { DispatchQueue.main.async { [weak self] in guard let self = self else {return} if currentVideo != nil { MP_AnalyticsManager.shared.player_b_pvAction(currentVideo.song.videoId ?? "", videoname: currentVideo.title ?? "", artistname: currentVideo.song.shortBylineText ?? "") //当值变化时通知播放器页面,更新UI NotificationCenter.notificationKey.post(notificationName: .positive_player_reload, object: currentVideo) } } } ///将选中Video的上1位,下两位项包括本身总计4项Video进行补全转为ViewModel,并播放这首音乐 func improveData(_ targetVideoId:String, isRandom:Bool = false) { //更新当前播放音乐ID self.currentVideoId = targetVideoId //对于选中Video的集合 var array:[MPPositive_SongItemModel] = [] if isRandom { //获取targetVideoId的索引 guard let targetIndex = self.randomVideos.firstIndex(where: {$0.videoId == targetVideoId}) else { return } array.append(self.randomVideos[targetIndex]) // //获取上一位 // let previousIndex = targetIndex-1 // if previousIndex >= 0 { // array.append(self.randomVideos[previousIndex]) // } let nextIndex = targetIndex+1 let lastIndex = targetIndex+2 if nextIndex < randomVideos.count { array.append(self.randomVideos[nextIndex]) } if lastIndex < randomVideos.count { array.append(self.randomVideos[lastIndex]) } }else { //获取targetVideoId的索引 guard let targetIndex = self.songVideos.firstIndex(where: {$0.videoId == targetVideoId}) else { return } array.append(self.songVideos[targetIndex]) // //获取上一位 // let previousIndex = targetIndex-1 // if previousIndex >= 0 { // array.append(self.songVideos[previousIndex]) // } let nextIndex = targetIndex+1 let lastIndex = targetIndex+2 if nextIndex < songVideos.count { array.append(self.songVideos[nextIndex]) } if lastIndex < songVideos.count { array.append(self.songVideos[lastIndex]) } } //获取完成,优先检索ViewModel,看看是否已存在补完video let videoIDs = Set(listViewVideos.map({$0.song.videoId})) //比较videoID,去掉已经补完的内容 array = array.filter({!videoIDs.contains($0.videoId)}) //全部转化为MPPositive_SongViewModel let viewModels = array.map({(MPPositive_SongViewModel($0))}) //添加新的ViewModel self.listViewVideos.append(contentsOf: viewModels) //更新当前播放音乐 self.currentVideo = self.listViewVideos.first(where: {$0.song.videoId == targetVideoId}) //只保留最后7首 self.listViewVideos = self.listViewVideos.suffix(7) MP_PlayerManager.shared.playerStatuTimerAction() } ///重新获取指定歌曲资源 func remakeImproveData(_ completion:@escaping (() -> Void)) { currentVideo.configure() completion() } ///移除选中的song,并更新listViewVideos,移除相同index的值 func removeData(_ targetVideoId:String) { let targetIndex = songVideos.firstIndex(where: {$0.videoId == targetVideoId}) ?? 0 //将选中的音乐移除,同时更新listView songVideos = songVideos.filter({$0.videoId != targetVideoId}) randomVideos = randomVideos.filter({$0.videoId != targetVideoId}) listViewVideos = listViewVideos.filter({$0.song.videoId != targetVideoId}) if currentVideo != nil { //判断是否当前音乐 if currentVideo.song.videoId == targetVideoId { //判断targetIndex是否大于最大音乐值 if targetIndex < songVideos.count { let videoId = songVideos[targetIndex].videoId ?? "" improveData(videoId) }else { //移除的是原来最后一首音乐,播放新的最后一首音乐 let videoId = songVideos.last?.videoId ?? "" improveData(videoId) } } } } ///插入下一首播放 func playNextAction(_ next:MPPositive_SongItemModel) { //获取当前播放音乐在顺序播放列表和随机播放列表中的下标 if let index = songVideos.firstIndex(where: {$0.videoId == currentVideo?.song.videoId}) { //判断下一首会不会越界 let nextIndex:Int = index + 1 if songVideos.indices.contains(nextIndex) { //不会越界,可以插入 songVideos.insert(next, at: nextIndex) }else { //越界了,只能添加到最后 songVideos.append(next) } } //设置随机列表 if let index = randomVideos.firstIndex(where: {$0.videoId == currentVideo?.song.videoId}) { //判断下一首会不会越界 let nextIndex:Int = index + 1 if randomVideos.indices.contains(nextIndex) { //不会越界,可以插入 randomVideos.insert(next, at: nextIndex) }else { //越界了,只能添加到最后 randomVideos.append(next) } } MP_HUD.success("Successfully added to next song".localizableString(), delay: 1.0) { print("用户将\(next.title ?? "")添加到下一首播放") } } //销毁时 deinit { itemObservation?.invalidate() //释放所有数据 songVideos = nil currentVideo = nil randomVideos = nil listViewVideos = nil } }