b面正式版-1.0.2

This commit is contained in:
Mr.zhou 2024-05-31 21:50:46 +08:00
parent 62deb230c0
commit 475a5d56c4
19 changed files with 390 additions and 280 deletions

View File

@ -1554,11 +1554,10 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MusicPlayer/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Musiclax;
INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "\"Musiclax\" requires you to turn on the microphone to recognize surrounding decibels and automatically turn on white noise for you. Do you allow this application to obtain your microphone permissions?";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "\"Musiclax\" requires opening your album to obtain photos, which are used to add your custom white noise. Do you want to allow this application to obtain your album permissions?";
INFOPLIST_KEY_NSUserTrackingUsageDescription = "\"Musiclax\" needs to request tracking permissions to provide a personalized advertising experience. We respect and protect your privacy and will not sell your data to third parties.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;
@ -1598,11 +1597,10 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = MusicPlayer/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Musiclax;
INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSLocationAlwaysUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "\"Musiclax\" needs to obtain your location information in order to refine the preview music information provided to you!";
INFOPLIST_KEY_NSMicrophoneUsageDescription = "\"Musiclax\" requires you to turn on the microphone to recognize surrounding decibels and automatically turn on white noise for you. Do you allow this application to obtain your microphone permissions?";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "\"Musiclax\" requires opening your album to obtain photos, which are used to add your custom white noise. Do you want to allow this application to obtain your album permissions?";
INFOPLIST_KEY_NSUserTrackingUsageDescription = "\"Musiclax\" needs to request tracking permissions to provide a personalized advertising experience. We respect and protect your privacy and will not sell your data to third parties.";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UIMainStoryboardFile = Main;

View File

@ -0,0 +1,22 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "img_v3_02bd_9660da3e-8f28-4628-863b-00379a5887ag 1.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "img_v3_02bd_9660da3e-8f28-4628-863b-00379a5887ag.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -4,12 +4,11 @@
<dict>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>audio</string>
<string>backgroundFetch</string>
<string>fetch</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSUserTrackingUsageDescription</key>
<string>&quot;Musiclax&quot; needs to request tracking permissions to provide a personalized advertising experience. We respect and protect your privacy and will not sell your data to third parties.</string>
</dict>
</plist>

View File

