198 lines
8.7 KiB
Swift
198 lines
8.7 KiB
Swift
//
|
||
// 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{
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
if newValue != nil {
|
||
MP_AnalyticsManager.shared.player_b_pvAction(newValue.song.videoId, videoname: newValue.title ?? "", artistname: newValue.song.shortBylineText ?? "")
|
||
if currentVideo != nil {
|
||
//当值变化时通知播放器页面,更新UI
|
||
NotificationCenter.notificationKey.post(notificationName: .positive_player_reload, object: currentVideo)
|
||
}else {
|
||
//当值变化时通知播放器页面,更新UI
|
||
NotificationCenter.notificationKey.post(notificationName: .positive_player_reload)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
///单曲播放队列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 = []
|
||
}
|
||
|
||
///将选中Video的上1位,下两位项包括本身总计4项Video进行补全转为ViewModel,并播放这首音乐
|
||
func improveData(_ targetVideoId:String, isRandom:Bool = false) {
|
||
//对于选中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)})
|
||
|
||
group = DispatchGroup()
|
||
|
||
//去重完毕,对剩下内容补完
|
||
for item in array {
|
||
group?.enter()
|
||
//补全歌词id和相关内容id
|
||
if item.lyricsID == nil || item.relatedID == nil {
|
||
improveDataforLycirsAndRelated(item) {[weak self] (result) in
|
||
item.lyricsID = result.0
|
||
item.relatedID = result.1
|
||
self?.group?.leave()
|
||
}
|
||
}else {
|
||
self.group?.leave()
|
||
}
|
||
group?.enter()
|
||
//判断当前videoID是否进行过下载
|
||
if let resource = getDocumentsFileURL(item.videoId) {
|
||
//下载过,resource直接填入
|
||
item.resourceUrls = [resource]
|
||
//补全完成,转化为ViewModel,并添加进listViewVideos
|
||
listViewVideos.append(.init(item))
|
||
self.group?.leave()
|
||
}else {
|
||
//没有下载过
|
||
//补全资源路径组和封面路径组
|
||
improveDataforResouceAndCover(item) {[weak self] resourceUrls, coverUrls in
|
||
item.resourceUrls = resourceUrls.0
|
||
item.itags = resourceUrls.1
|
||
item.mimeTypes = resourceUrls.2
|
||
item.coverUrls = coverUrls
|
||
//补全完成,转化为ViewModel,并添加进listViewVideos
|
||
self?.listViewVideos.append(.init(item))
|
||
self?.group?.leave()
|
||
}
|
||
}
|
||
}
|
||
group?.notify(queue: .main, execute: {
|
||
[weak self] in
|
||
//确定播放音乐
|
||
self?.currentVideo = self?.listViewVideos.first(where: {$0.song.videoId == targetVideoId})
|
||
//只保留最后四首
|
||
self?.listViewVideos = self?.listViewVideos.suffix(4)
|
||
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.0
|
||
currentVideo.song.itags = resourceUrls.1
|
||
currentVideo.song.mimeTypes = resourceUrls.2
|
||
//成功更新资源,将重新补完的歌曲,放进listViewVideos中
|
||
listViewVideos.forEach({ item in
|
||
if item.song.videoId == self.currentVideo.song.videoId {
|
||
item.song.resourceUrls = self.currentVideo.song.resourceUrls
|
||
item.song.itags = self.currentVideo.song.itags
|
||
item.song.mimeTypes = self.currentVideo.song.mimeTypes
|
||
}
|
||
})
|
||
// currentVideo.resourceAsset = .init(url: .init(string: currentVideo.song.resourceUrls!.first!)!)
|
||
// currentVideo.resourcePlayerItem = .init(asset: currentVideo.resourceAsset!)
|
||
// currentVideo.resourcePlayerItem = .init(url: .init(string: (currentVideo.song.resourceUrls?.first ?? ""))!, bitrate: Int64(currentVideo.song.bitrates?.first ?? 0), title: currentVideo.title, videoId: currentVideo.song.videoId)
|
||
currentVideo.configure()
|
||
//当值变化时通知播放器页面,更新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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//判断当前videoId是不是下载过
|
||
private func findVideoIdForDocument(_ videoId:String) -> Bool {
|
||
return MPPositive_DownloadItemModel.fetch(.init(format: "videoId == %@", videoId)).count != 0
|
||
}
|
||
}
|