From 130fefd189e8f2b7ea73a7f016db9a65c3bf76e6 Mon Sep 17 00:00:00 2001 From: "Mr.zhou" <1422157428@qq.com> Date: Tue, 9 Jul 2024 18:49:19 +0800 Subject: [PATCH] =?UTF-8?q?1.1.1=E6=95=B0=E6=8D=AE=E7=BB=93=E6=9E=84?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Tool(工具封装)/MP_NetWorkManager.swift | 194 ++++++++------- .../MPPositive_JsonBrowse.swift | 232 ++++++++++-------- .../Models/MPPositive_BrowseItemModel.swift | 4 +- .../MPPositive_BaseViewController.swift | 2 +- .../MPPositive_HomeViewController.swift | 5 +- .../MPPositive_MoreContentViewController.swift | 2 +- .../MPPositive_HomeSinglesTableViewCell.swift | 21 +- 7 files changed, 240 insertions(+), 220 deletions(-) diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift index 31e21a3..491b25b 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift @@ -1312,7 +1312,9 @@ extension MP_NetWorkManager { content.musicCarouselShelfRenderer?.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - browse.items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + browse.items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1392,7 +1394,9 @@ extension MP_NetWorkManager { content.musicCarouselShelfRenderer?.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - browse.items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + browse.items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1421,7 +1425,9 @@ extension MP_NetWorkManager { musicPlaylistShelfRenderer.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1430,7 +1436,9 @@ extension MP_NetWorkManager { musicShelfRenderer.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1449,7 +1457,9 @@ extension MP_NetWorkManager { musicPlaylistShelfRenderer.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1458,7 +1468,9 @@ extension MP_NetWorkManager { musicShelfRenderer.contents?.forEach({ content in //设置标题、歌手、专辑/列表 if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer { - items.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + items.append(.init(item)) + } }else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer { items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer))) } @@ -1540,8 +1552,8 @@ extension MP_NetWorkManager { params = musicShelfRenderer.title?.runs?.first?.navigationEndpoint?.browseEndpoint?.params //解析模块内容 musicShelfRenderer.contents?.forEach({ item in - if item.musicResponsiveListItemRenderer != nil { - itemViews.append(.init(parsingMusicResponsiveListItemRenderer(item.musicResponsiveListItemRenderer!))) + if let musicResponsiveListItemRenderer = item.musicResponsiveListItemRenderer, let asd = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + itemViews.append(.init(asd)) } }) } @@ -1573,7 +1585,9 @@ extension MP_NetWorkManager { //是音视频 musicPlaylistShelfRenderer.contents?.forEach({ item in if let musicResponsiveListItemRenderer = item.musicResponsiveListItemRenderer { - array.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let asd = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + array.append(.init(asd)) + } } }) continuation = musicPlaylistShelfRenderer.continuations?.first?.nextContinuationData?.continuation @@ -1601,7 +1615,9 @@ extension MP_NetWorkManager { if let contents = musicPlaylistShelfContinuation.contents { contents.forEach { item in if let musicResponsiveListItemRenderer = item.musicResponsiveListItemRenderer { - array.append(.init(parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer))) + if let asd = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + array.append(.init(asd)) + } } } } @@ -1810,9 +1826,10 @@ extension MP_NetWorkManager { let list = MPPositive_RecommendListViewModel() list.title = section.musicCarouselShelfRenderer?.header?.musicCarouselShelfBasicHeaderRenderer?.title?.runs?.reduce("", { $0 + ($1.text ?? "")}) section.musicCarouselShelfRenderer?.contents?.forEach({ content in - if content.musicResponsiveListItemRenderer != nil { - let item = parsingMusicResponsiveListItemRenderer(content.musicResponsiveListItemRenderer!) - list.items.append(.init(item)) + if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer{ + if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { + list.items.append(.init(item)) + } }else if content.musicTwoRowItemRenderer != nil { let item = parsingMusicTwoRowItemRenderer(content.musicTwoRowItemRenderer!) list.items.append(.init(item)) @@ -1968,45 +1985,7 @@ 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" { + if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer, let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) { resultList.previewItemViews.append(.init(item)) } }) @@ -2146,55 +2125,87 @@ extension MP_NetWorkManager { return (array, continuation, clickTrackingParams) } //MARK: - 解析具体内容形式 - //解析musicResponsiveListItemRenderer(通常是音视频内容) - private func parsingMusicResponsiveListItemRenderer(_ musicResponsiveListItemRenderer: RootMusicResponsiveListItemRenderer) -> MPPositive_BrowseItemModel { + //解析musicResponsiveListItemRenderer(四组件内容) + private func parsingMusicResponsiveListItemRenderer(_ musicResponsiveListItemRenderer: RootMusicResponsiveListItemRenderer) -> MPPositive_BrowseItemModel? { //生成一个音乐模型接收数据 let item = MPPositive_BrowseItemModel() //预览图片路径 item.coverUrls = musicResponsiveListItemRenderer.thumbnail?.musicThumbnailRenderer?.thumbnail?.thumbnails?.compactMap({$0.url}) - //设置主副标题 - if let flexColumns = musicResponsiveListItemRenderer.flexColumns { - for (index,flexColumn) in flexColumns.enumerated() { - if index == 0 { - //添加主标题 - item.title = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) - item.playListId = flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.first?.navigationEndpoint?.watchEndpoint?.playlistId - }else{ - item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "") - } - } - } - if item.playListId == nil { - //通过操作菜单获取playListId - item.playListId = musicResponsiveListItemRenderer.menu?.menuRenderer?.items?.first?.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId - } - //判断这个内容是音视频还是专辑列表艺术家 + //判断预览项性质,并继续补完数据 if let playlistItemData = musicResponsiveListItemRenderer.playlistItemData { - //是音视频 + //当前预览项是视频/单曲 item.itemType = .single item.videoId = playlistItemData.videoId - item.pageType = "MUSIC_VIDEO_TYPE_ATV" - } - if let navigationEndpoint = musicResponsiveListItemRenderer.navigationEndpoint { - //是专辑列表艺术家 - 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 { - 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 - } + //设置主副标题 + guard var flexColumns = musicResponsiveListItemRenderer.flexColumns, flexColumns.isEmpty != true else { + return nil } + //主标题为第一位,同时VideoId,PlayListId,pageType都以第一个flexColumn为主 + let first = flexColumns.removeFirst() + item.title = first.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) + //判断watchEndpoint(资源导向)是否存在 + guard let watchEndpoint = first.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.first?.navigationEndpoint?.watchEndpoint else {return nil} + //watchEndpoint内容赋值给item + item.playListId = watchEndpoint.playlistId + item.pageType = watchEndpoint.watchEndpointMusicSupportedConfigs?.watchEndpointMusicConfig?.musicVideoType + //设置副标题,通常为作者/专辑 + flexColumns.forEach { flexColumn in + item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "") + } + //继续补完videoId,检索是否具备playListId,当playListId为空时,说明并没有成功补完,需要使用菜单结构补全内容 + guard (item.playListId ?? "").isEmpty == true else { + //不为空,说明需要的数据已经补完了 + return item + } + //未补完,继续 + if let watchItem = musicResponsiveListItemRenderer.menu?.menuRenderer?.items?.first(where: {$0.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint != nil}) { + item.playListId = watchItem.menuNavigationItemRenderer?.navigationEndpoint?.watchEndpoint?.playlistId + return item + }else { + //补完失败 + return nil + } + }else if let navigationEndpoint = musicResponsiveListItemRenderer.navigationEndpoint { + //是专辑/艺术家/歌单 + //设置主副标题 + guard var flexColumns = musicResponsiveListItemRenderer.flexColumns, flexColumns.isEmpty != true else { + return nil + } + //主标题为第一位,其余内容都是副标题 + let first = flexColumns.removeFirst() + item.title = first.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) + //设置副标题,通常为作者/专辑 + flexColumns.forEach { flexColumn in + item.subtitle = (item.subtitle ?? "") + (flexColumn.musicResponsiveListItemFlexColumnRenderer?.text?.runs?.reduce("", { $0 + ($1.text ?? "")}) ?? "") + } + //设置预览Id + guard let browseEndpoint = navigationEndpoint.browseEndpoint else { + return nil + } + item.browseId = browseEndpoint.browseId + //根据pageType确定导航至何处 + guard let pageType = browseEndpoint.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType else {return nil} + item.pageType = pageType + if pageType == "MUSIC_PAGE_TYPE_ALBUM" { + //专辑 + item.itemType = .list + return item + }else if pageType == "MUSIC_PAGE_TYPE_PLAYLIST" { + //列表 + item.itemType = .list + return item + }else if pageType == "MUSIC_PAGE_TYPE_ARTIST" { + //艺术家 + item.itemType = .artist + return item + }else { + return nil + } + }else { + return nil } - return item } - //解析musicResponsiveListItemRenderer(是列表专辑内容) + //解析musicResponsiveListItemRenderer(三组件结构) private func parsingMusicTwoRowItemRenderer(_ musicTwoRowItemRenderer: RootMusicTwoRowItemRenderer) -> MPPositive_BrowseItemModel { //生成一个音乐模型接收数据 let item = MPPositive_BrowseItemModel() @@ -2224,7 +2235,6 @@ extension MP_NetWorkManager { item.itemType = .list item.pageType = browseEndpoint.browseEndpointContextSupportedConfigs?.browseEndpointContextMusicConfig?.pageType item.browseId = browseEndpoint.browseId - item.params = browseEndpoint.params } } return item diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/JsonStructs(js文件结构)/MPPositive_JsonBrowse.swift b/relax.offline.mp3.music/MP/MPPositive/Models/JsonStructs(js文件结构)/MPPositive_JsonBrowse.swift index da021c7..98ae996 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/JsonStructs(js文件结构)/MPPositive_JsonBrowse.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/JsonStructs(js文件结构)/MPPositive_JsonBrowse.swift @@ -469,32 +469,33 @@ struct JsonBrowses: Codable { } //MARK: - 图像信息数据结构 -///单曲/视频结构(通常是四组件构成,封面,一级标题,二级标题,额外包含ID内容) +///四组件结构(通常是四组件构成,封面,一级标题,二级标题,额外包含ID内容),根据playlistItemData和navigationEndpoint两者来敲定该预览项属于(播放/导航)一种,并继续下分 struct RootMusicResponsiveListItemRenderer: Codable { ///指向封面图像 let thumbnail:Thumbnail? ///指向标题歌手专辑(通常有多位,0位是标题,后续都为副标题) let flexColumns:[FlexColumn]? - ///菜单操作(某些情况下flexColumns无法拿到playListId) - let menu:Menu? ///单曲/视频ID(playlistItemData存在说明这条数据单曲/视频) let playlistItemData:PlaylistItemData? - ///专辑/歌单ID(navigationEndpoint存在说明这条数据是专辑/歌单) + ///页面导向(navigationEndpoint存在时,说明这条数据将会作为跳转内容导向一个页面) let navigationEndpoint:NavigationEndpoint? + ///菜单(当playlistItemData存在,且无法通过flexColumns获得PlayListID时,调用菜单强制获得playListId) + let menu:Menu? + enum CodingKeys: String, CodingKey { case thumbnail = "thumbnail" case flexColumns = "flexColumns" - case menu = "menu" case playlistItemData = "playlistItemData" case navigationEndpoint = "navigationEndpoint" + case menu = "menu" } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) thumbnail = try values.decodeIfPresent(Thumbnail.self, forKey: .thumbnail) flexColumns = try values.decodeIfPresent([FlexColumn].self, forKey: .flexColumns) - menu = try values.decodeIfPresent(Menu.self, forKey: .menu) playlistItemData = try values.decodeIfPresent(PlaylistItemData.self, forKey: .playlistItemData) navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint) + menu = try values.decodeIfPresent(Menu.self, forKey: .menu) } //含有封面图像 struct Thumbnail: Codable { @@ -573,6 +574,7 @@ struct RootMusicResponsiveListItemRenderer: Codable { struct Run: Codable { ///标题文本 let text:String? + ///文本导航 let navigationEndpoint:NavigationEndpoint? enum CodingKeys: String, CodingKey { case text = "text" @@ -583,60 +585,54 @@ struct RootMusicResponsiveListItemRenderer: Codable { text = try values.decodeIfPresent(String.self, forKey: .text) navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint) } + //文本导航 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 { + ///资源ID + let videoId:String? + ///对应歌单ID(未必存在) let playlistId:String? + ///指向资源类型 + let watchEndpointMusicSupportedConfigs:WatchEndpointMusicSupportedConfigs? enum CodingKeys: String, CodingKey { + case videoId = "videoId" case playlistId = "playlistId" + case watchEndpointMusicSupportedConfigs = "watchEndpointMusicSupportedConfigs" } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) + videoId = try values.decodeIfPresent(String.self, forKey: .videoId) playlistId = try values.decodeIfPresent(String.self, forKey: .playlistId) + watchEndpointMusicSupportedConfigs = try values.decodeIfPresent(WatchEndpointMusicSupportedConfigs.self, forKey: .watchEndpointMusicSupportedConfigs) } - } - 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? + struct WatchEndpointMusicSupportedConfigs: Codable { + let watchEndpointMusicConfig:WatchEndpointMusicConfig? enum CodingKeys: String, CodingKey { - case browseEndpointContextMusicConfig = "browseEndpointContextMusicConfig" + case watchEndpointMusicConfig = "watchEndpointMusicConfig" } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) - browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig) + watchEndpointMusicConfig = try values.decodeIfPresent(WatchEndpointMusicConfig.self, forKey: .watchEndpointMusicConfig) } - struct BrowseEndpointContextMusicConfig: Codable { - let pageType:String? + struct WatchEndpointMusicConfig: Codable { + ///资源类型 + let musicVideoType:String? enum CodingKeys: String, CodingKey { - case pageType = "pageType" + case musicVideoType = "musicVideoType" } init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) - pageType = try values.decodeIfPresent(String.self, forKey: .pageType) + musicVideoType = try values.decodeIfPresent(String.self, forKey: .musicVideoType) } } } @@ -646,68 +642,7 @@ struct RootMusicResponsiveListItemRenderer: Codable { } } } - //菜单操作 - struct Menu: Codable { - let menuRenderer:MenuRenderer? - enum CodingKeys: String, CodingKey { - case menuRenderer = "menuRenderer" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - menuRenderer = try values.decodeIfPresent(MenuRenderer.self, forKey: .menuRenderer) - } - struct MenuRenderer: Codable { - let items:[Item]? - enum CodingKeys: String, CodingKey { - case items = "items" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - items = try values.decodeIfPresent([Item].self, forKey: .items) - } - struct Item: Codable { - let menuNavigationItemRenderer:MenuNavigationItemRenderer? - enum CodingKeys: String, CodingKey { - case menuNavigationItemRenderer = "menuNavigationItemRenderer" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - menuNavigationItemRenderer = try values.decodeIfPresent(MenuNavigationItemRenderer.self, forKey: .menuNavigationItemRenderer) - } - struct MenuNavigationItemRenderer: Codable { - let navigationEndpoint:NavigationEndpoint? - enum CodingKeys: String, CodingKey { - case navigationEndpoint = "navigationEndpoint" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint) - } - - struct NavigationEndpoint: Codable { - let watchEndpoint:WatchEndpoint? - enum CodingKeys: String, CodingKey { - case watchEndpoint = "watchEndpoint" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint) - } - struct WatchEndpoint: Codable { - let playlistId:String? - enum CodingKeys: String, CodingKey { - case playlistId = "playlistId" - } - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - playlistId = try values.decodeIfPresent(String.self, forKey: .playlistId) - } - } - } - } - } - } - } + //歌曲详细数据内容 struct PlaylistItemData: Codable { let videoId:String? enum CodingKeys: String, CodingKey { @@ -718,6 +653,7 @@ struct RootMusicResponsiveListItemRenderer: Codable { videoId = try values.decodeIfPresent(String.self, forKey: .videoId) } } + //页面导向 struct NavigationEndpoint: Codable { let browseEndpoint:BrowseEndpoint? enum CodingKeys: String, CodingKey { @@ -728,18 +664,16 @@ struct RootMusicResponsiveListItemRenderer: Codable { browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint) } struct BrowseEndpoint: Codable { + ///预览ID,根据类型不同,视作不同作用 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 { @@ -752,6 +686,7 @@ struct RootMusicResponsiveListItemRenderer: Codable { browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig) } struct BrowseEndpointContextMusicConfig: Codable { + ///预览类型 let pageType:String? enum CodingKeys: String, CodingKey { case pageType = "pageType" @@ -763,11 +698,106 @@ struct RootMusicResponsiveListItemRenderer: Codable { } } } - } - + //菜单 + struct Menu: Codable { + let menuRenderer:MenuRenderer? + enum CodingKeys: String, CodingKey { + case menuRenderer = "menuRenderer" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + menuRenderer = try values.decodeIfPresent(MenuRenderer.self, forKey: .menuRenderer) + } + struct MenuRenderer: Codable { + ///菜单选项 + let items:[Item]? + enum CodingKeys: String, CodingKey { + case items = "items" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + items = try values.decodeIfPresent([Item].self, forKey: .items) + } + struct Item: Codable { + ///具备播放功能的选项(默认取包含watchEndpoint) + let menuNavigationItemRenderer:MenuNavigationItemRenderer? + enum CodingKeys: String, CodingKey { + case menuNavigationItemRenderer = "menuNavigationItemRenderer" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + menuNavigationItemRenderer = try values.decodeIfPresent(MenuNavigationItemRenderer.self, forKey: .menuNavigationItemRenderer) + } + struct MenuNavigationItemRenderer: Codable { + ///文本导航 + let navigationEndpoint:NavigationEndpoint? + enum CodingKeys: String, CodingKey { + case navigationEndpoint = "navigationEndpoint" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint) + } + //文本导航 + struct NavigationEndpoint: Codable { + ///资源特化 + let watchEndpoint:WatchEndpoint? + enum CodingKeys: String, CodingKey { + case watchEndpoint = "watchEndpoint" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint) + } + //导向播放 + struct WatchEndpoint: Codable { + ///资源ID + let videoId:String? + ///对应歌单ID(未必存在) + let playlistId:String? + ///指向资源类型 + let watchEndpointMusicSupportedConfigs:WatchEndpointMusicSupportedConfigs? + enum CodingKeys: String, CodingKey { + case videoId = "videoId" + case playlistId = "playlistId" + case watchEndpointMusicSupportedConfigs = "watchEndpointMusicSupportedConfigs" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + videoId = try values.decodeIfPresent(String.self, forKey: .videoId) + playlistId = try values.decodeIfPresent(String.self, forKey: .playlistId) + watchEndpointMusicSupportedConfigs = try values.decodeIfPresent(WatchEndpointMusicSupportedConfigs.self, forKey: .watchEndpointMusicSupportedConfigs) + } + struct WatchEndpointMusicSupportedConfigs: Codable { + let watchEndpointMusicConfig:WatchEndpointMusicConfig? + enum CodingKeys: String, CodingKey { + case watchEndpointMusicConfig = "watchEndpointMusicConfig" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + watchEndpointMusicConfig = try values.decodeIfPresent(WatchEndpointMusicConfig.self, forKey: .watchEndpointMusicConfig) + } + struct WatchEndpointMusicConfig: Codable { + ///资源类型 + let musicVideoType:String? + enum CodingKeys: String, CodingKey { + case musicVideoType = "musicVideoType" + } + init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + musicVideoType = try values.decodeIfPresent(String.self, forKey: .musicVideoType) + } + } + } + } + } + } + } + } + } } -///列表/专辑结构(通常是三组件构成,封面,一级标题,二级标题,额外包含ID内容) +///列表/专辑/歌手结构(通常是三组件构成,封面,一级标题,二级标题,额外包含ID内容) struct RootMusicTwoRowItemRenderer: Codable { ///内容预览图片 let thumbnailRenderer:ThumbnailRenderer? diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_BrowseItemModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_BrowseItemModel.swift index a1e998f..f0c802d 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_BrowseItemModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_BrowseItemModel.swift @@ -20,9 +20,7 @@ class MPPositive_BrowseItemModel: NSObject, Codable { var playListId:String? ///列表专辑预览ID var browseId:String? - ///列表专辑预览参数 - var params:String? - ///艺术家Id + ///艺术家Id(当pageType == “MUSIC_PAGE_TYPE_ARTIST”时,与browseId等价) var artistId:String? ///页面类型 var pageType:String? diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift index 9ea9e63..401a1e7 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift @@ -72,7 +72,7 @@ class MPPositive_BaseViewController: MP_BaseViewController, UIGestureRecognizerD } //pop上一个页面 @objc func popActionClick(_ sender:UIButton) { - MPPositive_Debouncer.shared.call { + MPPositive_Debouncer.shared.call(0.1) { [weak self] in guard let self = self else {return} navigationController?.popViewController(animated: true) diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift index b1d262d..230f6d9 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift @@ -137,7 +137,6 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro func presentGuide() { guard UserDefaults.standard.bool(forKey: "isGuide") != true else { //已经评论过了 - print("已经评论过了") return } //检索活跃天数是否达到3天 @@ -267,7 +266,7 @@ extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDeleg cell.requestNextBlock = { [weak self] (item) in guard let self = self else {return} - MP_AnalyticsManager.shared.home_b_module_clickAction(MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.section].title ?? "") + MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "") switch item.browseItem.itemType { case .single: //单曲/视频跳转 @@ -299,7 +298,7 @@ extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDeleg case .list: isFirstAppearance = false //列表专辑 - let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: item.browseItem.params ?? "", title: item.title ?? "", subtitle: item.subtitle ?? "") + let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "") navigationController?.pushViewController(listVC, animated: true) case .artist: isFirstAppearance = false diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift index 333cdfa..36ac25b 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift @@ -166,7 +166,7 @@ extension MPPositive_MoreContentViewController: UICollectionViewDataSource, UICo navigationController?.pushViewController(artistVC, animated: true) default: //列表专辑 - let listVC = MPPositive_ListShowViewController(browseModuleList.items[indexPath.row].browseItem.browseId ?? "", params: browseModuleList.items[indexPath.row].browseItem.params ?? "", title: browseModuleList.items[indexPath.row].title ?? "", subtitle: browseModuleList.items[indexPath.row].subtitle ?? "") + let listVC = MPPositive_ListShowViewController(browseModuleList.items[indexPath.row].browseItem.browseId ?? "", params: "", title: browseModuleList.items[indexPath.row].title ?? "", subtitle: browseModuleList.items[indexPath.row].subtitle ?? "") navigationController?.pushViewController(listVC, animated: true) } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift index 5c8a728..f3099fb 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift @@ -36,27 +36,9 @@ class MPPositive_HomeSinglesTableViewCell: UITableViewCell, UIViewControllerTran didSet{ titleLabel.text = browseViewModel.title collectionView.reloadData() -// let groupSize = browseViewModel.items.count / 3 // 每组的元素数量 -// var remainder = browseViewModel.items.count % 3 // 不完整组的元素数量 -// let numberOfGroups = 3 // 组数 -// var groups = [[MPPositive_BrowseItemViewModel]]() // 存储分组结果的数组 -// var start = 0 -// for _ in 0.. 0 ? 1 : 0) -// let group = Array(browseViewModel.items[start..