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) } } } }