// // 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!{ willSet{ if newValue != nil { if currentVideo != nil { //当值变化时通知播放器页面,更新UI NotificationCenter.notificationKey.post(notificationName: .positive_player_reload, object: currentVideo) }else { //当值变化时通知播放器页面,更新UI NotificationCenter.notificationKey.post(notificationName: .positive_player_reload) } } } } ///当前播放音乐ID var currentVideoId:String! ///单曲ViewModel列表 var listViewVideos:[MPPositive_SongViewModel]! ///异步请求组 var group:DispatchGroup? ///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 } ///将选中Video的上下2项包括本身总计3项Video进行补全转为ViewModel,并播放这首音乐 func improveData(_ targetVideoId:String) { //获取targetVideoId的索引 guard let targetIndex = self.songVideos.firstIndex(where: {$0.videoId == targetVideoId}) else { return } //对于选中Video的集合 var array:[MPPositive_SongItemModel] = [] array.append(self.songVideos[targetIndex]) //获取上一位 let previousIndex = targetIndex-1 if previousIndex >= 0 { array.append(self.songVideos[previousIndex]) } let nextIndex = targetIndex+1 if nextIndex < songVideos.count { array.append(self.songVideos[nextIndex]) } //获取完成,优先检索ViewModel,看看是否已存在补完video let videoIDs = Set(listViewVideos.map({$0.song.videoId})) //比较videoID,去掉已经补完的内容 array = array.filter({!videoIDs.contains($0.videoId)}) group = DispatchGroup() //去重完毕,对剩下内容补完 for item in array { group?.enter() //补全歌词id和相关内容id improveDataforLycirsAndRelated(item) {[weak self] (result) in item.lyricsID = result.0 item.relatedID = result.1 self?.group?.leave() } group?.enter() //补全资源路径组和封面路径组 improveDataforResouceAndCover(item) {[weak self] resourceUrls, coverUrls in item.resourceUrls = resourceUrls.1 item.audioUrls = resourceUrls.0 item.coverUrls = coverUrls //补全完成,转化为ViewModel,并添加进listViewVideos self?.listViewVideos.append(.init(item)) self?.group?.leave() } } group?.notify(queue: .main, execute: { //补完转化完毕,重新排序 self.listViewVideos = self.listViewVideos.sorted(by: {$0.index < $1.index}) //排序完成,确定播放音乐 self.currentVideo = self.listViewVideos.first(where: {$0.song.videoId == targetVideoId}) self.group = nil }) } ///重新获取指定歌曲资源 func remakeImproveData(_ completion:@escaping (() -> Void)) { //当前歌曲不能播放,需要重新配置资源 improveDataforResouceAndCover(currentVideo.song) {[weak self] resourceUrls, coverUrls in guard let self = self else {return} currentVideo.song.resourceUrls = resourceUrls.1 currentVideo.song.audioUrls = resourceUrls.0 //成功更新资源,将重新补完的歌曲,放进listViewVideos中 listViewVideos.forEach({ item in if item.song.videoId == self.currentVideo.song.videoId { item.song.resourceUrls = self.currentVideo.song.resourceUrls item.song.audioUrls = self.currentVideo.song.audioUrls } }) currentVideo.resourceAsset = .init(url: .init(string: currentVideo.song.resourceUrls!.first!)!) currentVideo.resourcePlayerItem = .init(asset: currentVideo.resourceAsset!) //当值变化时通知播放器页面,更新UI NotificationCenter.notificationKey.post(notificationName: .positive_player_reload) 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) } } } } ///调用next对单曲数据歌词ID与相关ID补全 private func improveDataforLycirsAndRelated(_ song:MPPositive_SongItemModel, completion:@escaping(((String?,String?)) -> Void)) { //单曲补全需要再次调用next接口 MP_NetWorkManager.shared.requestNextLyricsAndRelated(song){ result in completion(result) } } ///调用player对资源路径和封面路径补全 private func improveDataforResouceAndCover(_ song:MPPositive_SongItemModel, completion:@escaping((([String],[String]), [String]?) -> Void)) { //单曲补全需要调用player接口 MP_NetWorkManager.shared.requestPlayer(song) { resourceUrls, coverUrls in completion(resourceUrls,coverUrls) } } }