1094 lines
64 KiB
Swift
1094 lines
64 KiB
Swift
|
||
|
||
import Foundation
|
||
///预览结构体
|
||
struct JsonBrowses: Codable {
|
||
///获取访问数据
|
||
let responseContext:ResponseContext?
|
||
///抓取的数据_预览首次(无额外参数)获取会调用这个
|
||
let contents:Contents?
|
||
///抓取的数据_预览再(有额外参数)获取会调用这个
|
||
let continuationContents:ContinuationContents?
|
||
enum CodingKeys: String, CodingKey {
|
||
case responseContext = "responseContext"
|
||
case contents = "contents"
|
||
case continuationContents = "continuationContents"
|
||
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
responseContext = try values.decodeIfPresent(ResponseContext.self, forKey: .responseContext)
|
||
contents = try values.decodeIfPresent(Contents.self, forKey: .contents)
|
||
continuationContents = try values.decodeIfPresent(ContinuationContents.self, forKey: .continuationContents)
|
||
}
|
||
|
||
//MARK: - 内容结构
|
||
///访问数据
|
||
struct ResponseContext: Codable {
|
||
let visitorData:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case visitorData = "visitorData"
|
||
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
visitorData = try values.decodeIfPresent(String.self, forKey: .visitorData)
|
||
}
|
||
}
|
||
///内容结构一
|
||
struct Contents: Codable {
|
||
let singleColumnBrowseResultsRenderer : SingleColumnBrowseResultsRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
|
||
case singleColumnBrowseResultsRenderer = "singleColumnBrowseResultsRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
singleColumnBrowseResultsRenderer = try values.decodeIfPresent(SingleColumnBrowseResultsRenderer.self, forKey: .singleColumnBrowseResultsRenderer)
|
||
}
|
||
struct SingleColumnBrowseResultsRenderer: Codable {
|
||
///通常只有1位数据
|
||
let tabs : [Tab]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case tabs = "tabs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
tabs = try values.decodeIfPresent([Tab].self, forKey: .tabs)
|
||
}
|
||
struct Tab : Codable {
|
||
let tabRenderer : TabRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case tabRenderer = "tabRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
tabRenderer = try values.decodeIfPresent(TabRenderer.self, forKey: .tabRenderer)
|
||
}
|
||
struct TabRenderer : Codable {
|
||
///内容总汇(包含content以及第一阶段ctoke吗)
|
||
let content : Content?
|
||
let trackingParams : String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case content = "content"
|
||
case trackingParams = "trackingParams"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
content = try values.decodeIfPresent(Content.self, forKey: .content)
|
||
trackingParams = try values.decodeIfPresent(String.self, forKey: .trackingParams)
|
||
}
|
||
struct Content : Codable {
|
||
let sectionListRenderer : SectionListRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case sectionListRenderer = "sectionListRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
sectionListRenderer = try values.decodeIfPresent(SectionListRenderer.self, forKey: .sectionListRenderer)
|
||
}
|
||
//MARK: - 核心内容,从此往上代码无意义
|
||
struct SectionListRenderer : Codable {
|
||
///指向图像数据内容
|
||
let contents : [Content]?
|
||
///指向续页编码
|
||
let continuations : [Continuation]?
|
||
let trackingParams : String?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case contents = "contents"
|
||
case continuations = "continuations"
|
||
case trackingParams = "trackingParams"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
continuations = try values.decodeIfPresent([Continuation].self, forKey: .continuations)
|
||
trackingParams = try values.decodeIfPresent(String.self, forKey: .trackingParams)
|
||
}
|
||
///图像数据内容
|
||
struct Content: Codable {
|
||
let musicCarouselShelfRenderer:MusicCarouselShelfRenderer?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCarouselShelfRenderer = "musicCarouselShelfRenderer"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCarouselShelfRenderer = try values.decodeIfPresent(MusicCarouselShelfRenderer.self, forKey: .musicCarouselShelfRenderer)
|
||
}
|
||
struct MusicCarouselShelfRenderer: Codable {
|
||
///指向模块标题
|
||
let header:Header?
|
||
///指向音乐内容
|
||
let contents:[Content]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case header = "header"
|
||
case contents = "contents"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
header = try values.decodeIfPresent(Header.self, forKey: .header)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
}
|
||
///模块标题
|
||
struct Header: Codable {
|
||
let musicCarouselShelfBasicHeaderRenderer:MusicCarouselShelfBasicHeaderRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCarouselShelfBasicHeaderRenderer = "musicCarouselShelfBasicHeaderRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCarouselShelfBasicHeaderRenderer = try values.decodeIfPresent(MusicCarouselShelfBasicHeaderRenderer.self, forKey: .musicCarouselShelfBasicHeaderRenderer)
|
||
}
|
||
struct MusicCarouselShelfBasicHeaderRenderer: Codable {
|
||
let title:Title?
|
||
enum CodingKeys: String, CodingKey {
|
||
case title = "title"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||
}
|
||
struct Title: Codable {
|
||
///一般是第0位
|
||
let runs:[Run]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case runs = "runs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
|
||
//MARK: - 文本内容,标题/作者/专辑
|
||
struct Run: Codable {
|
||
///关键文本内容(代表各级标题)
|
||
let text:String?
|
||
///指向预览ID
|
||
let navigationEndpoint: NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct NavigationEndpoint: Codable {
|
||
let browseEndpoint:BrowseEndpoint?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
|
||
}
|
||
//MARK: - 展示内容块的预览内容
|
||
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 {
|
||
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)
|
||
}
|
||
//MARK: - Browse类型 作者/歌单/专辑
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///音乐内容
|
||
struct Content: Codable {
|
||
///常规列表(通常是四组件构成,封面,一级标题,二级标题,三级标题,额外包含ID内容,通常是单曲)
|
||
let musicResponsiveListItemRenderer:RootMusicResponsiveListItemRenderer?
|
||
///两行式列表(通常是三组件构成,封面,一级标题,二级标题,额外包含ID内容,通常是歌单)
|
||
let musicTwoRowItemRenderer:RootMusicTwoRowItemRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicResponsiveListItemRenderer = "musicResponsiveListItemRenderer"
|
||
case musicTwoRowItemRenderer = "musicTwoRowItemRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicResponsiveListItemRenderer = try values.decodeIfPresent(RootMusicResponsiveListItemRenderer.self, forKey: .musicResponsiveListItemRenderer)
|
||
musicTwoRowItemRenderer = try values.decodeIfPresent(RootMusicTwoRowItemRenderer.self, forKey: .musicTwoRowItemRenderer)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///续页编码
|
||
struct Continuation: Codable {
|
||
let nextContinuationData:NextContinuationData?
|
||
enum CodingKeys: String, CodingKey {
|
||
case nextContinuationData = "nextContinuationData"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
nextContinuationData = try values.decodeIfPresent(NextContinuationData.self, forKey: .nextContinuationData)
|
||
}
|
||
//MARK: - 续页编码
|
||
struct NextContinuationData: Codable {
|
||
let continuation:String?
|
||
let clickTrackingParams:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case continuation = "continuation"
|
||
case clickTrackingParams = "clickTrackingParams"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
continuation = try values.decodeIfPresent(String.self, forKey: .continuation)
|
||
clickTrackingParams = try values.decodeIfPresent(String.self, forKey: .clickTrackingParams)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///内容结构二
|
||
struct ContinuationContents: Codable {
|
||
let sectionListContinuation:SectionListContinuation?
|
||
enum CodingKeys: String, CodingKey {
|
||
case sectionListContinuation = "sectionListContinuation"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
sectionListContinuation = try values.decodeIfPresent(SectionListContinuation.self, forKey: .sectionListContinuation)
|
||
}
|
||
//MARK: - 核心内容,从此往上代码无意义
|
||
struct SectionListContinuation : Codable {
|
||
///指向图像数据内容
|
||
let contents : [Content]?
|
||
///指向续页编码
|
||
let continuations : [Continuation]?
|
||
let trackingParams : String?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case contents = "contents"
|
||
case continuations = "continuations"
|
||
case trackingParams = "trackingParams"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
continuations = try values.decodeIfPresent([Continuation].self, forKey: .continuations)
|
||
trackingParams = try values.decodeIfPresent(String.self, forKey: .trackingParams)
|
||
}
|
||
///图像数据内容
|
||
struct Content: Codable {
|
||
let musicCarouselShelfRenderer:MusicCarouselShelfRenderer?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCarouselShelfRenderer = "musicCarouselShelfRenderer"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCarouselShelfRenderer = try values.decodeIfPresent(MusicCarouselShelfRenderer.self, forKey: .musicCarouselShelfRenderer)
|
||
}
|
||
struct MusicCarouselShelfRenderer: Codable {
|
||
///指向模块标题
|
||
let header:Header?
|
||
///指向音乐内容
|
||
let contents:[Content]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case header = "header"
|
||
case contents = "contents"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
header = try values.decodeIfPresent(Header.self, forKey: .header)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
}
|
||
///模块标题
|
||
struct Header: Codable {
|
||
let musicCarouselShelfBasicHeaderRenderer:MusicCarouselShelfBasicHeaderRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCarouselShelfBasicHeaderRenderer = "musicCarouselShelfBasicHeaderRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCarouselShelfBasicHeaderRenderer = try values.decodeIfPresent(MusicCarouselShelfBasicHeaderRenderer.self, forKey: .musicCarouselShelfBasicHeaderRenderer)
|
||
}
|
||
struct MusicCarouselShelfBasicHeaderRenderer: Codable {
|
||
let title:Title?
|
||
enum CodingKeys: String, CodingKey {
|
||
case title = "title"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||
}
|
||
struct Title: Codable {
|
||
///一般是第0位
|
||
let runs:[Run]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case runs = "runs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
|
||
//MARK: - 文本内容,标题/作者/专辑
|
||
struct Run: Codable {
|
||
///关键文本内容(代表各级标题)
|
||
let text:String?
|
||
///指向预览ID
|
||
let navigationEndpoint: NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct NavigationEndpoint: Codable {
|
||
let browseEndpoint:BrowseEndpoint?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
|
||
}
|
||
//MARK: - 展示内容块的预览内容
|
||
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 {
|
||
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)
|
||
}
|
||
//MARK: - Browse类型 作者/歌单/专辑
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///音乐内容
|
||
struct Content: Codable {
|
||
///常规列表(通常是四组件构成,封面,一级标题,二级标题,三级标题,额外包含ID内容,通常是单曲)
|
||
let musicResponsiveListItemRenderer:RootMusicResponsiveListItemRenderer?
|
||
///两行式列表(通常是三组件构成,封面,一级标题,二级标题,额外包含ID内容,通常是歌单)
|
||
let musicTwoRowItemRenderer:RootMusicTwoRowItemRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicResponsiveListItemRenderer = "musicResponsiveListItemRenderer"
|
||
case musicTwoRowItemRenderer = "musicTwoRowItemRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicResponsiveListItemRenderer = try values.decodeIfPresent(RootMusicResponsiveListItemRenderer.self, forKey: .musicResponsiveListItemRenderer)
|
||
musicTwoRowItemRenderer = try values.decodeIfPresent(RootMusicTwoRowItemRenderer.self, forKey: .musicTwoRowItemRenderer)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///续页编码
|
||
struct Continuation: Codable {
|
||
let nextContinuationData:NextContinuationData?
|
||
enum CodingKeys: String, CodingKey {
|
||
case nextContinuationData = "nextContinuationData"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
nextContinuationData = try values.decodeIfPresent(NextContinuationData.self, forKey: .nextContinuationData)
|
||
}
|
||
//MARK: - 续页编码
|
||
struct NextContinuationData: Codable {
|
||
let continuation:String?
|
||
let clickTrackingParams:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case continuation = "continuation"
|
||
case clickTrackingParams = "clickTrackingParams"
|
||
}
|
||
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
continuation = try values.decodeIfPresent(String.self, forKey: .continuation)
|
||
clickTrackingParams = try values.decodeIfPresent(String.self, forKey: .clickTrackingParams)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//MARK: - 图像信息数据结构
|
||
///单曲/视频结构(通常是四组件构成,封面,一级标题,二级标题,三级标题,额外包含ID内容)
|
||
struct RootMusicResponsiveListItemRenderer: Codable {
|
||
///指向封面图像
|
||
let thumbnail:Thumbnail?
|
||
///指向标题歌手专辑(通常有3位,0位是标题,1位是歌手,3位是专辑/列表)
|
||
let flexColumns:[FlexColumn]?
|
||
///指向列表ID和视频ID
|
||
let overlay:Overlay?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnail = "thumbnail"
|
||
case overlay = "overlay"
|
||
case flexColumns = "flexColumns"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
thumbnail = try values.decodeIfPresent(Thumbnail.self, forKey: .thumbnail)
|
||
overlay = try values.decodeIfPresent(Overlay.self, forKey: .overlay)
|
||
flexColumns = try values.decodeIfPresent([FlexColumn].self, forKey: .flexColumns)
|
||
}
|
||
//含有封面图像
|
||
struct Thumbnail: Codable {
|
||
let musicThumbnailRenderer:MusicThumbnailRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicThumbnailRenderer = "musicThumbnailRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicThumbnailRenderer = try values.decodeIfPresent(MusicThumbnailRenderer.self, forKey: .musicThumbnailRenderer)
|
||
}
|
||
|
||
struct MusicThumbnailRenderer: Codable {
|
||
let thumbnail:Thumbnail?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnail = "thumbnail"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.thumbnail = try values.decodeIfPresent(Thumbnail.self, forKey: .thumbnail)
|
||
}
|
||
struct Thumbnail: Codable {
|
||
///封面图片组(默认取最后一位,图像内容最大最高清)
|
||
let thumbnails:[Thumbnails]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnails = "thumbnails"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.thumbnails = try values.decodeIfPresent([Thumbnails].self, forKey: .thumbnails)
|
||
}
|
||
//MARK: - 封面图片
|
||
///封面图片
|
||
struct Thumbnails: Codable {
|
||
///封面图片路径
|
||
let url:String?
|
||
let width:CGFloat?
|
||
let height:CGFloat?
|
||
enum CodingKeys: String, CodingKey {
|
||
case url = "url"
|
||
case width = "width"
|
||
case height = "height"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
url = try values.decodeIfPresent(String.self, forKey: .url)
|
||
width = try values.decodeIfPresent(CGFloat.self, forKey: .width)
|
||
height = try values.decodeIfPresent(CGFloat.self, forKey: .height)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//含有标题作者专辑
|
||
struct FlexColumn: Codable {
|
||
let musicResponsiveListItemFlexColumnRenderer:MusicResponsiveListItemFlexColumnRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicResponsiveListItemFlexColumnRenderer = "musicResponsiveListItemFlexColumnRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicResponsiveListItemFlexColumnRenderer = try values.decodeIfPresent(MusicResponsiveListItemFlexColumnRenderer.self, forKey: .musicResponsiveListItemFlexColumnRenderer)
|
||
}
|
||
struct MusicResponsiveListItemFlexColumnRenderer: Codable {
|
||
let text:Text?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(Text.self, forKey: .text)
|
||
}
|
||
struct Text: Codable {
|
||
let runs:[Run]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case runs = "runs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
//MARK: - 文本内容,标题/作者/专辑
|
||
struct Run: Codable {
|
||
///关键文本内容(代表各级标题)
|
||
let text:String?
|
||
///指向预览ID
|
||
let navigationEndpoint: NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct NavigationEndpoint: Codable {
|
||
let browseEndpoint:BrowseEndpoint?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
|
||
}
|
||
//MARK: - 展示内容块的预览内容
|
||
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 {
|
||
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)
|
||
}
|
||
//MARK: - Browse类型 作者/歌单/专辑
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//含有列表ID和视频ID
|
||
struct Overlay: Codable {
|
||
let musicItemThumbnailOverlayRenderer:MusicItemThumbnailOverlayRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicItemThumbnailOverlayRenderer = "musicItemThumbnailOverlayRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicItemThumbnailOverlayRenderer = try values.decodeIfPresent(MusicItemThumbnailOverlayRenderer.self, forKey: .musicItemThumbnailOverlayRenderer)
|
||
}
|
||
struct MusicItemThumbnailOverlayRenderer: Codable {
|
||
let content:Content?
|
||
enum CodingKeys: String, CodingKey {
|
||
case content = "content"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
content = try values.decodeIfPresent(Content.self, forKey: .content)
|
||
}
|
||
struct Content: Codable {
|
||
let musicPlayButtonRenderer:MusicPlayButtonRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicPlayButtonRenderer = "musicPlayButtonRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicPlayButtonRenderer = try values.decodeIfPresent(MusicPlayButtonRenderer.self, forKey: .musicPlayButtonRenderer)
|
||
}
|
||
struct MusicPlayButtonRenderer: Codable {
|
||
let playNavigationEndpoint:PlayNavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case playNavigationEndpoint = "playNavigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
playNavigationEndpoint = try values.decodeIfPresent(PlayNavigationEndpoint.self, forKey: .playNavigationEndpoint)
|
||
}
|
||
struct PlayNavigationEndpoint: 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)
|
||
}
|
||
|
||
//MARK: - 关键内容,视频ID/列表ID/参数
|
||
struct WatchEndpoint: Codable {
|
||
///视频ID
|
||
let videoId:String?
|
||
///视频列表
|
||
let playlistId:String?
|
||
///参数
|
||
let params:String?
|
||
///播放类型
|
||
let watchEndpointMusicSupportedConfigs:WatchEndpointMusicSupportedConfigs?
|
||
enum CodingKeys: String, CodingKey {
|
||
case videoId = "videoId"
|
||
case playlistId = "playlistId"
|
||
case params = "params"
|
||
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)
|
||
params = try values.decodeIfPresent(String.self, forKey: .params)
|
||
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)
|
||
}
|
||
//MARK: - 敲定Video类型
|
||
struct WatchEndpointMusicConfig: Codable {
|
||
///这个值存在,那么这个预览例就是Video,具体是什么由这个值判断
|
||
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内容)
|
||
struct RootMusicTwoRowItemRenderer: Codable {
|
||
///指向图像内容
|
||
let thumbnailRenderer:ThumbnailRenderer?
|
||
///指向主标题
|
||
let title:Title?
|
||
///指向副标题
|
||
let subtitle:Subtitle?
|
||
///指向列表ID和视频ID
|
||
let thumbnailOverlay:ThumbnailOverlay?
|
||
///指向视频内容
|
||
let navigationEndpoint:NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnailRenderer = "thumbnailRenderer"
|
||
case title = "title"
|
||
case subtitle = "subtitle"
|
||
case thumbnailOverlay = "thumbnailOverlay"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.thumbnailRenderer = try values.decodeIfPresent(ThumbnailRenderer.self, forKey: .thumbnailRenderer)
|
||
self.title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||
self.subtitle = try values.decodeIfPresent(Subtitle.self, forKey: .subtitle)
|
||
self.thumbnailOverlay = try values.decodeIfPresent(ThumbnailOverlay.self, forKey: .thumbnailOverlay)
|
||
self.navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct ThumbnailRenderer: Codable {
|
||
let musicThumbnailRenderer:MusicThumbnailRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicThumbnailRenderer = "musicThumbnailRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.musicThumbnailRenderer = try values.decodeIfPresent(MusicThumbnailRenderer.self, forKey: .musicThumbnailRenderer)
|
||
}
|
||
struct MusicThumbnailRenderer: Codable {
|
||
let thumbnail:Thumbnail?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnail = "thumbnail"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.thumbnail = try values.decodeIfPresent(Thumbnail.self, forKey: .thumbnail)
|
||
}
|
||
struct Thumbnail: Codable {
|
||
///封面图片组(默认取最后一位,图像内容最大最高清)
|
||
let thumbnails:[Thumbnails]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnails = "thumbnails"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.thumbnails = try values.decodeIfPresent([Thumbnails].self, forKey: .thumbnails)
|
||
}
|
||
//MARK: - 封面图片
|
||
///封面图片
|
||
struct Thumbnails: Codable {
|
||
///封面图片路径
|
||
let url:String?
|
||
let width:CGFloat?
|
||
let height:CGFloat?
|
||
enum CodingKeys: String, CodingKey {
|
||
case url = "url"
|
||
case width = "width"
|
||
case height = "height"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
url = try values.decodeIfPresent(String.self, forKey: .url)
|
||
width = try values.decodeIfPresent(CGFloat.self, forKey: .width)
|
||
height = try values.decodeIfPresent(CGFloat.self, forKey: .height)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
struct Title: Codable {
|
||
let runs:[Run]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case runs = "runs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
//MARK: - 文本内容,标题/作者/专辑
|
||
struct Run: Codable {
|
||
///关键文本内容(代表各级标题)
|
||
let text:String?
|
||
///指向预览ID
|
||
let navigationEndpoint: NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct NavigationEndpoint: Codable {
|
||
let browseEndpoint:BrowseEndpoint?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
|
||
}
|
||
//MARK: - 展示内容块的预览内容
|
||
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 {
|
||
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)
|
||
}
|
||
//MARK: - Browse类型 作者/歌单/专辑
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
struct Subtitle: Codable {
|
||
let runs:[Run]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case runs = "runs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
//MARK: - 文本内容,标题/作者/专辑
|
||
struct Run: Codable {
|
||
///关键文本内容(代表各级标题)
|
||
let text:String?
|
||
///指向预览ID
|
||
let navigationEndpoint: NavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
case navigationEndpoint = "navigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
navigationEndpoint = try values.decodeIfPresent(NavigationEndpoint.self, forKey: .navigationEndpoint)
|
||
}
|
||
struct NavigationEndpoint: Codable {
|
||
let browseEndpoint:BrowseEndpoint?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
|
||
}
|
||
//MARK: - 展示内容块的预览内容
|
||
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 {
|
||
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)
|
||
}
|
||
//MARK: - Browse类型 作者/歌单/专辑
|
||
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)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
struct ThumbnailOverlay: Codable {
|
||
let musicItemThumbnailOverlayRenderer:MusicItemThumbnailOverlayRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicItemThumbnailOverlayRenderer = "musicItemThumbnailOverlayRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.musicItemThumbnailOverlayRenderer = try values.decodeIfPresent(MusicItemThumbnailOverlayRenderer.self, forKey: .musicItemThumbnailOverlayRenderer)
|
||
}
|
||
struct MusicItemThumbnailOverlayRenderer: Codable {
|
||
let content:Content?
|
||
enum CodingKeys: String, CodingKey {
|
||
case content = "content"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.content = try values.decodeIfPresent(Content.self, forKey: .content)
|
||
}
|
||
struct Content: Codable {
|
||
let musicPlayButtonRenderer:MusicPlayButtonRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicPlayButtonRenderer = "musicPlayButtonRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.musicPlayButtonRenderer = try values.decodeIfPresent(MusicPlayButtonRenderer.self, forKey: .musicPlayButtonRenderer)
|
||
}
|
||
struct MusicPlayButtonRenderer: Codable {
|
||
let playNavigationEndpoint:PlayNavigationEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case playNavigationEndpoint = "playNavigationEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.playNavigationEndpoint = try values.decodeIfPresent(PlayNavigationEndpoint.self, forKey: .playNavigationEndpoint)
|
||
}
|
||
struct PlayNavigationEndpoint: Codable {
|
||
let watchPlaylistEndpoint:WatchPlaylistEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case watchPlaylistEndpoint = "watchPlaylistEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
watchPlaylistEndpoint = try values.decodeIfPresent(WatchPlaylistEndpoint.self, forKey: .watchPlaylistEndpoint)
|
||
}
|
||
|
||
//MARK: - 列表/专辑ID
|
||
struct WatchPlaylistEndpoint: 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 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)
|
||
self.watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint)
|
||
|
||
}
|
||
struct WatchEndpoint: Codable {
|
||
let videoId:String?
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case videoId = "videoId"
|
||
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
self.videoId = try values.decodeIfPresent(String.self, forKey: .videoId)
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|