470 lines
33 KiB
Swift
470 lines
33 KiB
Swift
//
|
||
// MPPositive_JsonSearchResults.swift
|
||
// MusicPlayer
|
||
//
|
||
// Created by Mr.Zhou on 2024/5/12.
|
||
//
|
||
|
||
import UIKit
|
||
//MARK: - 搜索结果结构
|
||
///搜索预览结果结构
|
||
struct JsonSearchPreviewResults: Codable {
|
||
let contents:Contents?
|
||
enum CodingKeys: String, CodingKey {
|
||
case contents = "contents"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
contents = try values.decodeIfPresent(Contents.self, forKey: .contents)
|
||
}
|
||
struct Contents: Codable {
|
||
let tabbedSearchResultsRenderer:TabbedSearchResultsRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case tabbedSearchResultsRenderer = "tabbedSearchResultsRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
tabbedSearchResultsRenderer = try values.decodeIfPresent(TabbedSearchResultsRenderer.self, forKey: .tabbedSearchResultsRenderer)
|
||
}
|
||
struct TabbedSearchResultsRenderer: Codable {
|
||
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 {
|
||
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 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)
|
||
}
|
||
struct SectionListRenderer: Codable {
|
||
///模块(每个模块内容不一样)
|
||
let contents:[Content]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case contents = "contents"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
}
|
||
//MARK: - 模块
|
||
struct Content: Codable {
|
||
///最佳结果
|
||
let musicCardShelfRenderer:MusicCardShelfRenderer?
|
||
///其他结果(同时还有更多内容键值)
|
||
let musicShelfRenderer:MusicShelfRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCardShelfRenderer = "musicCardShelfRenderer"
|
||
case musicShelfRenderer = "musicShelfRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCardShelfRenderer = try values.decodeIfPresent(MusicCardShelfRenderer.self, forKey: .musicCardShelfRenderer)
|
||
musicShelfRenderer = try values.decodeIfPresent(MusicShelfRenderer.self, forKey: .musicShelfRenderer)
|
||
}
|
||
//MARK: - 不同模块携带的内容
|
||
///最佳结果
|
||
struct MusicCardShelfRenderer: Codable {
|
||
///最佳结果封面
|
||
let thumbnail:Thumbnail?
|
||
///最佳结果标题(附带单曲ID)
|
||
let title:Title?
|
||
///最佳结果副标题
|
||
let subtitle:Subtitle?
|
||
///菜单操作(某些情况下flexColumns无法拿到playListId)
|
||
let menu:Menu?
|
||
///最佳结果组头标题
|
||
let header:Header?
|
||
///最佳结果其他内容,第0位是无用数据,获取时跳过
|
||
let contents:[Content]?
|
||
enum CodingKeys: String, CodingKey {
|
||
case thumbnail = "thumbnail"
|
||
case title = "title"
|
||
case subtitle = "subtitle"
|
||
case menu = "menu"
|
||
case header = "header"
|
||
case contents = "contents"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
thumbnail = try values.decodeIfPresent(Thumbnail.self, forKey: .thumbnail)
|
||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||
subtitle = try values.decodeIfPresent(Subtitle.self, forKey: .subtitle)
|
||
menu = try values.decodeIfPresent(Menu.self, forKey: .menu)
|
||
header = try values.decodeIfPresent(Header.self, forKey: .header)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
}
|
||
///最佳结果封面
|
||
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)
|
||
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)
|
||
thumbnails = try values.decodeIfPresent([Thumbnails].self, forKey: .thumbnails)
|
||
}
|
||
struct Thumbnails: Codable {
|
||
let url:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case url = "url"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
url = try values.decodeIfPresent(String.self, forKey: .url)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///最佳结果标题
|
||
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)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
struct Run: Codable {
|
||
///标题文本
|
||
let text:String?
|
||
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 watchEndpoint:WatchEndpoint?
|
||
///这个值存在就是艺术家/专辑/列表
|
||
let browseEndpoint:BrowseEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case watchEndpoint = "watchEndpoint"
|
||
case browseEndpoint = "browseEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
watchEndpoint = try values.decodeIfPresent(WatchEndpoint.self, forKey: .watchEndpoint)
|
||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||
}
|
||
struct WatchEndpoint: Codable {
|
||
let videoId:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case videoId = "videoId"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
videoId = try values.decodeIfPresent(String.self, forKey: .videoId)
|
||
}
|
||
}
|
||
struct BrowseEndpoint: Codable {
|
||
let browseId:String?
|
||
let browseEndpointContextSupportedConfigs:BrowseEndpointContextSupportedConfigs?
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseId = "browseId"
|
||
case browseEndpointContextSupportedConfigs = "browseEndpointContextSupportedConfigs"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseId = try values.decodeIfPresent(String.self, forKey: .browseId)
|
||
browseEndpointContextSupportedConfigs = try values.decodeIfPresent(BrowseEndpointContextSupportedConfigs.self, forKey: .browseEndpointContextSupportedConfigs)
|
||
}
|
||
struct BrowseEndpointContextSupportedConfigs: Codable {
|
||
let browseEndpointContextMusicConfig:BrowseEndpointContextMusicConfig?
|
||
enum CodingKeys: String, CodingKey {
|
||
case browseEndpointContextMusicConfig = "browseEndpointContextMusicConfig"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
browseEndpointContextMusicConfig = try values.decodeIfPresent(BrowseEndpointContextMusicConfig.self, forKey: .browseEndpointContextMusicConfig)
|
||
}
|
||
struct BrowseEndpointContextMusicConfig: Codable {
|
||
let pageType:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case pageType = "pageType"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
pageType = try values.decodeIfPresent(String.self, forKey: .pageType)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///最佳结果副标题
|
||
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)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
struct Run: Codable {
|
||
///标题文本
|
||
let text:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
}
|
||
}
|
||
}
|
||
///菜单操作
|
||
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 Header: Codable {
|
||
let musicCardShelfHeaderBasicRenderer:MusicCardShelfHeaderBasicRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicCardShelfHeaderBasicRenderer = "musicCardShelfHeaderBasicRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicCardShelfHeaderBasicRenderer = try values.decodeIfPresent(MusicCardShelfHeaderBasicRenderer.self, forKey: .musicCardShelfHeaderBasicRenderer)
|
||
}
|
||
struct MusicCardShelfHeaderBasicRenderer: 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 {
|
||
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)
|
||
}
|
||
|
||
struct Run: Codable {
|
||
///标题文本
|
||
let text:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
///最佳结果其他内容
|
||
struct Content: Codable {
|
||
let musicResponsiveListItemRenderer:RootMusicResponsiveListItemRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicResponsiveListItemRenderer = "musicResponsiveListItemRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicResponsiveListItemRenderer = try values.decodeIfPresent(RootMusicResponsiveListItemRenderer.self, forKey: .musicResponsiveListItemRenderer)
|
||
}
|
||
}
|
||
}
|
||
///其他结果
|
||
struct MusicShelfRenderer: Codable {
|
||
///模块标题
|
||
let title:Title?
|
||
///模块内容
|
||
let contents:[Content]?
|
||
///更多内容
|
||
let bottomEndpoint:BottomEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case title = "title"
|
||
case contents = "contents"
|
||
case bottomEndpoint = "bottomEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||
bottomEndpoint = try values.decodeIfPresent(BottomEndpoint.self, forKey: .bottomEndpoint)
|
||
}
|
||
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)
|
||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||
}
|
||
|
||
struct Run: Codable {
|
||
///标题文本
|
||
let text:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case text = "text"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||
}
|
||
}
|
||
}
|
||
struct Content: Codable {
|
||
let musicResponsiveListItemRenderer:RootMusicResponsiveListItemRenderer?
|
||
enum CodingKeys: String, CodingKey {
|
||
case musicResponsiveListItemRenderer = "musicResponsiveListItemRenderer"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
musicResponsiveListItemRenderer = try values.decodeIfPresent(RootMusicResponsiveListItemRenderer.self, forKey: .musicResponsiveListItemRenderer)
|
||
}
|
||
}
|
||
struct BottomEndpoint: Codable {
|
||
let searchEndpoint:SearchEndpoint?
|
||
enum CodingKeys: String, CodingKey {
|
||
case searchEndpoint = "searchEndpoint"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
searchEndpoint = try values.decodeIfPresent(SearchEndpoint.self, forKey: .searchEndpoint)
|
||
}
|
||
struct SearchEndpoint: Codable {
|
||
///当前搜索文本
|
||
let query:String?
|
||
///更多内容参数
|
||
let params:String?
|
||
enum CodingKeys: String, CodingKey {
|
||
case query = "query"
|
||
case params = "params"
|
||
}
|
||
init(from decoder: Decoder) throws {
|
||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||
query = try values.decodeIfPresent(String.self, forKey: .query)
|
||
params = try values.decodeIfPresent(String.self, forKey: .params)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|