From: liangzhenying <867174124@qq.com> Date: Fri, 10 Oct 2025 07:17:02 +0000 (+0800) Subject: 增加音乐播放 X-Git-Tag: 1.0.2~91 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=ce804d234c7bbe54c7a2d75bffeee73e763fb824;p=mirrors%2FShenYin.git 增加音乐播放 --- diff --git a/ShenYin/ShenYin/Api/HttpClient2.swift b/ShenYin/ShenYin/Api/HttpClient2.swift index 49477c7..cb99eba 100644 --- a/ShenYin/ShenYin/Api/HttpClient2.swift +++ b/ShenYin/ShenYin/Api/HttpClient2.swift @@ -95,7 +95,7 @@ extension CommomApi{ case .musicCategoryList(let categoryId,let page): return "/res/sleep-music/list/\(page)?categoryId=\(categoryId)" case .musicUrl( let id): - return "/res/voice-file/play/\(id)" + return "/res/music-file/path/\(id)" } } @@ -185,6 +185,41 @@ class HttpClient{ } } + static func download(url:String,fileId:String,completionHandler:@escaping ((String?) -> Void)){ + Logger.debug("dowload => ",url) + if let request = URLRequest(urlString:url) { + let task = HTTP(request, isDownload: true) + task.progress = { progress in + Logger.debug("下载进度:\(progress)") // 进度值在 0 到 1 之间 + } + task.downloadHandler = { response, tempUrl in + if let destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("\(fileId).mp3") { + if FileManager.default.fileExists(atPath: destinationUrl.path) { + Logger.debug("文件已经存在,先移除 => ",url) + do { + try FileManager.default.removeItem(atPath: destinationUrl.path) + }catch{ + Logger.debug("移除文件失败:\(error)") + completionHandler(nil) + } + } + do { + try FileManager.default.moveItem(at: tempUrl, to: destinationUrl) + Logger.debug("文件下载成功,保存路径:\(destinationUrl.path)") + completionHandler(destinationUrl.path) + } catch { + Logger.debug("移动文件失败:\(error)") + completionHandler(nil) + } + } + else{ + completionHandler(nil) + } + } + task.run() + } + } + } extension HttpClient{ diff --git "a/ShenYin/ShenYin/Resource/\345\244\247\347\272\246\345\234\250\345\206\254\345\255\243.mp3" "b/ShenYin/ShenYin/Resource/\345\244\247\347\272\246\345\234\250\345\206\254\345\255\243.mp3" new file mode 100644 index 0000000..4209e87 Binary files /dev/null and "b/ShenYin/ShenYin/Resource/\345\244\247\347\272\246\345\234\250\345\206\254\345\255\243.mp3" differ diff --git a/ShenYin/ShenYin/UI/Base/BaseVC.swift b/ShenYin/ShenYin/UI/Base/BaseVC.swift index ae612d9..814542b 100644 --- a/ShenYin/ShenYin/UI/Base/BaseVC.swift +++ b/ShenYin/ShenYin/UI/Base/BaseVC.swift @@ -85,7 +85,7 @@ open class BaseVC:UIViewController { } func addLog(){ - logBtn.frame = CGRect(x: UIScreen.main.bounds.size.width - 80, y: 200, width:60, height: 60) + logBtn.frame = CGRect(x: UIScreen.main.bounds.size.width - 80, y: kScreenHei - 200, width:60, height: 60) logBtn.backgroundColor = .blue logBtn.layer.cornerRadius = 30 logBtn.layer.masksToBounds = true diff --git a/ShenYin/ShenYin/UI/Sleep/AudioPlayerManager.swift b/ShenYin/ShenYin/UI/Sleep/AudioPlayerManager.swift index 74225cc..32995b0 100644 --- a/ShenYin/ShenYin/UI/Sleep/AudioPlayerManager.swift +++ b/ShenYin/ShenYin/UI/Sleep/AudioPlayerManager.swift @@ -1,19 +1,50 @@ -// -// AudioPlayer.swift -// ShenYin -// -// Created by liangshi on 2025/10/9. -// - import AVFoundation class AudioPlayerManager { + static let shared = AudioPlayerManager() + var player: AVPlayer? var playerItem: AVPlayerItem? + var timeObserverToken: Any? - func play(url: URL) { + typealias ProgressCallback = (_ current: Float, _ duration: Float) -> Void + var progressCallback: ProgressCallback? + + func play(filePath: String) { + Logger.debug("播放路径", filePath) + let url = URL(fileURLWithPath: filePath) playerItem = AVPlayerItem(url: url) player = AVPlayer(playerItem: playerItem) + setupProgressObserver() + setupPlayToEndObserver() + } + + func setupProgressObserver() { + guard let player = player else { return } + let interval = CMTimeMake(value: 1, timescale: 10) // 每 0.1 秒调用一次回调 + timeObserverToken = player.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main) { [weak self] time in + guard let self = self, let duration = self.playerItem?.duration else { return } + if CMTimeGetSeconds(duration) > 0 { + let currentProgress = Float(CMTimeGetSeconds(time)) + self.progressCallback?(currentProgress, Float(CMTimeGetSeconds(duration))) + } + } + } + + func setupPlayToEndObserver() { + NotificationCenter.default.addObserver(forName: Notification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem, queue: nil) { [weak self] _ in + guard let self = self else { return } + self.restartPlayback() + } + } + + func restartPlayback() { + guard let player = player, let playerItem = playerItem else { return } + player.seek(to: CMTime.zero) + player.play() + } + + func start() { player?.play() } @@ -21,9 +52,19 @@ class AudioPlayerManager { player?.pause() } - func setProgress(_ progress: Float) { - let duration = CMTimeGetSeconds((player?.currentItem?.duration)!) - let seekTime = CMTimeMakeWithSeconds(Float64(progress) * duration, preferredTimescale: 1) + func stop() { + player?.pause() + } + + func setDuration(_ duration: Float) { + let seekTime = CMTimeMakeWithSeconds(Float64(duration), preferredTimescale: 1) player?.seek(to: seekTime) } + + deinit { + if let token = timeObserverToken { + player?.removeTimeObserver(token) + } + NotificationCenter.default.removeObserver(self, name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem) + } } diff --git a/ShenYin/ShenYin/UI/Sleep/AudioPlayerVC.swift b/ShenYin/ShenYin/UI/Sleep/AudioPlayerVC.swift index 257b629..245433d 100644 --- a/ShenYin/ShenYin/UI/Sleep/AudioPlayerVC.swift +++ b/ShenYin/ShenYin/UI/Sleep/AudioPlayerVC.swift @@ -78,6 +78,14 @@ class AudioPlayerVC:BaseVC{ v.setImage(UIImage(named: "music_pause"), for: .selected) v.addTarget(self, action: #selector(btnAction), for: .touchUpInside) } + AudioPlayerManager.shared.progressCallback = {[weak self] current,duration in + guard let self = self else {return} + Logger.debug(duration) + slider.maximumValue = duration + slider.setValue(current, animated: true) + titleLabel.text = YLToos.formatSeconds1(Int(current)) + valueLabel.text = YLToos.formatSeconds1(Int(duration)) + } } override func setupLayout() { bgView.snp.makeConstraints { make in @@ -114,21 +122,27 @@ class AudioPlayerVC:BaseVC{ } } override func setupData() { - SleepVM.getMusicUrl(filedId: musicModel.fileId) { [weak self] model in guard let self = self else{return} - + if model.isSuccess{ + startDownload(url: model.data,fileId: musicModel.fileId) + } } } - override func navRightViewTapped() { - - } - @objc func addAction(){ - + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + AudioPlayerManager.shared.pause() } + @objc func btnAction(){ playBtn.isSelected = !playBtn.isSelected + if playBtn.isSelected { + AudioPlayerManager.shared.pause() + } + else{ + AudioPlayerManager.shared.start() + } } @objc func sliderChanged(_ slider:UISlider){ let value = YLToos.formatSeconds1(Int(slider.value)) @@ -136,6 +150,21 @@ class AudioPlayerVC:BaseVC{ if let text = titleLabel.text, text != value { titleLabel.text = value } + + AudioPlayerManager.shared.setDuration(slider.value) + } + func startDownload(url:String,fileId:String){ +// let url = "https://dc-cloud-priv.tos-cn-guangzhou.volces.com/music-file/2025_10_09/1976135290430767105.mp3" + HttpClient.download(url: url,fileId: fileId){[weak self] filePath in + guard let self = self else {return} + if let path = filePath{ + startPlay(path: path) + } + } + } + func startPlay(path:String){ + guard let path = Bundle.main.path(forResource: "大约在冬季", ofType: "mp3") else {return} + AudioPlayerManager.shared.play(filePath: path) + AudioPlayerManager.shared.start() } - } diff --git a/ShenYin/ShenYin/UI/Sleep/MusicModel.swift b/ShenYin/ShenYin/UI/Sleep/MusicModel.swift index 5ff12e3..8bc1034 100644 --- a/ShenYin/ShenYin/UI/Sleep/MusicModel.swift +++ b/ShenYin/ShenYin/UI/Sleep/MusicModel.swift @@ -29,3 +29,6 @@ class MusicModel:HandyJSON { var categoryId = "" required public init() { } } + class MusicDownloadModel:ResponseBaseModel { + var data = "" + } diff --git a/ShenYin/ShenYin/UI/Sleep/SleepVM.swift b/ShenYin/ShenYin/UI/Sleep/SleepVM.swift index b0eeb1e..9a09fa2 100644 --- a/ShenYin/ShenYin/UI/Sleep/SleepVM.swift +++ b/ShenYin/ShenYin/UI/Sleep/SleepVM.swift @@ -57,9 +57,9 @@ extension SleepVM{ completion(model) } } - static public func getMusicUrl(filedId id:String, completion:@escaping (_ result:ResponseBaseModel) ->Void) { + static public func getMusicUrl(filedId id:String, completion:@escaping (_ result:MusicDownloadModel) ->Void) { let api = CommomApi.musicUrl(filedId: id) - HttpClient.request(api) { (model:MusicCategoryRoot,res) in + HttpClient.request(api) { (model:MusicDownloadModel,res) in completion(model) } }