Merge branch 'master' of http://git.zhenbs.com:9999/3-group-ios/Music_Player3
# Conflicts: # MusicPlayer/MP/MPPositive/Views/Player/MPPositive_PlayerCoverView.swift
This commit is contained in:
commit
249ec76e3b
@ -40,6 +40,7 @@
|
|||||||
CBB5F1F92BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1F82BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift */; };
|
CBB5F1F92BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1F82BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift */; };
|
||||||
CBB5F1FB2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1FA2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift */; };
|
CBB5F1FB2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1FA2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift */; };
|
||||||
CBB5F1FD2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1FC2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift */; };
|
CBB5F1FD2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1FC2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift */; };
|
||||||
|
CBB5F1FF2BFCB40000CBF73A /* MPPositive_Debouncer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB5F1FE2BFCB40000CBF73A /* MPPositive_Debouncer.swift */; };
|
||||||
CBB75B0B2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB75B0A2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift */; };
|
CBB75B0B2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB75B0A2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift */; };
|
||||||
CBB9F9DD2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB9F9DC2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift */; };
|
CBB9F9DD2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB9F9DC2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift */; };
|
||||||
CBB9F9DF2BEDDCC5008338DE /* MP_PlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB9F9DE2BEDDCC5008338DE /* MP_PlayerManager.swift */; };
|
CBB9F9DF2BEDDCC5008338DE /* MP_PlayerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBB9F9DE2BEDDCC5008338DE /* MP_PlayerManager.swift */; };
|
||||||
@ -229,6 +230,7 @@
|
|||||||
CBB5F1F82BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionSongModel.swift; sourceTree = "<group>"; };
|
CBB5F1F82BFC35D000CBF73A /* MPPositive_CollectionSongModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionSongModel.swift; sourceTree = "<group>"; };
|
||||||
CBB5F1FA2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionListModel.swift; sourceTree = "<group>"; };
|
CBB5F1FA2BFC3DB600CBF73A /* MPPositive_CollectionListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionListModel.swift; sourceTree = "<group>"; };
|
||||||
CBB5F1FC2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionArtistModel.swift; sourceTree = "<group>"; };
|
CBB5F1FC2BFC40E400CBF73A /* MPPositive_CollectionArtistModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CollectionArtistModel.swift; sourceTree = "<group>"; };
|
||||||
|
CBB5F1FE2BFCB40000CBF73A /* MPPositive_Debouncer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_Debouncer.swift; sourceTree = "<group>"; };
|
||||||
CBB75B0A2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_DownloadItemModel.swift; sourceTree = "<group>"; };
|
CBB75B0A2BEF0BC400B3FF9A /* MPPositive_DownloadItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_DownloadItemModel.swift; sourceTree = "<group>"; };
|
||||||
CBB9F9DC2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_JsonLyrics.swift; sourceTree = "<group>"; };
|
CBB9F9DC2BEDCFEE008338DE /* MPPositive_JsonLyrics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_JsonLyrics.swift; sourceTree = "<group>"; };
|
||||||
CBB9F9DE2BEDDCC5008338DE /* MP_PlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_PlayerManager.swift; sourceTree = "<group>"; };
|
CBB9F9DE2BEDDCC5008338DE /* MP_PlayerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_PlayerManager.swift; sourceTree = "<group>"; };
|
||||||
@ -964,6 +966,7 @@
|
|||||||
CBCB32192BD7578500802900 /* MP_LocationManager.swift */,
|
CBCB32192BD7578500802900 /* MP_LocationManager.swift */,
|
||||||
CBBFA9172BBA83BA00057FD5 /* MP_CoreDataHandlerManager.swift */,
|
CBBFA9172BBA83BA00057FD5 /* MP_CoreDataHandlerManager.swift */,
|
||||||
CBE2C4C62BC783F700F283A7 /* MP_HUD.swift */,
|
CBE2C4C62BC783F700F283A7 /* MP_HUD.swift */,
|
||||||
|
CBB5F1FE2BFCB40000CBF73A /* MPPositive_Debouncer.swift */,
|
||||||
CBC687482BC2882B0023ECA6 /* MPTableManager.swift */,
|
CBC687482BC2882B0023ECA6 /* MPTableManager.swift */,
|
||||||
CBD958D12BB6600500666B0D /* MP_PlayerSlider.swift */,
|
CBD958D12BB6600500666B0D /* MP_PlayerSlider.swift */,
|
||||||
CB102F532BFAFA7200E967D8 /* MP_CircularProgressView.swift */,
|
CB102F532BFAFA7200E967D8 /* MP_CircularProgressView.swift */,
|
||||||
@ -1172,6 +1175,7 @@
|
|||||||
CB102F522BFAE73800E967D8 /* MPPositive_JsonRecommend.swift in Sources */,
|
CB102F522BFAE73800E967D8 /* MPPositive_JsonRecommend.swift in Sources */,
|
||||||
CBCB4FEF2BD11402009760B3 /* MPSideA_NavigationController.swift in Sources */,
|
CBCB4FEF2BD11402009760B3 /* MPSideA_NavigationController.swift in Sources */,
|
||||||
CBF456DD2BF1E72F00ABF761 /* MPPositive_SearchResultListViewModel.swift in Sources */,
|
CBF456DD2BF1E72F00ABF761 /* MPPositive_SearchResultListViewModel.swift in Sources */,
|
||||||
|
CBB5F1FF2BFCB40000CBF73A /* MPPositive_Debouncer.swift in Sources */,
|
||||||
CBEB01832BF5D88400D45006 /* MPPositive_ArtistShowCollectionViewCell.swift in Sources */,
|
CBEB01832BF5D88400D45006 /* MPPositive_ArtistShowCollectionViewCell.swift in Sources */,
|
||||||
CBD5E80C2BF33D0200A3EBED /* MPPositive_SearchResultTypeShowView.swift in Sources */,
|
CBD5E80C2BF33D0200A3EBED /* MPPositive_SearchResultTypeShowView.swift in Sources */,
|
||||||
CBCB35212BD7ACE900802900 /* MPPositive_JsonBrowse.swift in Sources */,
|
CBCB35212BD7ACE900802900 /* MPPositive_JsonBrowse.swift in Sources */,
|
||||||
|
|||||||
@ -49,6 +49,18 @@
|
|||||||
ReferencedContainer = "container:MusicPlayer.xcodeproj">
|
ReferencedContainer = "container:MusicPlayer.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
|
<EnvironmentVariables>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "IDERedirectionPolicy"
|
||||||
|
value = "oslogToStdio"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
<EnvironmentVariable
|
||||||
|
key = "OS_ACTIVITY_MODE"
|
||||||
|
value = "disable"
|
||||||
|
isEnabled = "YES">
|
||||||
|
</EnvironmentVariable>
|
||||||
|
</EnvironmentVariables>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import CoreData
|
import CoreData
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
|
import Alamofire
|
||||||
@_exported import IQKeyboardManagerSwift
|
@_exported import IQKeyboardManagerSwift
|
||||||
@UIApplicationMain
|
@UIApplicationMain
|
||||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
@ -22,6 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
setAudioSupport()
|
setAudioSupport()
|
||||||
|
MP_NetWorkManager.shared.requestStatusToYouTube()
|
||||||
IQKeyboardManager.shared.enable = true
|
IQKeyboardManager.shared.enable = true
|
||||||
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
|
IQKeyboardManager.shared.shouldResignOnTouchOutside = true
|
||||||
window = UIWindow(frame: UIScreen.main.bounds)
|
window = UIWindow(frame: UIScreen.main.bounds)
|
||||||
@ -91,7 +93,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
|||||||
window?.rootViewController = tabBarVC
|
window?.rootViewController = tabBarVC
|
||||||
window?.makeKeyAndVisible()
|
window?.makeKeyAndVisible()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Core Data stack
|
// MARK: - Core Data stack
|
||||||
lazy var persistentContainer: NSPersistentContainer = {
|
lazy var persistentContainer: NSPersistentContainer = {
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -83,6 +83,10 @@ extension NotificationCenter{
|
|||||||
case player_type_switch
|
case player_type_switch
|
||||||
///用户清空了歌单
|
///用户清空了歌单
|
||||||
case player_delete_list
|
case player_delete_list
|
||||||
|
///网络状态切换-网络不可用
|
||||||
|
case net_switch_notReachable
|
||||||
|
///网络状态切换-网络可用
|
||||||
|
case net_switch_reachable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
MusicPlayer/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift
Normal file
33
MusicPlayer/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// MPPositive_Debouncer.swift
|
||||||
|
// MusicPlayer
|
||||||
|
//
|
||||||
|
// Created by Mr.Zhou on 2024/5/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class MPPositive_Debouncer: NSObject {
|
||||||
|
static let shared = MPPositive_Debouncer()
|
||||||
|
//计时器
|
||||||
|
private var timer: Timer?
|
||||||
|
//计时值
|
||||||
|
private var delay: TimeInterval
|
||||||
|
|
||||||
|
private override init() {
|
||||||
|
delay = 0.4
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
deinit {
|
||||||
|
timer?.invalidate()
|
||||||
|
timer = nil
|
||||||
|
}
|
||||||
|
func call(_ action:@escaping (() -> Void)) {
|
||||||
|
// 取消之前的延迟调用
|
||||||
|
timer?.invalidate()
|
||||||
|
// 设置新的延迟调用
|
||||||
|
timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { _ in
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,30 @@ class MP_NetWorkManager: NSObject {
|
|||||||
private let search = "/search"
|
private let search = "/search"
|
||||||
///YouTuBe资源键值
|
///YouTuBe资源键值
|
||||||
private let youTubeKeys:[String] = ["MUSIC_VIDEO_TYPE_ATV","MUSIC_VIDEO_TYPE_OMV","MUSIC_PAGE_TYPE_ALBUM","MUSIC_PAGE_TYPE_ARTIST","MUSIC_PAGE_TYPE_PLAYLIST","MUSIC_PAGE_TYPE_TRACK_LYRICS","MUSIC_PAGE_TYPE_TRACK_RELATED"]
|
private let youTubeKeys:[String] = ["MUSIC_VIDEO_TYPE_ATV","MUSIC_VIDEO_TYPE_OMV","MUSIC_PAGE_TYPE_ALBUM","MUSIC_PAGE_TYPE_ARTIST","MUSIC_PAGE_TYPE_PLAYLIST","MUSIC_PAGE_TYPE_TRACK_LYRICS","MUSIC_PAGE_TYPE_TRACK_RELATED"]
|
||||||
|
//网络状态
|
||||||
|
enum NetWorkStatus: String {
|
||||||
|
case notReachable = "网络不可用"
|
||||||
|
case unknown = "网络未知"
|
||||||
|
case reachable = "网络可用"
|
||||||
|
}
|
||||||
|
///网络监听器
|
||||||
|
private let reachabilityManager:NetworkReachabilityManager = NetworkReachabilityManager(host: "https://music.youtube.com/")!
|
||||||
|
///当前网络状态
|
||||||
|
var netWorkStatu:NetWorkStatus!{
|
||||||
|
willSet{
|
||||||
|
//旧值为网络可用,新值为网络不可用,为断网第一时间,发出通知告知播放器
|
||||||
|
if netWorkStatu == .reachable, newValue == .notReachable {
|
||||||
|
print("网络不可用")
|
||||||
|
NotificationCenter.notificationKey.post(notificationName: .net_switch_notReachable)
|
||||||
|
}
|
||||||
|
//旧值为网络不可用,新值为网络可用,为网络回复第一时间,发出通知告知播放器
|
||||||
|
if (netWorkStatu == .notReachable), newValue == .reachable {
|
||||||
|
print("网络可用")
|
||||||
|
NotificationCenter.notificationKey.post(notificationName: .net_switch_reachable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - 固定参数
|
//MARK: - 固定参数
|
||||||
//访问数据(首次首页预览时获得)
|
//访问数据(首次首页预览时获得)
|
||||||
private var visitorData:String?
|
private var visitorData:String?
|
||||||
@ -133,21 +157,17 @@ class MP_NetWorkManager: NSObject {
|
|||||||
monitor.start(queue: queue)
|
monitor.start(queue: queue)
|
||||||
}
|
}
|
||||||
///网络请求检测
|
///网络请求检测
|
||||||
private func requestStatusToYouTube(_ isAilable:@escaping(Bool) -> Void) {
|
func requestStatusToYouTube() {
|
||||||
//设置一个节点
|
|
||||||
let reachabilityManager = NetworkReachabilityManager(host: "https://music.youtube.com/")
|
|
||||||
//通过ping节点确认是否能执行网络请求
|
//通过ping节点确认是否能执行网络请求
|
||||||
reachabilityManager?.startListening(onUpdatePerforming: { status in
|
reachabilityManager.startListening(onQueue: .main, onUpdatePerforming: { [weak self] status in
|
||||||
|
guard let self = self else {return}
|
||||||
switch status {
|
switch status {
|
||||||
case .unknown://未知状况
|
case .unknown://未知状况
|
||||||
isAilable(false)
|
netWorkStatu = .unknown
|
||||||
print("网络情况未知")
|
|
||||||
case .notReachable://网络不可用
|
case .notReachable://网络不可用
|
||||||
isAilable(false)
|
netWorkStatu = .notReachable
|
||||||
print("网络不可用")
|
|
||||||
case .reachable(.ethernetOrWiFi), .reachable(.cellular)://网络可用,且做出了分类
|
case .reachable(.ethernetOrWiFi), .reachable(.cellular)://网络可用,且做出了分类
|
||||||
//网络可用
|
netWorkStatu = .reachable
|
||||||
isAilable(true)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -189,11 +209,8 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostHomeBrowse(url, parameters: parameters)
|
||||||
self.requestPostHomeBrowse(url, parameters: parameters)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -255,12 +272,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostAlbumOrList(url, parameters: parameters) { results in
|
||||||
self.requestPostAlbumOrList(url, parameters: parameters) { results in
|
comletion(results)
|
||||||
comletion(results)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求列表/专辑数据
|
//请求列表/专辑数据
|
||||||
@ -315,12 +329,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostArtist(url, parameters: parameters) { result in
|
||||||
self.requestPostArtist(url, parameters: parameters) { result in
|
comletion(result)
|
||||||
comletion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求艺术家信息
|
//请求艺术家信息
|
||||||
@ -374,12 +385,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostArtistMore(url, parameters: parameters) { result in
|
||||||
self.requestPostArtistMore(url, parameters: parameters) { result in
|
comletion(result)
|
||||||
comletion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///请求艺术家更多数据
|
///请求艺术家更多数据
|
||||||
@ -430,12 +438,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostArtistMoreContinuation(url, parameters: parameters) { result in
|
||||||
self.requestPostArtistMoreContinuation(url, parameters: parameters) { result in
|
comletion(result)
|
||||||
comletion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///请求艺术家更多数据继续
|
///请求艺术家更多数据继续
|
||||||
@ -487,14 +492,10 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostNextList(url, parameters: parameters) { listSongs in
|
||||||
//发送next列表请求
|
//成功拿到列表所有歌曲(内容尚不完善)
|
||||||
self.requestPostNextList(url, parameters: parameters) { listSongs in
|
completion(listSongs)
|
||||||
//成功拿到列表所有歌曲(内容尚不完善)
|
|
||||||
completion(listSongs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求next列表
|
//请求next列表
|
||||||
@ -542,13 +543,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostNextLyricsAndRelated(url, parameters: parameters) { result in
|
||||||
//发送next列表歌词/相关内容请求
|
completion(result)
|
||||||
self.requestPostNextLyricsAndRelated(url, parameters: parameters) { result in
|
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求请求Next歌词/相关内容
|
//请求请求Next歌词/相关内容
|
||||||
@ -596,12 +593,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostPlayer(url, parameters: parameters){ resourceUlrs, coverUrls in
|
||||||
self.requestPostPlayer(url, parameters: parameters){ resourceUlrs, coverUrls in
|
completion(resourceUlrs, coverUrls)
|
||||||
completion(resourceUlrs, coverUrls)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求单曲/视频
|
//请求单曲/视频
|
||||||
@ -651,12 +645,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostLyric(url, parameters: parameters) { lyrics in
|
||||||
self.requestPostLyric(url, parameters: parameters) { lyrics in
|
completion(lyrics)
|
||||||
completion(lyrics)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求歌词
|
//请求歌词
|
||||||
@ -701,12 +692,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostRecommend(url, parameters: parameters) { results in
|
||||||
self.requestPostRecommend(url, parameters: parameters) { results in
|
completion(results)
|
||||||
completion(results)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///请求相关内容
|
///请求相关内容
|
||||||
@ -757,12 +745,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostSearchSuggestions(url, parameters: parameters) { result in
|
||||||
self.requestPostSearchSuggestions(url, parameters: parameters) { result in
|
completion(result)
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求搜索建议
|
//请求搜索建议
|
||||||
@ -811,12 +796,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostSearchPreviewResults(url, parameters: parameters) { result in
|
||||||
self.requestPostSearchPreviewResults(url, parameters: parameters) { result in
|
completion(result)
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求搜索预览结果
|
//请求搜索预览结果
|
||||||
@ -871,12 +853,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostSearchTypeResults(url, parameters: parameters) { result in
|
||||||
self.requestPostSearchTypeResults(url, parameters: parameters) { result in
|
completion(result)
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求搜索分类结果
|
//请求搜索分类结果
|
||||||
@ -931,12 +910,9 @@ extension MP_NetWorkManager {
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
requestStatusToYouTube { isAvailable in
|
guard netWorkStatu != .notReachable else {return}
|
||||||
if isAvailable == true {
|
requestPostSearchTypeContinuation(url, parameters: parameters) { result in
|
||||||
self.requestPostSearchTypeContinuation(url, parameters: parameters) { result in
|
completion(result)
|
||||||
completion(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//请求搜索分类继续结果
|
//请求搜索分类继续结果
|
||||||
|
|||||||
@ -103,7 +103,10 @@ class MP_PlayerManager:NSObject{
|
|||||||
super.init()
|
super.init()
|
||||||
// 添加观察者,监听播放结束事件
|
// 添加观察者,监听播放结束事件
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(_ :)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
|
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying(_ :)), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
|
||||||
|
//监听用户切换了音乐
|
||||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(userSwitchCurrentVideoAction(_ :)), notificationName: .positive_player_reload)
|
NotificationCenter.notificationKey.add(observer: self, selector: #selector(userSwitchCurrentVideoAction(_ :)), notificationName: .positive_player_reload)
|
||||||
|
//监听网络状态恢复可用
|
||||||
|
NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_ :)), notificationName: .net_switch_reachable)
|
||||||
}
|
}
|
||||||
deinit {
|
deinit {
|
||||||
NotificationCenter.default.removeObserver(self)
|
NotificationCenter.default.removeObserver(self)
|
||||||
@ -160,7 +163,24 @@ class MP_PlayerManager:NSObject{
|
|||||||
loadPlayer.currentVideo?.resourcePlayerItem?.addObserver(self, forKeyPath: "status", options: [.old,.new], context: nil)
|
loadPlayer.currentVideo?.resourcePlayerItem?.addObserver(self, forKeyPath: "status", options: [.old,.new], context: nil)
|
||||||
//当前缓冲值
|
//当前缓冲值
|
||||||
loadPlayer.currentVideo?.resourcePlayerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: [.old,.new], context: nil)
|
loadPlayer.currentVideo?.resourcePlayerItem.addObserver(self, forKeyPath: "loadedTimeRanges", options: [.old,.new], context: nil)
|
||||||
|
//是否具备足够播放的能力
|
||||||
|
loadPlayer.currentVideo?.resourcePlayerItem.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: [.old,.new], context: nil)
|
||||||
|
//启动全部预加载
|
||||||
|
loadPlayer.listViewVideos.forEach({$0.preloadAsset($0.resourceAsset)})
|
||||||
}
|
}
|
||||||
|
///网络状态恢复正常
|
||||||
|
@objc private func netWorkReachableAction(_ sender:Notification) {
|
||||||
|
//监听到网络状态恢复,检索当前播放器是否正在播放
|
||||||
|
if loadPlayer?.currentVideo != nil {
|
||||||
|
//有音乐播放,获取当前播放进度
|
||||||
|
let currentTime = loadPlayer.currentVideo!.resourcePlayerItem.currentTime()
|
||||||
|
//手动调整播放时间点,以此重启播放器缓存
|
||||||
|
player.seek(to: currentTime)
|
||||||
|
player.play()
|
||||||
|
playState = .Playing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//实现KVO监听
|
//实现KVO监听
|
||||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||||
guard let keyPath = keyPath else {
|
guard let keyPath = keyPath else {
|
||||||
@ -174,14 +194,6 @@ class MP_PlayerManager:NSObject{
|
|||||||
if playState != .Playing {
|
if playState != .Playing {
|
||||||
//当statuVlaue值等于playerItem准备播放的值,说明已经准备好播放
|
//当statuVlaue值等于playerItem准备播放的值,说明已经准备好播放
|
||||||
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 已经准备好播放")
|
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 已经准备好播放")
|
||||||
//还未播放当前音乐,启动播放
|
|
||||||
print("开始播放音乐-\(loadPlayer.currentVideo?.title ?? "")")
|
|
||||||
player.play()
|
|
||||||
playState = .Playing
|
|
||||||
//执行开始播放闭包
|
|
||||||
if startActionBlock != nil {
|
|
||||||
startActionBlock!()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else {
|
}else {
|
||||||
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 未做好准备播放,失败原因是\(loadPlayer.currentVideo?.resourcePlayerItem.error?.localizedDescription ?? "")")
|
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 未做好准备播放,失败原因是\(loadPlayer.currentVideo?.resourcePlayerItem.error?.localizedDescription ?? "")")
|
||||||
@ -211,7 +223,21 @@ class MP_PlayerManager:NSObject{
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "playbackLikelyToKeepUp"://是否存在足够的数据开始播放
|
case "playbackLikelyToKeepUp"://是否存在足够的数据开始播放
|
||||||
break
|
if let playbackLikelyToKeepUp = change?[.newKey] as? Bool, playbackLikelyToKeepUp == true {
|
||||||
|
if playState != .Playing {
|
||||||
|
//还未播放当前音乐,启动播放
|
||||||
|
player.play()
|
||||||
|
playState = .Playing
|
||||||
|
//执行开始播放闭包
|
||||||
|
if startActionBlock != nil {
|
||||||
|
startActionBlock!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
//没有足够的数据支持播放
|
||||||
|
player.pause()
|
||||||
|
playState = .Null
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -324,7 +350,7 @@ class MP_PlayerManager:NSObject{
|
|||||||
switch playType {
|
switch playType {
|
||||||
case .random://随机,播放随机列表内容
|
case .random://随机,播放随机列表内容
|
||||||
for (index, item) in loadPlayer.randomVideos.enumerated() {
|
for (index, item) in loadPlayer.randomVideos.enumerated() {
|
||||||
if item.videoId == loadPlayer.currentVideo.song.videoId {
|
if item.videoId == loadPlayer.currentVideo?.song.videoId {
|
||||||
//找到播放音乐的索引
|
//找到播放音乐的索引
|
||||||
nextIndex = index - 1
|
nextIndex = index - 1
|
||||||
}
|
}
|
||||||
@ -333,15 +359,15 @@ class MP_PlayerManager:NSObject{
|
|||||||
if nextIndex < 0 {
|
if nextIndex < 0 {
|
||||||
//播放列表最后一首
|
//播放列表最后一首
|
||||||
let last = loadPlayer.randomVideos.last
|
let last = loadPlayer.randomVideos.last
|
||||||
loadPlayer.improveData(last?.videoId ?? "")
|
loadPlayer.improveData(last?.videoId ?? "", isRandom: true)
|
||||||
}else {
|
}else {
|
||||||
//查询列表对应单曲
|
//查询列表对应单曲
|
||||||
let song = loadPlayer.randomVideos[nextIndex]
|
let song = loadPlayer.randomVideos[nextIndex]
|
||||||
loadPlayer.improveData(song.videoId ?? "")
|
loadPlayer.improveData(song.videoId ?? "", isRandom: true)
|
||||||
}
|
}
|
||||||
default://常规播放或者单曲播放
|
default://常规播放或者单曲播放
|
||||||
for (index, item) in loadPlayer.songVideos.enumerated() {
|
for (index, item) in loadPlayer.songVideos.enumerated() {
|
||||||
if item.videoId == loadPlayer.currentVideo.song.videoId {
|
if item.videoId == loadPlayer.currentVideo?.song.videoId {
|
||||||
//找到播放音乐的索引
|
//找到播放音乐的索引
|
||||||
nextIndex = index - 1
|
nextIndex = index - 1
|
||||||
}
|
}
|
||||||
@ -366,7 +392,7 @@ class MP_PlayerManager:NSObject{
|
|||||||
switch playType {
|
switch playType {
|
||||||
case .random:
|
case .random:
|
||||||
for (index, item) in loadPlayer.randomVideos.enumerated() {
|
for (index, item) in loadPlayer.randomVideos.enumerated() {
|
||||||
if item.videoId == loadPlayer.currentVideo.song.videoId {
|
if item.videoId == loadPlayer.currentVideo?.song.videoId {
|
||||||
//找到播放音乐的索引
|
//找到播放音乐的索引
|
||||||
nextIndex = index + 1
|
nextIndex = index + 1
|
||||||
}
|
}
|
||||||
@ -375,15 +401,15 @@ class MP_PlayerManager:NSObject{
|
|||||||
if nextIndex > (loadPlayer.randomVideos.count-1) {
|
if nextIndex > (loadPlayer.randomVideos.count-1) {
|
||||||
//播放列表第一首
|
//播放列表第一首
|
||||||
let first = loadPlayer.randomVideos.first
|
let first = loadPlayer.randomVideos.first
|
||||||
loadPlayer.improveData(first?.videoId ?? "")
|
loadPlayer.improveData(first?.videoId ?? "", isRandom: true)
|
||||||
}else {
|
}else {
|
||||||
//存在下一首,获取下一首ID,并播放
|
//存在下一首,获取下一首ID,并播放
|
||||||
let song = loadPlayer.randomVideos[nextIndex]
|
let song = loadPlayer.randomVideos[nextIndex]
|
||||||
loadPlayer.improveData(song.videoId ?? "")
|
loadPlayer.improveData(song.videoId ?? "", isRandom: true)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
for (index, item) in loadPlayer.songVideos.enumerated() {
|
for (index, item) in loadPlayer.songVideos.enumerated() {
|
||||||
if item.videoId == loadPlayer.currentVideo.song.videoId {
|
if item.videoId == loadPlayer.currentVideo?.song.videoId {
|
||||||
//找到播放音乐的索引
|
//找到播放音乐的索引
|
||||||
nextIndex = index + 1
|
nextIndex = index + 1
|
||||||
}
|
}
|
||||||
@ -411,7 +437,10 @@ class MP_PlayerManager:NSObject{
|
|||||||
//切歌时移除KVO监听
|
//切歌时移除KVO监听
|
||||||
video.resourcePlayerItem.removeObserver(self, forKeyPath: "status")
|
video.resourcePlayerItem.removeObserver(self, forKeyPath: "status")
|
||||||
video.resourcePlayerItem.removeObserver(self, forKeyPath: "loadedTimeRanges")
|
video.resourcePlayerItem.removeObserver(self, forKeyPath: "loadedTimeRanges")
|
||||||
// video.resourcePlayerItem.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
|
video.resourcePlayerItem.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
|
||||||
|
}
|
||||||
|
if cacheValueBlock != nil {
|
||||||
|
cacheValueBlock!(0, 1)
|
||||||
}
|
}
|
||||||
if loadPlayer.currentVideo != nil {
|
if loadPlayer.currentVideo != nil {
|
||||||
//开始播放
|
//开始播放
|
||||||
|
|||||||
@ -33,13 +33,19 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
var song:MPPositive_SongItemModel!
|
var song:MPPositive_SongItemModel!
|
||||||
///是否进行过预加载
|
///是否进行过预加载
|
||||||
var isPloading:Bool = false
|
var isPloading:Bool = false
|
||||||
|
// 标记为已取消
|
||||||
|
private var isCancelled = false
|
||||||
init(_ song:MPPositive_SongItemModel) {
|
init(_ song:MPPositive_SongItemModel) {
|
||||||
super.init()
|
super.init()
|
||||||
self.song = song
|
self.song = song
|
||||||
configure()
|
configure()
|
||||||
}
|
}
|
||||||
deinit {
|
deinit {
|
||||||
|
//释放内存
|
||||||
|
resourcePlayerItem = nil
|
||||||
|
resourceAsset = nil
|
||||||
|
isCancelled = true
|
||||||
|
print("\(title ?? "")被释放了")
|
||||||
}
|
}
|
||||||
//数据配置
|
//数据配置
|
||||||
private func configure() {
|
private func configure() {
|
||||||
@ -76,9 +82,9 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
}
|
}
|
||||||
reloadCollectionAndDownLoad()
|
reloadCollectionAndDownLoad()
|
||||||
//执行预加载
|
//执行预加载
|
||||||
if isPloading == false {
|
// if isPloading == false {
|
||||||
preloadAsset(resourceAsset)
|
// preloadAsset(resourceAsset)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
//页面状态更新
|
//页面状态更新
|
||||||
func reloadCollectionAndDownLoad() {
|
func reloadCollectionAndDownLoad() {
|
||||||
@ -91,12 +97,19 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
|
|
||||||
//执行预加载
|
//执行预加载
|
||||||
func preloadAsset(_ asset:AVURLAsset) {
|
func preloadAsset(_ asset:AVURLAsset) {
|
||||||
|
guard isPloading == false else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.isPloading = true
|
||||||
//执行预加载
|
//执行预加载
|
||||||
if #available(iOS 16, *) {
|
if #available(iOS 16, *) {
|
||||||
//ios16以上的情况
|
//ios16以上的情况
|
||||||
Task{
|
Task{
|
||||||
do{
|
do{
|
||||||
let playable = try await asset.load(.isPlayable)
|
let playable = try await asset.load(.isPlayable)
|
||||||
|
guard !isCancelled else {
|
||||||
|
return
|
||||||
|
}
|
||||||
if playable == true {
|
if playable == true {
|
||||||
print("\(self.title ?? "")预加载成功")
|
print("\(self.title ?? "")预加载成功")
|
||||||
self.isPloading = true
|
self.isPloading = true
|
||||||
@ -105,8 +118,9 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
switch asset.status(of: .isPlayable) {
|
switch asset.status(of: .isPlayable) {
|
||||||
case .failed(let erro):
|
case .failed(let erro):
|
||||||
print("\(title ?? "")预加载失败,失败原因:\(erro.localizedDescription)")
|
print("\(title ?? "")预加载失败,失败原因:\(erro.localizedDescription)")
|
||||||
|
self.isPloading = false
|
||||||
default:
|
default:
|
||||||
break
|
self.isPloading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}catch{
|
}catch{
|
||||||
@ -118,7 +132,7 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
let keys = ["playable"]
|
let keys = ["playable"]
|
||||||
asset.loadValuesAsynchronously(forKeys: keys) {
|
asset.loadValuesAsynchronously(forKeys: keys) {
|
||||||
[weak self] in
|
[weak self] in
|
||||||
guard let self = self else {return}
|
guard let self = self, !isCancelled else {return}
|
||||||
for key in keys {
|
for key in keys {
|
||||||
var error: NSError? = nil
|
var error: NSError? = nil
|
||||||
let status = asset.statusOfValue(forKey: key, error: &error)
|
let status = asset.statusOfValue(forKey: key, error: &error)
|
||||||
@ -131,8 +145,10 @@ class MPPositive_SongViewModel: NSObject {
|
|||||||
}
|
}
|
||||||
case .failed:
|
case .failed:
|
||||||
print("\(title ?? "")预加载失败,失败原因:\(error?.localizedDescription ?? "")")
|
print("\(title ?? "")预加载失败,失败原因:\(error?.localizedDescription ?? "")")
|
||||||
|
self.isPloading = false
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
print("\(title ?? "")预加载被取消了")
|
print("\(title ?? "")预加载被取消了")
|
||||||
|
self.isPloading = false
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,9 +26,8 @@ class MPPositive_PlayerLoadViewModel: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
///当前播放音乐ID
|
|
||||||
var currentVideoId:String!
|
///单曲播放队列ViewModel
|
||||||
///单曲ViewModel列表
|
|
||||||
var listViewVideos:[MPPositive_SongViewModel]!
|
var listViewVideos:[MPPositive_SongViewModel]!
|
||||||
///异步请求组
|
///异步请求组
|
||||||
var group:DispatchGroup?
|
var group:DispatchGroup?
|
||||||
@ -42,26 +41,42 @@ class MPPositive_PlayerLoadViewModel: NSObject {
|
|||||||
//根据列表生成一份随机播放列表
|
//根据列表生成一份随机播放列表
|
||||||
self.randomVideos = self.songVideos.shuffled()
|
self.randomVideos = self.songVideos.shuffled()
|
||||||
self.listViewVideos = []
|
self.listViewVideos = []
|
||||||
self.currentVideoId = currentVideoId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///将选中Video的上下2项包括本身总计3项Video进行补全转为ViewModel,并播放这首音乐
|
///将选中Video的上下2项包括本身总计3项Video进行补全转为ViewModel,并播放这首音乐
|
||||||
func improveData(_ targetVideoId:String) {
|
func improveData(_ targetVideoId:String, isRandom:Bool = false) {
|
||||||
//获取targetVideoId的索引
|
|
||||||
guard let targetIndex = self.songVideos.firstIndex(where: {$0.videoId == targetVideoId}) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//对于选中Video的集合
|
//对于选中Video的集合
|
||||||
var array:[MPPositive_SongItemModel] = []
|
var array:[MPPositive_SongItemModel] = []
|
||||||
array.append(self.songVideos[targetIndex])
|
if isRandom {
|
||||||
//获取上一位
|
//获取targetVideoId的索引
|
||||||
let previousIndex = targetIndex-1
|
guard let targetIndex = self.randomVideos.firstIndex(where: {$0.videoId == targetVideoId}) else {
|
||||||
if previousIndex >= 0 {
|
return
|
||||||
array.append(self.songVideos[previousIndex])
|
}
|
||||||
}
|
array.append(self.randomVideos[targetIndex])
|
||||||
let nextIndex = targetIndex+1
|
//获取上一位
|
||||||
if nextIndex < songVideos.count {
|
let previousIndex = targetIndex-1
|
||||||
array.append(self.songVideos[nextIndex])
|
if previousIndex >= 0 {
|
||||||
|
array.append(self.randomVideos[previousIndex])
|
||||||
|
}
|
||||||
|
let nextIndex = targetIndex+1
|
||||||
|
if nextIndex < randomVideos.count {
|
||||||
|
array.append(self.randomVideos[nextIndex])
|
||||||
|
}
|
||||||
|
}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
|
||||||
|
if nextIndex < songVideos.count {
|
||||||
|
array.append(self.songVideos[nextIndex])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//获取完成,优先检索ViewModel,看看是否已存在补完video
|
//获取完成,优先检索ViewModel,看看是否已存在补完video
|
||||||
let videoIDs = Set(listViewVideos.map({$0.song.videoId}))
|
let videoIDs = Set(listViewVideos.map({$0.song.videoId}))
|
||||||
@ -89,11 +104,12 @@ class MPPositive_PlayerLoadViewModel: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
group?.notify(queue: .main, execute: {
|
group?.notify(queue: .main, execute: {
|
||||||
//补完转化完毕,重新排序
|
[weak self] in
|
||||||
self.listViewVideos = self.listViewVideos.sorted(by: {$0.index < $1.index})
|
//确定播放音乐
|
||||||
//排序完成,确定播放音乐
|
self?.currentVideo = self?.listViewVideos.first(where: {$0.song.videoId == targetVideoId})
|
||||||
self.currentVideo = self.listViewVideos.first(where: {$0.song.videoId == targetVideoId})
|
//只保留最后三首
|
||||||
self.group = nil
|
self?.listViewVideos = self?.listViewVideos.suffix(3)
|
||||||
|
self?.group = nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
///重新获取指定歌曲资源
|
///重新获取指定歌曲资源
|
||||||
|
|||||||
@ -308,7 +308,7 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont
|
|||||||
coverView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
|
coverView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
|
||||||
lyricsView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
|
lyricsView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
|
||||||
lyricsView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
|
lyricsView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
|
||||||
lyricsView.lyricsLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics ?? "No Lyrics"
|
lyricsView.lyricsLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics?.isEmpty == true ? "No Lyrics":MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics
|
||||||
coverView.loadBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false
|
coverView.loadBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false
|
||||||
coverView.collectionSongBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isCollection ?? false
|
coverView.collectionSongBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isCollection ?? false
|
||||||
}
|
}
|
||||||
@ -469,26 +469,38 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont
|
|||||||
}
|
}
|
||||||
//切换播放器状态(按顺序/随机/单曲)
|
//切换播放器状态(按顺序/随机/单曲)
|
||||||
@objc private func typeClick(_ sender:UIButton) {
|
@objc private func typeClick(_ sender:UIButton) {
|
||||||
//对播放器播放方式截形切换
|
MPPositive_Debouncer.shared.call {
|
||||||
var value = MP_PlayerManager.shared.getPlayType().rawValue
|
[weak self] in
|
||||||
value += 1
|
guard let self = self else {return}
|
||||||
if value > 2 {
|
//对播放器播放方式截形切换
|
||||||
value = 0
|
var value = MP_PlayerManager.shared.getPlayType().rawValue
|
||||||
|
value += 1
|
||||||
|
if value > 2 {
|
||||||
|
value = 0
|
||||||
|
}
|
||||||
|
MP_PlayerManager.shared.setPlayType(.init(rawValue: value)!)
|
||||||
}
|
}
|
||||||
MP_PlayerManager.shared.setPlayType(.init(rawValue: value)!)
|
|
||||||
}
|
}
|
||||||
//下一首
|
//下一首
|
||||||
@objc private func nextClick(_ sender:UIButton) {
|
@objc private func nextClick(_ sender:UIButton) {
|
||||||
coverView.sliderView.value = 0
|
MPPositive_Debouncer.shared.call {
|
||||||
playBtn.isUserInteractionEnabled = false
|
[weak self] in
|
||||||
MP_PlayerManager.shared.nextEvent()
|
guard let self = self else {return}
|
||||||
|
coverView.sliderView.value = 0
|
||||||
|
playBtn.isUserInteractionEnabled = false
|
||||||
|
MP_PlayerManager.shared.nextEvent()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
//上一首
|
//上一首
|
||||||
@objc private func previousClick(_ sender:UIButton) {
|
@objc private func previousClick(_ sender:UIButton) {
|
||||||
coverView.sliderView.value = 0
|
MPPositive_Debouncer.shared.call {
|
||||||
playBtn.isUserInteractionEnabled = false
|
[weak self] in
|
||||||
MP_PlayerManager.shared.previousEvent()
|
guard let self = self else {return}
|
||||||
|
coverView.sliderView.value = 0
|
||||||
|
playBtn.isUserInteractionEnabled = false
|
||||||
|
MP_PlayerManager.shared.previousEvent()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,21 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
lazy var durationLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.85), textAlignment: .left)
|
lazy var durationLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.85), textAlignment: .left)
|
||||||
///最大播放时间值Label
|
///最大播放时间值Label
|
||||||
lazy var maxTimesLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .right)
|
lazy var maxTimesLabel:UILabel = createLabel("00:00" ,font: .systemFont(ofSize: 12*width, weight: .medium), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .right)
|
||||||
|
///断网提醒View
|
||||||
|
private lazy var maskNotReachableView:UIView = {
|
||||||
|
let maskView = UIView()
|
||||||
|
maskView.backgroundColor = .init(hex: "#000000", alpha: 0.7)
|
||||||
|
maskView.layer.masksToBounds = true
|
||||||
|
maskView.layer.cornerRadius = 16*width
|
||||||
|
//放置一个label
|
||||||
|
let noticeLabel:UILabel = createLabel("The network connection is disconnected and the player will stop loading music. Please restore the network as soon as possible!", font: .systemFont(ofSize: 18, weight: .medium), textColor: .white, textAlignment: .center, lines: 0)
|
||||||
|
maskView.addSubview(noticeLabel)
|
||||||
|
noticeLabel.snp.makeConstraints { make in
|
||||||
|
make.center.equalToSuperview()
|
||||||
|
make.width.equalToSuperview().multipliedBy(0.7)
|
||||||
|
}
|
||||||
|
return maskView
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +80,12 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
configure()
|
configure()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//添加监听
|
||||||
|
NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkNotReachableAction(_:)), notificationName: .net_switch_notReachable)
|
||||||
|
NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_:)), notificationName: .net_switch_reachable)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -77,6 +98,7 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
// restoreDownloadProgress()
|
// restoreDownloadProgress()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func restoreDownloadProgress() {
|
public func restoreDownloadProgress() {
|
||||||
|
|
||||||
if let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo,
|
if let currentVideo = MP_PlayerManager.shared.loadPlayer.currentVideo,
|
||||||
@ -116,6 +138,11 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
NotificationCenter.default.removeObserver(self)
|
||||||
|
}
|
||||||
|
|
||||||
//视图配置
|
//视图配置
|
||||||
private func configure() {
|
private func configure() {
|
||||||
//配置封面图
|
//配置封面图
|
||||||
@ -126,6 +153,11 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
make.centerX.equalToSuperview()
|
make.centerX.equalToSuperview()
|
||||||
make.top.equalToSuperview().offset(12*width)
|
make.top.equalToSuperview().offset(12*width)
|
||||||
}
|
}
|
||||||
|
addSubview(maskNotReachableView)
|
||||||
|
maskNotReachableView.snp.makeConstraints { make in
|
||||||
|
make.left.right.top.bottom.equalTo(coverImageView)
|
||||||
|
}
|
||||||
|
maskNotReachableView.isHidden = true
|
||||||
//添加标题
|
//添加标题
|
||||||
addSubview(titleLabel)
|
addSubview(titleLabel)
|
||||||
titleLabel.snp.makeConstraints { make in
|
titleLabel.snp.makeConstraints { make in
|
||||||
@ -178,6 +210,23 @@ class MPPositive_PlayerCoverView: UIView {
|
|||||||
// 恢复进度
|
// 恢复进度
|
||||||
restoreDownloadProgress()
|
restoreDownloadProgress()
|
||||||
}
|
}
|
||||||
|
//网络不可用时触发
|
||||||
|
@objc private func netWorkNotReachableAction(_ sender:Notification) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
[weak self] in
|
||||||
|
guard let self = self else {return}
|
||||||
|
maskNotReachableView.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//网络可用时触发
|
||||||
|
@objc private func netWorkReachableAction(_ sender:Notification) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
[weak self] in
|
||||||
|
guard let self = self else {return}
|
||||||
|
maskNotReachableView.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//调整音乐进度
|
//调整音乐进度
|
||||||
@objc private func seekProgressClick(_ sender: UISlider, forEvent event: UIEvent) {
|
@objc private func seekProgressClick(_ sender: UISlider, forEvent event: UIEvent) {
|
||||||
//获取touchEvent
|
//获取touchEvent
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user