//
|
// PayMusicVC.swift
|
// XQMuse
|
//
|
// Created by 无故事王国 on 2024/8/22.
|
//
|
|
import UIKit
|
import JQTools
|
import AVFoundation
|
import MediaPlayer
|
import RxRelay
|
import RxSwift
|
|
|
let ChangeMasterVoice_Noti = Notification.Name.init(rawValue: "ChangeMasterVoice_Noti")
|
|
@objc enum PlayMusicState:Int{
|
case playing = 1
|
case paurse = 2
|
case end = 3
|
case next = 4
|
}
|
|
@objc protocol PayMusicDelegate{
|
func playState(_ state:PlayMusicState)
|
@objc optional func playListen(currentInterval:TimeInterval,totalInterval:TimeInterval)
|
}
|
|
class PayMusicVC: BaseVC{
|
|
enum PayMuiscState {
|
case playing
|
case pause
|
}
|
|
private var coverImage:UIImageView!
|
private var label_name:UILabel!
|
private var btn_handle:UIButton!
|
private var btn_handleClose:UIButton!
|
private(set) var audioPlayer:AudioPlayer!
|
private var isAniLoop:Bool = false
|
private var meditationModel:MeditationModel?{
|
didSet{
|
if let m = meditationModel{
|
coverImage.sd_setImage(with: URL(string: m.coverUrl.components(separatedBy: ",").first!.jq_urlEncoded()),placeholderImage: UIImage(named: "login_top_bg"))
|
label_name.text = m.meditationTitle
|
}
|
}
|
}
|
|
private init() {
|
super.init(nibName: nil, bundle: nil)
|
}
|
|
internal required init?(coder: NSCoder) {
|
fatalError("init(coder:) has not been implemented")
|
}
|
|
override func viewDidLoad() {
|
super.viewDidLoad()
|
audioPlayer = AudioPlayer.getSharedInstance()
|
|
let tap = UITapGestureRecognizer(target: self, action: #selector(showDetailAction))
|
coverImage.isUserInteractionEnabled = true
|
coverImage.addGestureRecognizer(tap)
|
|
|
NotificationCenter.default.rx.notification(UIApplication.didBecomeActiveNotification).subscribe(onNext: {noti in
|
if self.audioPlayer.bgmPlayer?.timeControlStatus == .playing{
|
PayMusicVC.updateStatus(.playing)
|
}else{
|
PayMusicVC.updateStatus(.pause)
|
}
|
}).disposed(by: disposeBag)
|
}
|
|
override func setUI() {
|
view.backgroundColor = UIColor(hexString: "#B1C998")
|
view.jq_cornerRadius = 23.25
|
|
coverImage = UIImageView(image: UIImage(named: "bg_home_1"))
|
coverImage.jq_cornerRadius = 18.25
|
coverImage.jq_borderColor = .black
|
coverImage.jq_borderWidth = 3.5
|
view.addSubview(coverImage)
|
coverImage.snp.makeConstraints { make in
|
make.left.equalTo(7.5)
|
make.width.height.equalTo(36.5)
|
make.centerY.equalToSuperview()
|
}
|
|
btn_handle = UIButton(type: .custom)
|
btn_handle.setImage(UIImage(named: "icon_play_purse"), for: .normal)
|
btn_handle.setImage(UIImage(named: "icon_play_small"), for: .selected)
|
btn_handle.addTarget(self, action: #selector(tapHandleAction), for: .touchUpInside)
|
view.addSubview(btn_handle)
|
|
btn_handleClose = UIButton(type: .custom)
|
btn_handleClose.setImage(UIImage(named: "icon_play_close"), for: .normal)
|
btn_handleClose.addTarget(self, action: #selector(closeAction), for: .touchUpInside)
|
view.addSubview(btn_handleClose)
|
|
let statckView = UIStackView(arrangedSubviews: [btn_handle,btn_handleClose])
|
statckView.axis = .horizontal
|
statckView.distribution = .equalSpacing
|
statckView.spacing = 18
|
view.addSubview(statckView)
|
statckView.snp.makeConstraints { make in
|
make.right.equalToSuperview().offset(-24.5)
|
make.centerY.equalToSuperview()
|
make.width.equalTo(73.5)
|
}
|
|
label_name = UILabel()
|
label_name.text = "--"
|
label_name.font = .systemFont(ofSize: 14.8, weight: .bold)
|
label_name.textColor = .white
|
view.addSubview(label_name)
|
label_name.snp.makeConstraints { make in
|
make.left.equalTo(self.coverImage.snp.right).offset(17.5)
|
make.centerY.equalToSuperview()
|
make.right.equalTo(statckView.snp.left)
|
}
|
}
|
|
static func show(model:MeditationModel,isHidden:Bool = true){
|
if let tabBarVC = JQ_currentViewController().navigationController?.tabBarController as? BaseTabBarVC{
|
if !tabBarVC.children.contains(where: {$0 is PayMusicVC}){
|
let vc = PayMusicVC()
|
vc.view.isHidden = isHidden
|
vc.meditationModel = model
|
let tabBarHeight = JQ_currentViewController().navigationController?.tabBarController?.tabBar.height ?? 0
|
JQ_currentViewController().navigationController?.tabBarController?.addChild(vc)
|
JQ_currentViewController().navigationController?.tabBarController?.view.addSubview(vc.view)
|
vc.view.snp.makeConstraints { make in
|
make.left.equalTo(18.5)
|
make.right.equalTo(-18.5)
|
make.height.equalTo(46.5)
|
make.bottom.equalToSuperview().offset(-(tabBarHeight))
|
}
|
vc.view.layoutIfNeeded()
|
vc.startRunloopAni()
|
}else{
|
PayMusicVC.updateStatus(.playing, musicName: model.meditationTitle)
|
}
|
}
|
}
|
|
static func updateStatus(_ state:PayMuiscState,musicName:String? = nil){
|
if let tabBarVC = JQ_currentViewController().navigationController?.tabBarController as? BaseTabBarVC{
|
if let vc = tabBarVC.children.filter({$0 is PayMusicVC}).first as? PayMusicVC{
|
vc.btn_handle.isSelected = state == .pause
|
if let musicName{
|
vc.label_name.text = musicName
|
}
|
switch state {
|
case .playing:
|
MPNowPlayingInfoCenter.default().playbackState = .playing
|
case .pause:
|
MPNowPlayingInfoCenter.default().playbackState = .paused
|
}
|
}
|
}
|
}
|
|
static func hidden(){
|
if let tabBarVC = JQ_currentViewController().navigationController?.tabBarController as? BaseTabBarVC{
|
if let vc = tabBarVC.children.filter({$0 is PayMusicVC}).first{
|
AudioPlayer.destroy()
|
vc.view.removeFromSuperview()
|
vc.removeFromParent()
|
MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
|
}
|
}
|
}
|
|
@objc func showDetailAction(){
|
if let id = meditationModel?.id{
|
|
Services.getMeditationDetail(id: id).subscribe(onNext: {[weak self]data in
|
guard let weakSelf = self else { return }
|
if let m = data.data{
|
let isVip = m.isVip == .yes
|
if m.chargeType == .free || (isVip && m.chargeType == .vipFree) || (m.chargeType == .payment && m.isBuy == .yes){
|
let vc = HomeItemDetailVC(model: m)
|
vc.hidesBottomBarWhenPushed = true
|
JQ_currentNavigationController().jq_push(vc: vc)
|
return
|
}
|
|
if m.chargeType == .payment && m.isBuy == .no{
|
guard sceneDelegate!.checkisLoginState() else{return}
|
let vc = PaymentOrderVC(museItemModel: m,type: .muse,showType:.vertical)
|
vc.hidesBottomBarWhenPushed = true
|
JQ_currentNavigationController().jq_push(vc: vc)
|
return
|
}
|
|
if m.chargeType == .vipFree{
|
let vc = VIPCenterVC()
|
vc.hidesBottomBarWhenPushed = true
|
JQ_currentNavigationController().jq_push(vc: vc)
|
return
|
}
|
}
|
}).disposed(by: disposeBag)
|
}
|
}
|
|
private func startRunloopAni(){
|
isAniLoop = true
|
// 创建旋转动画
|
let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
|
rotationAnimation.fromValue = 0
|
rotationAnimation.toValue = CGFloat.pi * 2
|
rotationAnimation.duration = 5 // 动画持续时间
|
rotationAnimation.repeatCount = .greatestFiniteMagnitude // 无限重复
|
coverImage.layer.add(rotationAnimation, forKey: nil)
|
}
|
|
private func stopRunloopAni(){
|
isAniLoop = false
|
coverImage.layer.removeAllAnimations()
|
}
|
|
@objc func tapHandleAction(_ btn:UIButton){
|
btn.isSelected = !btn.isSelected
|
|
if btn.isSelected{
|
self.audioPlayer.bgmPlayer?.pause()
|
self.audioPlayer.masterPlayer?.pause()
|
self.stopRunloopAni()
|
PayMusicVC.updateStatus(.pause)
|
}else{
|
|
if self.audioPlayer.scenePlayer?.timeControlStatus == .playing{
|
self.audioPlayer.scenePlayer?.pause()
|
}
|
|
self.audioPlayer.bgmPlayer?.play()
|
self.audioPlayer.masterPlayer?.play()
|
self.audioPlayer.masterPlayer?.volume = Float(UserDefaultSettingViewModel.getSetting()?.masterVolume ?? 0.5)
|
self.startRunloopAni()
|
PayMusicVC.updateStatus(.playing)
|
}
|
DispatchQueue.main.asyncAfter(delay: 0.4) {
|
NotificationCenter.default.post(name: ReloadData_Noti, object: nil, userInfo: nil)
|
}
|
}
|
|
@objc func closeAction(_ btn:UIButton){
|
CommonAlertView.show(title: "提示", content: "是否关闭当前播放音频?") {[weak self] state in
|
guard let weakSelf = self else { return }
|
if state{
|
self?.audioPlayer.cleanMuse()
|
self?.view.removeFromSuperview()
|
self?.removeFromParent()
|
|
if let id = self?.audioPlayer.meditationModel?.id{
|
Services.watchMuse(id: id, timeLook: self?.audioPlayer.lisenMuseTime ?? 0).subscribe(onNext: { _ in
|
NotificationCenter.default.post(name: TreeTaskUpdate_Noti, object: nil)
|
}).disposed(by: weakSelf.disposeBag)
|
}
|
|
if UserDefaultSettingViewModel.getSetting()?.bgm != nil{
|
AudioPlayer.getSharedInstance().playSceneAt(UserDefaultSettingViewModel.getSetting()!.bgm!.audioFile)
|
}
|
|
DispatchQueue.main.asyncAfter(delay: 0.4) {
|
NotificationCenter.default.post(name: ReloadData_Noti, object: nil, userInfo: nil)
|
}
|
}
|
}
|
}
|
}
|
|
class AudioPlayer {
|
private(set) var bgmPlayer:AVPlayer? // 背景音
|
private(set) var scenePlayer:AVPlayer? //场景音
|
private(set) var masterPlayer:AVPlayer? //大师音
|
private(set) var playIndex:Int = 0 //播放的角标
|
private var cacheDirectory:URL!
|
private let session = URLSession.shared
|
private var urls = [URL]()
|
private var timer:Timer?
|
private(set) var times = BehaviorRelay<Int?>(value: nil) //倒计时定时器
|
private static var _sharedInstance: AudioPlayer?
|
var meditationModel:MeditationModel? //疗愈音频
|
var lisenMuseTime:Int = 0 //听疗愈时间记录
|
|
weak var delegate:PayMusicDelegate?
|
private var disposeBag = DisposeBag()
|
|
class func getSharedInstance() -> AudioPlayer {
|
guard let instance = _sharedInstance else {
|
_sharedInstance = AudioPlayer()
|
_sharedInstance!.cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!.appendingPathComponent("audios")
|
print("---:\(_sharedInstance!.cacheDirectory.absoluteString)")
|
|
if !FileManager.default.fileExists(atPath: _sharedInstance!.cacheDirectory!.absoluteString){
|
try? FileManager.default.createDirectory(at: _sharedInstance!.cacheDirectory, withIntermediateDirectories: false)
|
}
|
return _sharedInstance!
|
}
|
return instance
|
}
|
|
private init() {
|
NotificationCenter.default.addObserver(forName: ChangeMasterVoice_Noti, object: nil, queue: .main) { noti in
|
if let value = noti.object as? Float{
|
print("--->进入")
|
self.masterPlayer?.volume = value
|
self.bgmPlayer?.volume = value
|
}
|
}
|
|
NotificationCenter.default.rx.notification(.AVPlayerItemDidPlayToEndTime).subscribe(onNext: {[weak self]data in
|
guard let weakSelf = self else { return }
|
let notifiUrl = ((data.object as? AVPlayerItem)?.asset as? AVURLAsset)
|
let sceneItem = (self?.scenePlayer?.currentItem?.asset as? AVURLAsset)
|
let bgmItem = (self?.bgmPlayer?.currentItem?.asset as? AVURLAsset)
|
let masterItem = (self?.masterPlayer?.currentItem?.asset as? AVURLAsset)
|
|
|
if masterItem?.url == notifiUrl?.url{
|
weakSelf.masterPlayer = nil
|
}
|
|
|
if bgmItem?.url == notifiUrl?.url{
|
if weakSelf.playIndex < weakSelf.urls.count - 1{
|
weakSelf.next()
|
weakSelf.delegate?.playState(.next)
|
}else{
|
weakSelf.bgmPlayer?.pause()
|
weakSelf.playIndex = 0
|
weakSelf.bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: weakSelf.urls[0]))
|
weakSelf.bgmPlayer?.play()
|
}
|
|
if let id = weakSelf.meditationModel?.id{
|
Services.watchMuse(id: id, timeLook: weakSelf.lisenMuseTime).subscribe(onNext: { _ in
|
weakSelf.lisenMuseTime = 0
|
NotificationCenter.default.post(name: TreeTaskUpdate_Noti, object: nil)
|
NotificationCenter.default.post(name: CleanDetailTime_Noti, object: nil)
|
}).disposed(by: weakSelf.disposeBag)
|
}
|
}
|
|
if sceneItem?.url == notifiUrl?.url{
|
self?.scenePlayer?.seek(to: CMTime.zero)
|
self?.scenePlayer?.play()
|
}
|
|
}).disposed(by: disposeBag)
|
} // 私有化init方法
|
|
//销毁单例对象
|
class func destroy() {
|
_sharedInstance = nil
|
}
|
|
func clean(){
|
self.bgmPlayer?.pause()
|
self.masterPlayer?.pause()
|
self.meditationModel = nil
|
self.masterPlayer = nil
|
self.bgmPlayer = nil
|
self.timer = nil
|
AudioPlayer.destroy()
|
}
|
|
func cleanMuse(){
|
self.bgmPlayer?.pause()
|
self.masterPlayer?.pause()
|
self.meditationModel = nil
|
self.masterPlayer = nil
|
self.timer = nil
|
self.lisenMuseTime = 0
|
}
|
|
func playBGMAt(firstPlayIndex:Int,model:MeditationModel,delegate:PayMusicDelegate?,coverImage:UIImage? = nil){
|
|
//清除之前的
|
self.urls.removeAll()
|
self.masterPlayer?.pause()
|
self.bgmPlayer?.pause()
|
self.masterPlayer = nil
|
self.bgmPlayer = nil
|
|
self.delegate = delegate
|
self.playIndex = firstPlayIndex
|
self.meditationModel = model
|
|
let urls = model.meditationMusicList.map { url in
|
return URL(string: url.jq_urlEncoded())!
|
}
|
|
if urls.count == 0{
|
alertError(msg: "数据获取失败");return
|
}
|
|
let masterUrl = URL(string: model.tutorAudioUrl.jq_urlEncoded())
|
|
autoreleasepool{[unowned self] () in
|
for url in urls {
|
self.checkCacheAudio(from: url) {[unowned self] _, url in
|
self.urls.append(url)
|
}
|
}
|
self.bgmPlayer = AVPlayer(url: self.urls[firstPlayIndex])
|
|
if masterUrl != nil{
|
self.masterPlayer = AVPlayer(url: masterUrl!)
|
self.masterPlayer?.volume = Float(UserDefaultSettingViewModel.getSetting()?.masterVolume ?? 0.5)
|
}
|
}
|
|
self.bgmPlayer?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: DispatchQueue.main) { [weak self](time) in
|
guard let weakSelf = self else { return }
|
weakSelf.delegate?.playState(.playing)
|
guard weakSelf.bgmPlayer != nil else {return}
|
weakSelf.lisenMuseTime += 1
|
//当前正在播放的时间
|
let loadTime = CMTimeGetSeconds(time)
|
//视频总时间
|
let totalTime = CMTimeGetSeconds((weakSelf.bgmPlayer?.currentItem?.duration)!)
|
|
weakSelf.delegate?.playListen?(currentInterval: loadTime, totalInterval: totalTime)
|
|
if let m = weakSelf.meditationModel{
|
var dic = [String:Any]()
|
dic[MPMediaItemPropertyTitle] = m.meditationTitle
|
dic[MPMediaItemPropertyArtist] = "泉疗愈"
|
dic[MPMediaItemPropertyDiscNumber] = 1
|
dic[MPNowPlayingInfoPropertyElapsedPlaybackTime] = loadTime
|
dic[MPNowPlayingInfoPropertyPlaybackRate] = 1
|
// 获取时长。item.duration.seconds 不凑效
|
let asset = weakSelf.bgmPlayer?.currentItem?.asset
|
dic[MPMediaItemPropertyPlaybackDuration] = CMTimeGetSeconds(asset!.duration)
|
dic[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: CGSize(width: 50, height: 50), requestHandler: { s in
|
|
if let coverImage{
|
return coverImage
|
}else{
|
return UIImage(named: "home_top_bg")!
|
}
|
})
|
MPNowPlayingInfoCenter.default().nowPlayingInfo = dic
|
}
|
}
|
|
self.bgmPlayer?.rx.observe(AVPlayer.TimeControlStatus.self,"timeControlStatus").subscribe(onNext: { state in
|
DispatchQueue.main.asyncAfter(delay: 1.0) {
|
if state == .paused{
|
print("----》暂停")
|
PayMusicVC.updateStatus(.pause)
|
}else if state == .playing{
|
print("----》播放")
|
PayMusicVC.updateStatus(.playing)
|
}
|
}
|
}).disposed(by: disposeBag)
|
|
|
|
self.bgmPlayer?.currentItem?.rx.observe(AVPlayerItem.Status.self,"status").subscribe(onNext: { _ in
|
print("---MasterStatus1: \(self.masterPlayer?.status.rawValue ?? 0)")
|
print("---bgmStatus1: \(self.bgmPlayer?.status.rawValue ?? 0)")
|
if self.bgmPlayer?.status == .readyToPlay && self.masterPlayer?.status == .readyToPlay{
|
self.bgmPlayer?.play()
|
self.masterPlayer?.play()
|
}
|
|
}).disposed(by: disposeBag)
|
|
self.masterPlayer?.currentItem?.rx.observe(AVPlayerItem.Status.self,"status").subscribe(onNext: { _ in
|
print("---MasterStatus: \(self.masterPlayer?.status.rawValue ?? 0)")
|
print("---bgmStatus: \(self.bgmPlayer?.status.rawValue ?? 0)")
|
if self.bgmPlayer?.status == .readyToPlay && self.masterPlayer?.status == .readyToPlay{
|
self.bgmPlayer?.play()
|
self.masterPlayer?.play()
|
}
|
}).disposed(by: disposeBag)
|
|
setLockScreen()
|
|
do {
|
try AVAudioSession.sharedInstance().setActive(true)
|
print("Playback OK")
|
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.allowBluetooth, .allowAirPlay])
|
print("Session is Active")
|
} catch {
|
print(error)
|
}
|
}
|
|
|
func setBGMRate(value:CGFloat){
|
if let v = bgmPlayer?.currentItem?.duration.timescale,v > 0{
|
bgmPlayer?.seek(to: CMTime(seconds: value, preferredTimescale: v))
|
}
|
}
|
|
/// 播放场景音乐
|
func playSceneAt(_ url:String){
|
guard let URL = URL(string: url.jq_urlEncoded()) else { return }
|
scenePlayer?.pause()
|
|
if scenePlayer == nil{
|
scenePlayer = AVPlayer(url: URL)
|
}else{
|
scenePlayer?.replaceCurrentItem(with: AVPlayerItem(url: URL))
|
}
|
DispatchQueue.main.asyncAfter(delay: 0.5) {
|
self.scenePlayer?.play()
|
self.scenePlayer?.volume = Float(UserDefaultSettingViewModel.getSetting()?.volume ?? 0.5)
|
}
|
}
|
|
func dellocScene(){
|
scenePlayer?.pause()
|
scenePlayer = nil
|
}
|
|
func pauseScene(){
|
scenePlayer?.pause()
|
}
|
|
func playScene(){
|
if UserDefaultSettingViewModel.getSetting()?.bgm != nil{
|
playSceneAt(UserDefaultSettingViewModel.getSetting()?.bgm?.audioFile ?? "")
|
}
|
}
|
|
func next(){
|
if UserDefaultSettingViewModel.getSetting()?.playModel == .line{
|
playIndex += 1
|
}
|
|
let index = min((urls.count - 1), playIndex)
|
bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
|
bgmPlayer?.play()
|
}
|
|
func previous(){
|
playIndex -= 1
|
let index = max(0, playIndex)
|
bgmPlayer?.replaceCurrentItem(with: AVPlayerItem(url: urls[index]))
|
bgmPlayer?.play()
|
}
|
|
func setLockScreen(){
|
// 锁屏进度控制
|
let center = MPRemoteCommandCenter.shared()
|
|
// 修改进度
|
center.changePlaybackPositionCommand.addTarget {[unowned self] event in
|
|
guard let event = event as? MPChangePlaybackPositionCommandEvent else {
|
return .commandFailed
|
}
|
|
self.bgmPlayer?.seek(to: CMTime(seconds: event.positionTime, preferredTimescale: 1),
|
toleranceBefore: CMTime(seconds: 0, preferredTimescale: 1),
|
toleranceAfter: CMTime(seconds: 0, preferredTimescale: 1))
|
|
// 更新锁屏信息
|
return .success
|
}
|
|
// 播放
|
center.playCommand.addTarget {[weak self] event in
|
self?.bgmPlayer?.play()
|
self?.masterPlayer?.play()
|
PayMusicVC.updateStatus(.playing)
|
return .success
|
}
|
|
// 暂停
|
center.pauseCommand.addTarget {[weak self] event in
|
self?.bgmPlayer?.pause()
|
self?.masterPlayer?.pause()
|
PayMusicVC.updateStatus(.pause)
|
return .success
|
}
|
|
// 下一首
|
center.nextTrackCommand.addTarget { event in
|
return .success
|
}
|
|
center.nextTrackCommand.isEnabled = false
|
center.previousTrackCommand.isEnabled = false
|
|
// 上一首
|
center.previousTrackCommand.addTarget { event in
|
return .success
|
}
|
}
|
|
func setTimer(times:Int){
|
self.times.accept(times)
|
guard timer == nil else {return}
|
timer = Timer(timeInterval: 1, repeats: true, block: {[weak self] timer in
|
guard let weakSelf = self else { return }
|
let newTimes = weakSelf.times.value! - 1
|
|
if newTimes <= 0{
|
weakSelf.times.accept(nil)
|
weakSelf.stopTimer()
|
weakSelf.bgmPlayer?.pause()
|
weakSelf.masterPlayer?.pause()
|
weakSelf.scenePlayer?.pause()
|
MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
|
AudioPlayer.destroy()
|
PayMusicVC.hidden()
|
}else{
|
weakSelf.times.accept(newTimes)
|
}
|
})
|
timer?.fire()
|
|
if let t = timer{
|
RunLoop.current.add(t, forMode: .default)
|
}
|
}
|
|
func stopTimer(){
|
timer?.invalidate()
|
timer = nil
|
times.accept(nil)
|
}
|
|
|
// 下载视频并缓存,如果没有缓存,原路返回并异步下载
|
internal func checkCacheAudio(from url: URL, completion: @escaping (Bool,URL) -> Void) {
|
|
let videoCacheUrl = cacheDirectory.appendingPathComponent(url.lastPathComponent.jq_md5String() + "." + url.pathExtension)
|
|
// 检查缓存中是否已存在文件
|
if FileManager.default.fileExists(atPath: videoCacheUrl.path) {
|
completion(true,videoCacheUrl)
|
return
|
}else{
|
completion(false,url)
|
}
|
|
// 使用URLSession下载视频
|
let downloadTask = session.downloadTask(with: url) { tempLocalUrl, response, error in
|
if let tempLocalUrl = tempLocalUrl, error == nil {
|
do {
|
let temp = videoCacheUrl.appendingPathExtension(url.pathExtension)
|
try FileManager.default.moveItem(at: tempLocalUrl, to: temp)
|
} catch {
|
print("视频缓存失败:catch")
|
}
|
} else {
|
print("视频缓存失败:\(error?.localizedDescription ?? "")")
|
}
|
}
|
downloadTask.resume()
|
}
|
}
|
|
|
struct MusicProjectPlayInfoModel {
|
|
}
|