@ -31,8 +31,6 @@ class MP_LunchViewController: UIViewController {
timer.add(to: RunLoop.current, forMode: .common)
//idfa
_ = requestTrackingAuthorization(self)
//
MP_LocationManager.shared.setLocationPermission(self, complete: nil)
MP_AnalyticsManager.shared.getOpenStatus { [weak self] open in
guard let self = self else {return}
if open {

View File

@ -51,7 +51,7 @@ var app_Version:String{
///
let bottomPadding = UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0
///
let placeholderImage:UIImage = UIImage(named: "Home First'placeholder")!
let placeholderImage:UIImage = UIImage(named: "placeholder")!
///
let privacyUrl:URL = .init(string: "https://musiclax.mystrikingly.com/privacy")!
///
@ -167,7 +167,7 @@ func switchPlayTypeBtnIcon(_ btn:UIButton) {
}
}
///广
func requestTrackingAuthorization(_ observe:UIViewController) -> Bool {
func requestTrackingAuthorization(_ observe:UIViewController,max:Int = 0) -> Bool {
if #available(iOS 14, *) {
//
let status = ATTrackingManager.trackingAuthorizationStatus
@ -178,7 +178,10 @@ func requestTrackingAuthorization(_ observe:UIViewController) -> Bool {
ATTrackingManager.requestTrackingAuthorization { status in
let isAuthorized = status == .authorized
DispatchQueue.main.async {
_ = requestTrackingAuthorization(observe)
let new = max + 1
if new < 3 {
_ = requestTrackingAuthorization(observe, max: new)
}
}
}
case .authorized:

View File

@ -8,160 +8,160 @@
import Foundation
import CoreLocation
class MP_LocationManager: NSObject {
static let shared = MP_LocationManager()
var getAuthHandle: ((_ success: Bool) -> Void)?
//
private var locationManager: CLLocationManager!
//
private var location:String = "US"
override init() {
super.init()
locationManager = CLLocationManager()
// 3 kCLLocationAccuracyThreeKilometers
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.delegate = self
}
///
/// - Parameter complete:
func setLocationPermission(_ viewController:UIViewController ,complete:(() -> Void)?) {
if MP_LocationManager().hasLocationPermission() == true {
//
if complete != nil {
complete!()
}
}else {
//
switch MP_LocationManager().locationPermission() {
case .notDetermined:
MP_LocationManager().requestLocationAuthorizaiton()
case .restricted, .denied:
DispatchQueue.main.async {
let alertController = UIAlertController(title: "Location permission request", message: "“Musiclax” needs to obtain your location information in order to refine the preview music information provided to you!", preferredStyle: .alert)
let CancelAction = UIAlertAction(title:"Cancel", style: .cancel)
let OKAction = UIAlertAction(title: "Settings", style: .default) { (action) in
let url = URL(string: UIApplication.openSettingsURLString)
if let url = url,UIApplication.shared.canOpenURL(url){
if #available(iOS 10, *) {
UIApplication.shared.open(url, options:[:], completionHandler: nil)
}else{
UIApplication.shared.canOpenURL(url)
}
}
}
alertController.addAction(CancelAction)
alertController.addAction(OKAction)
viewController.present(alertController, animated: true, completion: nil)
}
default:
if complete != nil {
complete!()
}
}
}
}
///
fileprivate func hasLocationService() -> Bool {
return CLLocationManager.locationServicesEnabled()
}
/// APP
fileprivate func hasLocationPermission() -> Bool {
switch locationPermission() {
case .notDetermined, .restricted, .denied:
return false
case .authorizedWhenInUse, .authorizedAlways:
return true
default:
break
}
return false
}
///
fileprivate func locationPermission() -> CLAuthorizationStatus {
if #available(iOS 14.0, *) {
let status: CLAuthorizationStatus = locationManager.authorizationStatus
print("location authorizationStatus is \(status.rawValue)")
return status
} else {
let status = CLLocationManager.authorizationStatus()
print("location authorizationStatus is \(status.rawValue)")
return status
}
}
//MARK: - didChangeAuthorization
func requestLocationAuthorizaiton() {
locationManager.requestWhenInUseAuthorization()
}
//MARK: -
func requestLocation() -> String {
//
locationManager.requestLocation()
return location
}
}
extension MP_LocationManager: CLLocationManagerDelegate {
//MARK: - ios 14.0
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
handleChangedAuthorization()
}
//MARK: - ios 14.0
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
handleChangedAuthorization()
}
private func handleChangedAuthorization() {
if let block = getAuthHandle, locationPermission() != .notDetermined {
if hasLocationPermission() {
block(true)
} else {
block(false)
}
}
}
//MARK: -
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let loction = locations.last {
//
print("latitude: \(loction.coordinate.latitude) longitude:\(loction.coordinate.longitude)")
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(loction) { (placemarks, error) in
if let placemark = placemarks?.first {
//
if let area = placemark.administrativeArea, !area.isEmpty {
print("Area code: \(area)")
self.location = area
} else if let locality = placemark.locality, !locality.isEmpty {
print("Area code: \(locality)")
self.location = locality
} else if let country = placemark.country, !country.isEmpty {
print("Country code: \(country)")
self.location = country
}
}
if let error = error {
print("Reverse geocoding failure: \(error.localizedDescription)")
//US
self.location = "US"
return
}
}
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Reverse geocoding failure: \(error.localizedDescription)")
//US
self.location = "US"
}
}
//class MP_LocationManager: NSObject {
// static let shared = MP_LocationManager()
// var getAuthHandle: ((_ success: Bool) -> Void)?
// //
// private var locationManager: CLLocationManager!
// //
// private var location:String = "US"
// override init() {
// super.init()
// locationManager = CLLocationManager()
// // 3 kCLLocationAccuracyThreeKilometers
// locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
// locationManager.delegate = self
//
// }
//
// ///
// /// - Parameter complete:
// func setLocationPermission(_ viewController:UIViewController ,complete:(() -> Void)?) {
// if MP_LocationManager().hasLocationPermission() == true {
// //
// if complete != nil {
// complete!()
// }
// }else {
// //
// switch MP_LocationManager().locationPermission() {
// case .notDetermined:
// MP_LocationManager().requestLocationAuthorizaiton()
// case .restricted, .denied:
// DispatchQueue.main.async {
// let alertController = UIAlertController(title: "Location permission request", message: "Musiclax needs to obtain your location information in order to refine the preview music information provided to you!", preferredStyle: .alert)
// let CancelAction = UIAlertAction(title:"Cancel", style: .cancel)
// let OKAction = UIAlertAction(title: "Settings", style: .default) { (action) in
// let url = URL(string: UIApplication.openSettingsURLString)
// if let url = url,UIApplication.shared.canOpenURL(url){
// if #available(iOS 10, *) {
// UIApplication.shared.open(url, options:[:], completionHandler: nil)
// }else{
// UIApplication.shared.canOpenURL(url)
// }
// }
// }
// alertController.addAction(CancelAction)
// alertController.addAction(OKAction)
// viewController.present(alertController, animated: true, completion: nil)
// }
// default:
// if complete != nil {
// complete!()
// }
// }
// }
// }
//
// ///
// fileprivate func hasLocationService() -> Bool {
//
// return CLLocationManager.locationServicesEnabled()
//
// }
// /// APP
// fileprivate func hasLocationPermission() -> Bool {
//
// switch locationPermission() {
// case .notDetermined, .restricted, .denied:
// return false
// case .authorizedWhenInUse, .authorizedAlways:
// return true
// default:
// break
// }
// return false
// }
//
// ///
// fileprivate func locationPermission() -> CLAuthorizationStatus {
// if #available(iOS 14.0, *) {
// let status: CLAuthorizationStatus = locationManager.authorizationStatus
// print("location authorizationStatus is \(status.rawValue)")
// return status
// } else {
// let status = CLLocationManager.authorizationStatus()
// print("location authorizationStatus is \(status.rawValue)")
// return status
// }
// }
//
//
// //MARK: - didChangeAuthorization
// func requestLocationAuthorizaiton() {
// locationManager.requestWhenInUseAuthorization()
//
// }
// //MARK: -
// func requestLocation() -> String {
// //
// locationManager.requestLocation()
// return location
// }
//}
//extension MP_LocationManager: CLLocationManagerDelegate {
// //MARK: - ios 14.0
// func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
// handleChangedAuthorization()
// }
//
// //MARK: - ios 14.0
// func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
// handleChangedAuthorization()
// }
//
// private func handleChangedAuthorization() {
// if let block = getAuthHandle, locationPermission() != .notDetermined {
// if hasLocationPermission() {
// block(true)
// } else {
// block(false)
// }
// }
// }
// //MARK: -
// func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if let loction = locations.last {
// //
// print("latitude: \(loction.coordinate.latitude) longitude:\(loction.coordinate.longitude)")
// let geocoder = CLGeocoder()
// geocoder.reverseGeocodeLocation(loction) { (placemarks, error) in
// if let placemark = placemarks?.first {
// //
// if let area = placemark.administrativeArea, !area.isEmpty {
// print("Area code: \(area)")
// self.location = area
// } else if let locality = placemark.locality, !locality.isEmpty {
// print("Area code: \(locality)")
// self.location = locality
// } else if let country = placemark.country, !country.isEmpty {
// print("Country code: \(country)")
// self.location = country
// }
// }
// if let error = error {
// print("Reverse geocoding failure: \(error.localizedDescription)")
// //US
// self.location = "US"
// return
// }
// }
// }
// }
//
// func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// print("Reverse geocoding failure: \(error.localizedDescription)")
// //US
// self.location = "US"
// }
//}

View File

@ -40,7 +40,8 @@ class MP_NetWorkManager: NSObject {
///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"]
///IP
private let banIPs:[String] = ["CN",
private let banIPs:[String] = [
"CN",
"HK",
"TW",
"JP",
@ -49,7 +50,8 @@ class MP_NetWorkManager: NSObject {
"CH",
"BE",
"MO",
"SG"]
"SG"
]
//
enum NetWorkStatus: String {
case notReachable = "网络不可用"
@ -80,7 +82,7 @@ class MP_NetWorkManager: NSObject {
//
private lazy var currTimeDate:String = (Date().timeZone() - 7.days).toString(.custom("YYYYMMdd"))
///
private lazy var locaton:String = MP_LocationManager.shared.requestLocation()
private var locaton:String?
//
private var continuationAndItct:(String?,String?){
willSet{
@ -108,7 +110,7 @@ class MP_NetWorkManager: NSObject {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -214,10 +216,12 @@ extension MP_NetWorkManager {
return
}
if banIPs.contains(code) == true {
locaton = ""
//
completion(false)
}else {
//
locaton = code
completion(true)
}
case .failure(let error):
@ -260,7 +264,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -324,7 +328,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -381,7 +385,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -437,7 +441,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -490,7 +494,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -544,7 +548,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -595,7 +599,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -697,7 +701,7 @@ extension MP_NetWorkManager {
// //
// "hl":Language_first_local,
// //
// "gl":locaton
// "gl":locaton ?? ""
// ]
// ],
// "playbackContext": [
@ -754,7 +758,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -801,7 +805,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -854,7 +858,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -905,7 +909,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -962,7 +966,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -1019,7 +1023,7 @@ extension MP_NetWorkManager {
//
"hl":Language_first_local,
//
"gl":locaton
"gl":locaton ?? ""
]
]
]
@ -1591,7 +1595,7 @@ extension MP_NetWorkManager {
contents.forEach { content in
//
let item = MPPositive_BrowseItemModel()
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer {
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, (musicResponsiveListItemRenderer.playlistItemData != nil || musicResponsiveListItemRenderer.navigationEndpoint != nil) && (musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE"){
//
item.coverUrls = musicResponsiveListItemRenderer.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
@ -1614,7 +1618,7 @@ extension MP_NetWorkManager {
///
item.browseId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
let pageType = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true {
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = musicResponsiveListItemRenderer.navigationEndpoint?.browseEndpoint?.browseId
@ -1627,7 +1631,7 @@ extension MP_NetWorkManager {
}
}
}
if item.title != nil && item.itemType != nil {
if item.title != nil && item.itemType != nil, item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
resultList.previewItemViews.append(.init(item))
}
}
@ -1643,6 +1647,72 @@ extension MP_NetWorkManager {
musicShelfRenderer.contents?.forEach({ content in
/////
let item = MPPositive_BrowseItemModel()
if (content.musicResponsiveListItemRenderer?.playlistItemData != nil || content.musicResponsiveListItemRenderer?.navigationEndpoint != nil) && (content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE") {
//
item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
if index == 0 {
//
item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
item.pageType = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.first?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
}else {
//
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
}
}
item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
//id
if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
//
item.itemType = .single
item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
}else {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
//
item.itemType = .artist
}else {
///
item.itemType = .list
}
}
}
}
if item.itemType != nil, item.title != nil, item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
resultList.previewItemViews.append(.init(item))
}
})
//queryparams
if let searchEndpoint = musicShelfRenderer.bottomEndpoint?.searchEndpoint {
resultList.query = searchEndpoint.query
resultList.params = searchEndpoint.params
}
}
resultListSections.append(resultList)
}
resultListSections.forEach { list in
list.previewItemViews = list.previewItemViews.filter({ item in
return item.item.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE"
})
}
resultListSections = resultListSections.filter({$0.previewItemViews.count != 0})
return resultListSections
}
///
private func parsingSearchTypeResults(_ musicShelfRenderer:JsonSearchTypeResults.Contents.TabbedSearchResultsRenderer.Tab.TabRenderer.Content.SectionListRenderer.Content.MusicShelfRenderer) -> ([MPPositive_SearchResultItemViewModel], String?, String?) {
var array:[MPPositive_SearchResultItemViewModel] = []
if let contents = musicShelfRenderer.contents {
///
contents.forEach({ content in
/////
let item = MPPositive_BrowseItemModel()
if (content.musicResponsiveListItemRenderer?.playlistItemData != nil || content.musicResponsiveListItemRenderer?.navigationEndpoint != nil) && (content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE") {
//
item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
@ -1665,7 +1735,7 @@ extension MP_NetWorkManager {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true {
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
@ -1677,67 +1747,12 @@ extension MP_NetWorkManager {
}
}
}
//
if item.itemType != nil {
resultList.previewItemViews.append(.init(item))
}
})
//queryparams
if let searchEndpoint = musicShelfRenderer.bottomEndpoint?.searchEndpoint {
resultList.query = searchEndpoint.query
resultList.params = searchEndpoint.params
}
}
resultListSections.append(resultList)
}
resultListSections = resultListSections.filter({$0.previewItemViews.count != 0})
return resultListSections
}
///
private func parsingSearchTypeResults(_ musicShelfRenderer:JsonSearchTypeResults.Contents.TabbedSearchResultsRenderer.Tab.TabRenderer.Content.SectionListRenderer.Content.MusicShelfRenderer) -> ([MPPositive_SearchResultItemViewModel], String?, String?) {
var array:[MPPositive_SearchResultItemViewModel] = []
if let contents = musicShelfRenderer.contents {
///
contents.forEach({ content in
/////
let item = MPPositive_BrowseItemModel()
//
item.coverUrls = content.musicResponsiveListItemRenderer?.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.map({$0.url ?? ""})
//
for (index, flexColumn) in (content.musicResponsiveListItemRenderer?.flexColumns ?? []).enumerated() {
if index == 0 {
//
item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")})
}else {
//
item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "")
array.append(.init(item))
}
}
item.playListId = content.musicResponsiveListItemRenderer?.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId
//id
if content.musicResponsiveListItemRenderer?.playlistItemData != nil {
//
item.itemType = .single
item.videoId = content.musicResponsiveListItemRenderer?.playlistItemData?.videoId
}else {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
//
item.itemType = .artist
}else {
///
item.itemType = .list
}
}
}
//
if item.itemType != nil {
array.append(.init(item))
}
})
}
var continuation:String?
@ -1780,7 +1795,7 @@ extension MP_NetWorkManager {
///
item.browseId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
let pageType = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
if youTubeKeys.contains(pageType ?? "") == true {
if youTubeKeys.contains(pageType ?? "") == true && pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
if pageType == "MUSIC_PAGE_TYPE_ARTIST" {
item.artistId = content.musicResponsiveListItemRenderer?.navigationEndpoint?.browseEndpoint?.browseId
@ -1840,17 +1855,19 @@ extension MP_NetWorkManager {
}
if let navigationEndpoint = musicResponsiveListItemRenderer.navigationEndpoint {
//
if navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType == "MUSIC_PAGE_TYPE_ARTIST" {
if navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType == "MUSIC_PAGE_TYPE_ARTIST" && navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
item.itemType = .artist
item.artistId = navigationEndpoint.browseEndpoint?.browseId
item.pageType = "MUSIC_PAGE_TYPE_ARTIST"
}else {
//
item.itemType = .list
item.pageType = navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
item.browseId = navigationEndpoint.browseEndpoint?.browseId
item.params = navigationEndpoint.browseEndpoint?.params
if navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType != "MUSIC_PAGE_TYPE_NON_MUSIC_AUDIO_TRACK_PAGE" {
//
item.itemType = .list
item.pageType = navigationEndpoint.browseEndpoint?.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType
item.browseId = navigationEndpoint.browseEndpoint?.browseId
item.params = navigationEndpoint.browseEndpoint?.params
}
}
}
return item

View File

@ -258,6 +258,20 @@ class MP_PlayerManager:NSObject{
if playState != .Playing {
//statuVlaueplayerItem
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 已经准备好播放")
// if playState != .Playing {
// player.play()
// playState = .Playing
// //
// suspendTimer()
// let times = Int(self.times)
// let msTimes = times*1000
// MP_AnalyticsManager.shared.player_b_delay_actionAction(loadPlayer.currentVideo?.song.videoId ?? "", videoname: loadPlayer.currentVideo?.title ?? "", artistname: loadPlayer.currentVideo?.song.shortBylineText ?? "", delay: "\(msTimes)ms")
// MP_AnalyticsManager.shared.player_b_success_actionAction(loadPlayer.currentVideo?.song.videoId ?? "", videoname: loadPlayer.currentVideo?.title ?? "", artistname: loadPlayer.currentVideo?.song.shortBylineText ?? "")
// //
// if startActionBlock != nil {
// startActionBlock!()
// }
// }
}
}else {
print("当前音乐-\(loadPlayer.currentVideo?.title ?? "") 未做好准备播放,失败原因是\(loadPlayer.currentVideo?.resourcePlayerItem.error?.localizedDescription ?? "")")
@ -295,7 +309,7 @@ class MP_PlayerManager:NSObject{
//
private func cacheLoadTimes() {
//Item
if let timeRanges = loadPlayer.currentVideo?.resourcePlayerItem.loadedTimeRanges.map({$0.timeRangeValue}), let first = timeRanges.first {
if let timeRanges = loadPlayer?.currentVideo?.resourcePlayerItem.loadedTimeRanges.map({$0.timeRangeValue}), let first = timeRanges.first {
//
let startSeconds = first.start.seconds
//

View File

@ -642,12 +642,15 @@ struct RootMusicResponsiveListItemRenderer: Codable {
}
struct NavigationEndpoint: Codable {
let watchEndpoint:WatchEndpoint?
let browseEndpoint:BrowseEndpoint?
enum CodingKeys: String, CodingKey {
case watchEndpoint = "watchEndpoint"
case browseEndpoint = "browseEndpoint"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint)
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
}
struct WatchEndpoint: Codable {
let playlistId:String?
@ -659,6 +662,42 @@ struct RootMusicResponsiveListItemRenderer: Codable {
playlistId = try values.decodeIfPresent(String.self, forKey: .playlistId)
}
}
struct BrowseEndpoint: Codable {
let browseId:String?
let params:String?
let browseEndpointContextSupportedConfigs:BrowseEndpointContextSupportedConfigs?
enum CodingKeys: String, CodingKey {
case browseId = "browseId"
case params = "params"
case browseEndpointContextSupportedConfigs = "browseEndpointContextSupportedConfigs"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseId = try values.decodeIfPresent(String.self, forKey: .browseId)
params = try values.decodeIfPresent(String.self, forKey: .params)
browseEndpointContextSupportedConfigs = try values.decodeIfPresent(BrowseEndpointContextSupportedConfigs.self, forKey: .browseEndpointContextSupportedConfigs)
}
struct BrowseEndpointContextSupportedConfigs: Codable {
let browseEndpointContextMusicConfig:BrowseEndpointContextMusicConfig?
enum CodingKeys: String, CodingKey {
case browseEndpointContextMusicConfig = "browseEndpointContextMusicConfig"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig)
}
struct BrowseEndpointContextMusicConfig: Codable {
let pageType:String?
enum CodingKeys: String, CodingKey {
case pageType = "pageType"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
pageType = try values.decodeIfPresent(String.self, forKey: .pageType)
}
}
}
}
}
}
}
@ -781,6 +820,7 @@ struct RootMusicResponsiveListItemRenderer: Codable {
}
}
}
}
}

View File

@ -15,7 +15,7 @@ class MPPositive_PlayerLoadViewModel: NSObject {
///ViewModel
var currentVideo:MPPositive_SongViewModel!{
willSet{
DispatchQueue.main.asyncAfter(deadline: .now()) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
[weak self] in
guard let self = self else {return}
if newValue != nil {
@ -97,6 +97,7 @@ class MPPositive_PlayerLoadViewModel: NSObject {
array = array.filter({!videoIDs.contains($0.videoId)})
group = DispatchGroup()
//,
for item in array {
group?.enter()
@ -108,7 +109,7 @@ class MPPositive_PlayerLoadViewModel: NSObject {
self?.group?.leave()
}
}else {
group?.leave()
self.group?.leave()
}
group?.enter()
//videoID
@ -117,7 +118,7 @@ class MPPositive_PlayerLoadViewModel: NSObject {
item.resourceUrls = [resource]
//,ViewModellistViewVideos
listViewVideos.append(.init(item))
group?.leave()
self.group?.leave()
}else {
//
//

View File

@ -74,6 +74,7 @@ class MPPositive_MoreSongOperationsViewController: UIViewController {
}
}
var removeBlock:(() -> Void)?
var disMissBlock:(() -> Void)?
init(_ song:MPPositive_SongItemModel) {
super.init(nibName: nil, bundle: nil)
DispatchQueue.main.async {
@ -94,7 +95,12 @@ class MPPositive_MoreSongOperationsViewController: UIViewController {
view.layer.cornerRadius = 18*width
configure()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if disMissBlock != nil {
disMissBlock!()
}
}
private func configure() {
view.addSubview(indictorImageView)
indictorImageView.snp.makeConstraints { make in

View File

@ -93,6 +93,12 @@ extension MPPositive_LoveSongsViewController: UITableViewDataSource, UITableView
[weak self] in
MPPositive_ModalType = .MoreOperations
let moreVC = MPPositive_MoreSongOperationsViewController(first)
moreVC.removeBlock = {
self?.reload()
}
moreVC.disMissBlock = {
self?.reload()
}
moreVC.transitioningDelegate = self
moreVC.modalPresentationStyle = .custom
self?.present(moreVC, animated: true)

View File

@ -115,6 +115,7 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController{
}
removeErrorView()
MP_HUD.hideNow()
tableView.showMessage(MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count)
tableView.reloadData()
}
}

View File

@ -304,18 +304,23 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont
}
//MARK: -
private func uploadUI() {
//
backImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl)
coverView.coverImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl)
coverView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
coverView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
lyricsView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.lyricsLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics?.isEmpty == true ? "No Lyrics":MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics
coverView.downloadButton.state = (MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false) ? .downloaded:.startDownload
coverView.downloadButton.isUserInteractionEnabled = !(MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false)
coverView.collectionSongBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isCollection ?? false
coverView.restoreDownloadProgress()
DispatchQueue.main.async {
[weak self] in
guard let self = self else {return}
print("\(MP_PlayerManager.shared.loadPlayer.currentVideo.title ?? "")刷新了页面")
//
backImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl)
coverView.coverImageView.kf.setImage(with: MP_PlayerManager.shared.loadPlayer.currentVideo?.coverUrl)
coverView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
coverView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.titleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.title
lyricsView.subtitleLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.subtitle
lyricsView.lyricsLabel.text = MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics?.isEmpty == true ? "No Lyrics":MP_PlayerManager.shared.loadPlayer.currentVideo?.lyrics
coverView.downloadButton.state = (MPPositive_DownloadItemModel.fetch(.init(format: "videoId == %@", MP_PlayerManager.shared.loadPlayer.currentVideo?.song.videoId ?? "")).count != 0) ? .downloaded:.startDownload
coverView.downloadButton.isUserInteractionEnabled = !(MP_PlayerManager.shared.loadPlayer.currentVideo?.isDlownd ?? false)
coverView.collectionSongBtn.isSelected = MP_PlayerManager.shared.loadPlayer.currentVideo?.isCollection ?? false
coverView.restoreDownloadProgress()
}
}
//MARK: -
//

View File

@ -22,9 +22,9 @@ class MPPositive_RecommendViewController: MPPositive_BaseViewController,UIViewCo
[weak self] in
//
guard let self = self else {return}
sectionLabel.text = loadRecommend.members.title
sectionLabel.text = loadRecommend?.members?.title
collectionView.reloadData()
dataSource.titles = loadRecommend?.sectionLists.compactMap({$0.title}) ?? []
dataSource.titles = loadRecommend?.sectionLists?.compactMap({$0.title}) ?? []
dataSource.reloadData(selectedIndex: 0)
segmentView.reloadData()
}
@ -43,7 +43,7 @@ class MPPositive_RecommendViewController: MPPositive_BaseViewController,UIViewCo
///View
private lazy var membersView:UIView = createMusicMembersView()
//
private lazy var sectionLabel:UILabel = createLabel(font: .systemFont(ofSize: 18*width, weight: .regular), textColor: .white, textAlignment: .left)
private lazy var sectionLabel:UILabel = createLabel("Loading",font: .systemFont(ofSize: 18*width, weight: .regular), textColor: .white, textAlignment: .left)
//CollectionView
private lazy var collectionView:UICollectionView = {
let layout = UICollectionViewFlowLayout()

View File

@ -131,8 +131,8 @@ class MPPositive_PlayerCoverView: UIView, PKDownloadButtonDelegate {
downloadButton.stopDownloadButton.progress = progress
}
}else {
//
downloadButton.state = .startDownload
//,
downloadButton.state = (MPPositive_DownloadItemModel.fetch(.init(format: "videoId == %@", currentVideo.song.videoId ?? "")).count != 0) ? .downloaded:.startDownload
downloadButton.isUserInteractionEnabled = true
}
}

View File

@ -90,8 +90,8 @@
<color key="textColor" white="1" alpha="0.40000000000000002" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version 1.0" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="miJ-lx-eHK">
<rect key="frame" x="294" y="22" width="66" height="16"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Version 1.0.2" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="miJ-lx-eHK">
<rect key="frame" x="283" y="22" width="77" height="16"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.61960784310000006" green="0.61960784310000006" blue="0.61960784310000006" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>