From 41a4947db20f4b837704ef6a0c916f57aef47c3d Mon Sep 17 00:00:00 2001 From: Mattia Date: Mon, 21 Sep 2020 17:34:03 +0200 Subject: [PATCH] More Types --- CHANGELOG.md | 8 +- .../generated/player_response_json.g.dart | 237 + .../generated/playlist_response.g.dart | 2 +- .../responses/generated/search_page_id.g.dart | 6436 ++++++++++++++ .../responses/generated/watch_page_id.g.dart | 7659 +++++++++++++++++ .../responses/playlist_response.dart | 5 +- .../responses/search_page.dart | 246 +- .../responses/watch_page.dart | 129 +- lib/src/search/base_search_content.dart | 5 + lib/src/search/related_query.dart | 10 +- lib/src/search/search_client.dart | 40 +- lib/src/search/search_playlist.dart | 5 +- lib/src/search/search_video.dart | 3 +- lib/src/videos/comments/comments_client.dart | 2 + lib/src/videos/streams/streams_client.dart | 5 +- lib/src/videos/video_client.dart | 6 +- test/closed_caption_test.dart | 10 +- test/comments_client_test.dart | 2 +- test/search_test.dart | 10 +- 19 files changed, 14554 insertions(+), 266 deletions(-) create mode 100644 lib/src/reverse_engineering/responses/generated/player_response_json.g.dart create mode 100644 lib/src/reverse_engineering/responses/generated/search_page_id.g.dart create mode 100644 lib/src/reverse_engineering/responses/generated/watch_page_id.g.dart create mode 100644 lib/src/search/base_search_content.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index f0d10fa..3766a39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,16 @@ - Only throw custom exceptions from the library. - `getUploadsFromPage` no longer throws. +## 1.5.1 +- BREAKING CHANGE: Renamed `getVideosAsync` to `getVideos`. +- Implemented `getVideosFromPage` which supersedes `queryFromPage`. +- Implemented JSON Classes for reverse engineer. +- Added `forceWatchPage` to the video client to assure the fetching of the video page. (ATM useful only if using the comments api) +- Remove adaptive streams. These are not used anymore. + ## 1.5.0 - BREAKING CHANGE: Renamed `Container` class to `StreamContainer` to avoid conflicting with Flutter `Container`. See #66 - ## 1.4.4 - Expose HttpClient in APIs - Fix #55: Typo in README.md diff --git a/lib/src/reverse_engineering/responses/generated/player_response_json.g.dart b/lib/src/reverse_engineering/responses/generated/player_response_json.g.dart new file mode 100644 index 0000000..f69e948 --- /dev/null +++ b/lib/src/reverse_engineering/responses/generated/player_response_json.g.dart @@ -0,0 +1,237 @@ +// To parse this JSON data, do +// +// final playerConfigJson = playerConfigJsonFromJson(jsonString); + +import 'dart:convert'; + +class PlayerConfigJson { + PlayerConfigJson({ + this.assets, + this.attrs, + this.args, + }); + + final Assets assets; + final Attrs attrs; + final Args args; + + factory PlayerConfigJson.fromRawJson(String str) => + PlayerConfigJson.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PlayerConfigJson.fromJson(Map json) => + PlayerConfigJson( + assets: json["assets"] == null ? null : Assets.fromJson(json["assets"]), + attrs: json["attrs"] == null ? null : Attrs.fromJson(json["attrs"]), + args: json["args"] == null ? null : Args.fromJson(json["args"]), + ); + + Map toJson() => { + "assets": assets == null ? null : assets.toJson(), + "attrs": attrs == null ? null : attrs.toJson(), + "args": args == null ? null : args.toJson(), + }; +} + +class Args { + Args({ + this.innertubeApiKey, + this.showMiniplayerButton, + this.useMiniplayerUi, + this.gapiHintParams, + this.playerResponse, + this.cbrver, + this.cbr, + this.innertubeApiVersion, + this.innertubeContextClientVersion, + this.vssHost, + this.hostLanguage, + this.cr, + this.externalFullscreen, + this.useFastSizingOnWatchDefault, + this.c, + this.ps, + this.csiPageType, + this.cos, + this.enablecsi, + this.watermark, + this.cver, + this.transparentBackground, + this.hl, + this.enablejsapi, + this.cosver, + this.loaderUrl, + }); + + final String innertubeApiKey; + final String showMiniplayerButton; + final String useMiniplayerUi; + final String gapiHintParams; + final String playerResponse; + final String cbrver; + final String cbr; + final String innertubeApiVersion; + final String innertubeContextClientVersion; + final String vssHost; + final String hostLanguage; + final String cr; + final bool externalFullscreen; + final bool useFastSizingOnWatchDefault; + final String c; + final String ps; + final String csiPageType; + final String cos; + final String enablecsi; + final String watermark; + final String cver; + final String transparentBackground; + final String hl; + final String enablejsapi; + final String cosver; + final String loaderUrl; + + factory Args.fromRawJson(String str) => Args.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Args.fromJson(Map json) => Args( + innertubeApiKey: json["innertube_api_key"] == null + ? null + : json["innertube_api_key"], + showMiniplayerButton: json["show_miniplayer_button"] == null + ? null + : json["show_miniplayer_button"], + useMiniplayerUi: json["use_miniplayer_ui"] == null + ? null + : json["use_miniplayer_ui"], + gapiHintParams: + json["gapi_hint_params"] == null ? null : json["gapi_hint_params"], + playerResponse: + json["player_response"] == null ? null : json["player_response"], + cbrver: json["cbrver"] == null ? null : json["cbrver"], + cbr: json["cbr"] == null ? null : json["cbr"], + innertubeApiVersion: json["innertube_api_version"] == null + ? null + : json["innertube_api_version"], + innertubeContextClientVersion: + json["innertube_context_client_version"] == null + ? null + : json["innertube_context_client_version"], + vssHost: json["vss_host"] == null ? null : json["vss_host"], + hostLanguage: + json["host_language"] == null ? null : json["host_language"], + cr: json["cr"] == null ? null : json["cr"], + externalFullscreen: json["external_fullscreen"] == null + ? null + : json["external_fullscreen"], + useFastSizingOnWatchDefault: + json["use_fast_sizing_on_watch_default"] == null + ? null + : json["use_fast_sizing_on_watch_default"], + c: json["c"] == null ? null : json["c"], + ps: json["ps"] == null ? null : json["ps"], + csiPageType: + json["csi_page_type"] == null ? null : json["csi_page_type"], + cos: json["cos"] == null ? null : json["cos"], + enablecsi: json["enablecsi"] == null ? null : json["enablecsi"], + watermark: json["watermark"] == null ? null : json["watermark"], + cver: json["cver"] == null ? null : json["cver"], + transparentBackground: json["transparent_background"] == null + ? null + : json["transparent_background"], + hl: json["hl"] == null ? null : json["hl"], + enablejsapi: json["enablejsapi"] == null ? null : json["enablejsapi"], + cosver: json["cosver"] == null ? null : json["cosver"], + loaderUrl: json["loaderUrl"] == null ? null : json["loaderUrl"], + ); + + Map toJson() => { + "innertube_api_key": innertubeApiKey == null ? null : innertubeApiKey, + "show_miniplayer_button": + showMiniplayerButton == null ? null : showMiniplayerButton, + "use_miniplayer_ui": useMiniplayerUi == null ? null : useMiniplayerUi, + "gapi_hint_params": gapiHintParams == null ? null : gapiHintParams, + "player_response": playerResponse == null ? null : playerResponse, + "cbrver": cbrver == null ? null : cbrver, + "cbr": cbr == null ? null : cbr, + "innertube_api_version": + innertubeApiVersion == null ? null : innertubeApiVersion, + "innertube_context_client_version": + innertubeContextClientVersion == null + ? null + : innertubeContextClientVersion, + "vss_host": vssHost == null ? null : vssHost, + "host_language": hostLanguage == null ? null : hostLanguage, + "cr": cr == null ? null : cr, + "external_fullscreen": + externalFullscreen == null ? null : externalFullscreen, + "use_fast_sizing_on_watch_default": useFastSizingOnWatchDefault == null + ? null + : useFastSizingOnWatchDefault, + "c": c == null ? null : c, + "ps": ps == null ? null : ps, + "csi_page_type": csiPageType == null ? null : csiPageType, + "cos": cos == null ? null : cos, + "enablecsi": enablecsi == null ? null : enablecsi, + "watermark": watermark == null ? null : watermark, + "cver": cver == null ? null : cver, + "transparent_background": + transparentBackground == null ? null : transparentBackground, + "hl": hl == null ? null : hl, + "enablejsapi": enablejsapi == null ? null : enablejsapi, + "cosver": cosver == null ? null : cosver, + "loaderUrl": loaderUrl == null ? null : loaderUrl, + }; +} + +class Assets { + Assets({ + this.playerCanaryState, + this.js, + this.css, + }); + + final String playerCanaryState; + final String js; + final String css; + + factory Assets.fromRawJson(String str) => Assets.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Assets.fromJson(Map json) => Assets( + playerCanaryState: json["player_canary_state"] == null + ? null + : json["player_canary_state"], + js: json["js"] == null ? null : json["js"], + css: json["css"] == null ? null : json["css"], + ); + + Map toJson() => { + "player_canary_state": + playerCanaryState == null ? null : playerCanaryState, + "js": js == null ? null : js, + "css": css == null ? null : css, + }; +} + +class Attrs { + Attrs({ + this.id, + }); + + final String id; + + factory Attrs.fromRawJson(String str) => Attrs.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Attrs.fromJson(Map json) => Attrs( + id: json["id"] == null ? null : json["id"], + ); + + Map toJson() => { + "id": id == null ? null : id, + }; +} diff --git a/lib/src/reverse_engineering/responses/generated/playlist_response.g.dart b/lib/src/reverse_engineering/responses/generated/playlist_response.g.dart index 8348f7f..20b7d84 100644 --- a/lib/src/reverse_engineering/responses/generated/playlist_response.g.dart +++ b/lib/src/reverse_engineering/responses/generated/playlist_response.g.dart @@ -85,7 +85,7 @@ class Video { final int timeCreated; final bool ccLicense; final String title; - final int rating; + final num rating; final bool isHd; final Privacy privacy; final int lengthSeconds; diff --git a/lib/src/reverse_engineering/responses/generated/search_page_id.g.dart b/lib/src/reverse_engineering/responses/generated/search_page_id.g.dart new file mode 100644 index 0000000..6e2bcaa --- /dev/null +++ b/lib/src/reverse_engineering/responses/generated/search_page_id.g.dart @@ -0,0 +1,6436 @@ +// To parse this JSON data, do +// +// final searchPageId = searchPageIdFromJson(jsonString); + +import 'dart:convert'; + +class SearchPageId { + SearchPageId({ + this.responseContext, + this.estimatedResults, + this.contents, + this.trackingParams, + this.topbar, + this.adSafetyReason, + this.refinements, + this.onResponseReceivedCommands, + }); + + final ResponseContext responseContext; + final String estimatedResults; + final Contents contents; + final String trackingParams; + final Topbar topbar; + final AdSafetyReason adSafetyReason; + final List refinements; + final List onResponseReceivedCommands; + + factory SearchPageId.fromRawJson(String str) => + SearchPageId.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SearchPageId.fromJson(Map json) => SearchPageId( + responseContext: json["responseContext"] == null + ? null + : ResponseContext.fromJson(json["responseContext"]), + estimatedResults: + json["estimatedResults"] == null ? null : json["estimatedResults"], + contents: json["contents"] == null + ? null + : Contents.fromJson(json["contents"]), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + topbar: json["topbar"] == null ? null : Topbar.fromJson(json["topbar"]), + adSafetyReason: json["adSafetyReason"] == null + ? null + : AdSafetyReason.fromJson(json["adSafetyReason"]), + refinements: json["refinements"] == null + ? null + : List.from(json["refinements"].map((x) => x)), + onResponseReceivedCommands: json["onResponseReceivedCommands"] == null + ? null + : List.from( + json["onResponseReceivedCommands"] + .map((x) => OnResponseReceivedCommand.fromJson(x))), + ); + + Map toJson() => { + "responseContext": + responseContext == null ? null : responseContext.toJson(), + "estimatedResults": estimatedResults == null ? null : estimatedResults, + "contents": contents == null ? null : contents.toJson(), + "trackingParams": trackingParams == null ? null : trackingParams, + "topbar": topbar == null ? null : topbar.toJson(), + "adSafetyReason": + adSafetyReason == null ? null : adSafetyReason.toJson(), + "refinements": refinements == null + ? null + : List.from(refinements.map((x) => x)), + "onResponseReceivedCommands": onResponseReceivedCommands == null + ? null + : List.from( + onResponseReceivedCommands.map((x) => x.toJson())), + }; +} + +class AdSafetyReason { + AdSafetyReason({ + this.apmUserPreference, + this.isWebAndAppActivityEnabled, + }); + + final ApmUserPreference apmUserPreference; + final bool isWebAndAppActivityEnabled; + + factory AdSafetyReason.fromRawJson(String str) => + AdSafetyReason.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory AdSafetyReason.fromJson(Map json) => AdSafetyReason( + apmUserPreference: json["apmUserPreference"] == null + ? null + : ApmUserPreference.fromJson(json["apmUserPreference"]), + isWebAndAppActivityEnabled: json["isWebAndAppActivityEnabled"] == null + ? null + : json["isWebAndAppActivityEnabled"], + ); + + Map toJson() => { + "apmUserPreference": + apmUserPreference == null ? null : apmUserPreference.toJson(), + "isWebAndAppActivityEnabled": isWebAndAppActivityEnabled == null + ? null + : isWebAndAppActivityEnabled, + }; +} + +class ApmUserPreference { + ApmUserPreference(); + + factory ApmUserPreference.fromRawJson(String str) => + ApmUserPreference.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ApmUserPreference.fromJson(Map json) => + ApmUserPreference(); + + Map toJson() => {}; +} + +class Contents { + Contents({ + this.twoColumnSearchResultsRenderer, + }); + + final TwoColumnSearchResultsRenderer twoColumnSearchResultsRenderer; + + factory Contents.fromRawJson(String str) => + Contents.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Contents.fromJson(Map json) => Contents( + twoColumnSearchResultsRenderer: + json["twoColumnSearchResultsRenderer"] == null + ? null + : TwoColumnSearchResultsRenderer.fromJson( + json["twoColumnSearchResultsRenderer"]), + ); + + Map toJson() => { + "twoColumnSearchResultsRenderer": twoColumnSearchResultsRenderer == null + ? null + : twoColumnSearchResultsRenderer.toJson(), + }; +} + +class TwoColumnSearchResultsRenderer { + TwoColumnSearchResultsRenderer({ + this.primaryContents, + }); + + final PrimaryContents primaryContents; + + factory TwoColumnSearchResultsRenderer.fromRawJson(String str) => + TwoColumnSearchResultsRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory TwoColumnSearchResultsRenderer.fromJson(Map json) => + TwoColumnSearchResultsRenderer( + primaryContents: json["primaryContents"] == null + ? null + : PrimaryContents.fromJson(json["primaryContents"]), + ); + + Map toJson() => { + "primaryContents": + primaryContents == null ? null : primaryContents.toJson(), + }; +} + +class PrimaryContents { + PrimaryContents({ + this.sectionListRenderer, + }); + + final SectionListRenderer sectionListRenderer; + + factory PrimaryContents.fromRawJson(String str) => + PrimaryContents.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PrimaryContents.fromJson(Map json) => + PrimaryContents( + sectionListRenderer: json["sectionListRenderer"] == null + ? null + : SectionListRenderer.fromJson(json["sectionListRenderer"]), + ); + + Map toJson() => { + "sectionListRenderer": + sectionListRenderer == null ? null : sectionListRenderer.toJson(), + }; +} + +class SectionListRenderer { + SectionListRenderer({ + this.contents, + this.trackingParams, + this.subMenu, + this.hideBottomSeparator, + this.targetId, + }); + + final List contents; + final String trackingParams; + final SubMenu subMenu; + final bool hideBottomSeparator; + final String targetId; + + factory SectionListRenderer.fromRawJson(String str) => + SectionListRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SectionListRenderer.fromJson(Map json) => + SectionListRenderer( + contents: json["contents"] == null + ? null + : List.from(json["contents"] + .map((x) => SectionListRendererContent.fromJson(x))), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + subMenu: + json["subMenu"] == null ? null : SubMenu.fromJson(json["subMenu"]), + hideBottomSeparator: json["hideBottomSeparator"] == null + ? null + : json["hideBottomSeparator"], + targetId: json["targetId"] == null ? null : json["targetId"], + ); + + Map toJson() => { + "contents": contents == null + ? null + : List.from(contents.map((x) => x.toJson())), + "trackingParams": trackingParams == null ? null : trackingParams, + "subMenu": subMenu == null ? null : subMenu.toJson(), + "hideBottomSeparator": + hideBottomSeparator == null ? null : hideBottomSeparator, + "targetId": targetId == null ? null : targetId, + }; +} + +class SectionListRendererContent { + SectionListRendererContent({ + this.itemSectionRenderer, + this.continuationItemRenderer, + }); + + final ContentItemSectionRenderer itemSectionRenderer; + final ContinuationItemRenderer continuationItemRenderer; + + factory SectionListRendererContent.fromRawJson(String str) => + SectionListRendererContent.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SectionListRendererContent.fromJson(Map json) => + SectionListRendererContent( + itemSectionRenderer: json["itemSectionRenderer"] == null + ? null + : ContentItemSectionRenderer.fromJson(json["itemSectionRenderer"]), + continuationItemRenderer: json["continuationItemRenderer"] == null + ? null + : ContinuationItemRenderer.fromJson( + json["continuationItemRenderer"]), + ); + + Map toJson() => { + "itemSectionRenderer": + itemSectionRenderer == null ? null : itemSectionRenderer.toJson(), + "continuationItemRenderer": continuationItemRenderer == null + ? null + : continuationItemRenderer.toJson(), + }; +} + +class ContinuationItemRenderer { + ContinuationItemRenderer({ + this.trigger, + this.continuationEndpoint, + }); + + final String trigger; + final ContinuationEndpoint continuationEndpoint; + + factory ContinuationItemRenderer.fromRawJson(String str) => + ContinuationItemRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ContinuationItemRenderer.fromJson(Map json) => + ContinuationItemRenderer( + trigger: json["trigger"] == null ? null : json["trigger"], + continuationEndpoint: json["continuationEndpoint"] == null + ? null + : ContinuationEndpoint.fromJson(json["continuationEndpoint"]), + ); + + Map toJson() => { + "trigger": trigger == null ? null : trigger, + "continuationEndpoint": + continuationEndpoint == null ? null : continuationEndpoint.toJson(), + }; +} + +class ContinuationEndpoint { + ContinuationEndpoint({ + this.clickTrackingParams, + this.commandMetadata, + this.continuationCommand, + }); + + final String clickTrackingParams; + final ContinuationEndpointCommandMetadata commandMetadata; + final ContinuationCommand continuationCommand; + + factory ContinuationEndpoint.fromRawJson(String str) => + ContinuationEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ContinuationEndpoint.fromJson(Map json) => + ContinuationEndpoint( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : ContinuationEndpointCommandMetadata.fromJson( + json["commandMetadata"]), + continuationCommand: json["continuationCommand"] == null + ? null + : ContinuationCommand.fromJson(json["continuationCommand"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "continuationCommand": + continuationCommand == null ? null : continuationCommand.toJson(), + }; +} + +class ContinuationEndpointCommandMetadata { + ContinuationEndpointCommandMetadata({ + this.webCommandMetadata, + }); + + final PurpleWebCommandMetadata webCommandMetadata; + + factory ContinuationEndpointCommandMetadata.fromRawJson(String str) => + ContinuationEndpointCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ContinuationEndpointCommandMetadata.fromJson( + Map json) => + ContinuationEndpointCommandMetadata( + webCommandMetadata: json["webCommandMetadata"] == null + ? null + : PurpleWebCommandMetadata.fromJson(json["webCommandMetadata"]), + ); + + Map toJson() => { + "webCommandMetadata": + webCommandMetadata == null ? null : webCommandMetadata.toJson(), + }; +} + +class PurpleWebCommandMetadata { + PurpleWebCommandMetadata({ + this.url, + this.sendPost, + this.apiUrl, + }); + + final Url url; + final bool sendPost; + final ApiUrl apiUrl; + + factory PurpleWebCommandMetadata.fromRawJson(String str) => + PurpleWebCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurpleWebCommandMetadata.fromJson(Map json) => + PurpleWebCommandMetadata( + url: json["url"] == null ? null : urlValues.map[json["url"]], + sendPost: json["sendPost"] == null ? null : json["sendPost"], + apiUrl: + json["apiUrl"] == null ? null : apiUrlValues.map[json["apiUrl"]], + ); + + Map toJson() => { + "url": url == null ? null : urlValues.reverse[url], + "sendPost": sendPost == null ? null : sendPost, + "apiUrl": apiUrl == null ? null : apiUrlValues.reverse[apiUrl], + }; +} + +enum ApiUrl { + YOUTUBEI_V1_SEARCH, + YOUTUBEI_V1_PLAYLIST_CREATE, + YOUTUBEI_V1_BROWSE_EDIT_PLAYLIST, + YOUTUBEI_V1_PLAYLIST_GET_ADD_TO_PLAYLIST, + YOUTUBEI_V1_FLAG_GET_FORM, + YOUTUBEI_V1_NOTIFICATION_GET_NOTIFICATION_MENU, + YOUTUBEI_V1_NOTIFICATION_GET_UNSEEN_COUNT, + YOUTUBEI_V1_ACCOUNT_ACCOUNT_MENU +} + +final apiUrlValues = EnumValues({ + "/youtubei/v1/account/account_menu": ApiUrl.YOUTUBEI_V1_ACCOUNT_ACCOUNT_MENU, + "/youtubei/v1/browse/edit_playlist": ApiUrl.YOUTUBEI_V1_BROWSE_EDIT_PLAYLIST, + "/youtubei/v1/flag/get_form": ApiUrl.YOUTUBEI_V1_FLAG_GET_FORM, + "/youtubei/v1/notification/get_notification_menu": + ApiUrl.YOUTUBEI_V1_NOTIFICATION_GET_NOTIFICATION_MENU, + "/youtubei/v1/notification/get_unseen_count": + ApiUrl.YOUTUBEI_V1_NOTIFICATION_GET_UNSEEN_COUNT, + "/youtubei/v1/playlist/create": ApiUrl.YOUTUBEI_V1_PLAYLIST_CREATE, + "/youtubei/v1/playlist/get_add_to_playlist": + ApiUrl.YOUTUBEI_V1_PLAYLIST_GET_ADD_TO_PLAYLIST, + "/youtubei/v1/search": ApiUrl.YOUTUBEI_V1_SEARCH +}); + +enum Url { SERVICE_AJAX } + +final urlValues = EnumValues({"/service_ajax": Url.SERVICE_AJAX}); + +class ContinuationCommand { + ContinuationCommand({ + this.token, + this.request, + }); + + final String token; + final String request; + + factory ContinuationCommand.fromRawJson(String str) => + ContinuationCommand.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ContinuationCommand.fromJson(Map json) => + ContinuationCommand( + token: json["token"] == null ? null : json["token"], + request: json["request"] == null ? null : json["request"], + ); + + Map toJson() => { + "token": token == null ? null : token, + "request": request == null ? null : request, + }; +} + +class ContentItemSectionRenderer { + ContentItemSectionRenderer({ + this.contents, + this.trackingParams, + }); + + final List contents; + final String trackingParams; + + factory ContentItemSectionRenderer.fromRawJson(String str) => + ContentItemSectionRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ContentItemSectionRenderer.fromJson(Map json) => + ContentItemSectionRenderer( + contents: json["contents"] == null + ? null + : List.from( + json["contents"].map((x) => PurpleContent.fromJson(x))), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + ); + + Map toJson() => { + "contents": contents == null + ? null + : List.from(contents.map((x) => x.toJson())), + "trackingParams": trackingParams == null ? null : trackingParams, + }; +} + +class PurpleContent { + PurpleContent({ + this.videoRenderer, + this.shelfRenderer, + this.radioRenderer, + this.horizontalCardListRenderer, + this.channelRenderer, + }); + + final PurpleVideoRenderer videoRenderer; + final ShelfRenderer shelfRenderer; + final RadioRenderer radioRenderer; + final HorizontalCardListRenderer horizontalCardListRenderer; + final ChannelRenderer channelRenderer; + + factory PurpleContent.fromRawJson(String str) => + PurpleContent.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurpleContent.fromJson(Map json) => PurpleContent( + videoRenderer: json["videoRenderer"] == null + ? null + : PurpleVideoRenderer.fromJson(json["videoRenderer"]), + shelfRenderer: json["shelfRenderer"] == null + ? null + : ShelfRenderer.fromJson(json["shelfRenderer"]), + radioRenderer: json["radioRenderer"] == null + ? null + : RadioRenderer.fromJson(json["radioRenderer"]), + horizontalCardListRenderer: json["horizontalCardListRenderer"] == null + ? null + : HorizontalCardListRenderer.fromJson( + json["horizontalCardListRenderer"]), + channelRenderer: json["channelRenderer"] == null + ? null + : ChannelRenderer.fromJson(json["channelRenderer"]), + ); + + Map toJson() => { + "videoRenderer": videoRenderer == null ? null : videoRenderer.toJson(), + "shelfRenderer": shelfRenderer == null ? null : shelfRenderer.toJson(), + "radioRenderer": radioRenderer == null ? null : radioRenderer.toJson(), + "horizontalCardListRenderer": horizontalCardListRenderer == null + ? null + : horizontalCardListRenderer.toJson(), + "channelRenderer": + channelRenderer == null ? null : channelRenderer.toJson(), + }; +} + +class ChannelRenderer { + ChannelRenderer({ + this.channelId, + this.title, + this.navigationEndpoint, + this.thumbnail, + this.descriptionSnippet, + this.shortBylineText, + this.videoCountText, + this.subscriptionButton, + this.subscriberCountText, + this.subscribeButton, + this.trackingParams, + this.longBylineText, + }); + + final String channelId; + final PublishedTimeText title; + final RunNavigationEndpoint navigationEndpoint; + final ChannelRendererThumbnail thumbnail; + final TitleClass descriptionSnippet; + final Text shortBylineText; + final TitleClass videoCountText; + final SubscriptionButton subscriptionButton; + final PublishedTimeText subscriberCountText; + final A11YSkipNavigationButtonClass subscribeButton; + final String trackingParams; + final Text longBylineText; + + factory ChannelRenderer.fromRawJson(String str) => + ChannelRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ChannelRenderer.fromJson(Map json) => + ChannelRenderer( + channelId: json["channelId"] == null ? null : json["channelId"], + title: json["title"] == null + ? null + : PublishedTimeText.fromJson(json["title"]), + navigationEndpoint: json["navigationEndpoint"] == null + ? null + : RunNavigationEndpoint.fromJson(json["navigationEndpoint"]), + thumbnail: json["thumbnail"] == null + ? null + : ChannelRendererThumbnail.fromJson(json["thumbnail"]), + descriptionSnippet: json["descriptionSnippet"] == null + ? null + : TitleClass.fromJson(json["descriptionSnippet"]), + shortBylineText: json["shortBylineText"] == null + ? null + : Text.fromJson(json["shortBylineText"]), + videoCountText: json["videoCountText"] == null + ? null + : TitleClass.fromJson(json["videoCountText"]), + subscriptionButton: json["subscriptionButton"] == null + ? null + : SubscriptionButton.fromJson(json["subscriptionButton"]), + subscriberCountText: json["subscriberCountText"] == null + ? null + : PublishedTimeText.fromJson(json["subscriberCountText"]), + subscribeButton: json["subscribeButton"] == null + ? null + : A11YSkipNavigationButtonClass.fromJson(json["subscribeButton"]), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + longBylineText: json["longBylineText"] == null + ? null + : Text.fromJson(json["longBylineText"]), + ); + + Map toJson() => { + "channelId": channelId == null ? null : channelId, + "title": title == null ? null : title.toJson(), + "navigationEndpoint": + navigationEndpoint == null ? null : navigationEndpoint.toJson(), + "thumbnail": thumbnail == null ? null : thumbnail.toJson(), + "descriptionSnippet": + descriptionSnippet == null ? null : descriptionSnippet.toJson(), + "shortBylineText": + shortBylineText == null ? null : shortBylineText.toJson(), + "videoCountText": + videoCountText == null ? null : videoCountText.toJson(), + "subscriptionButton": + subscriptionButton == null ? null : subscriptionButton.toJson(), + "subscriberCountText": + subscriberCountText == null ? null : subscriberCountText.toJson(), + "subscribeButton": + subscribeButton == null ? null : subscribeButton.toJson(), + "trackingParams": trackingParams == null ? null : trackingParams, + "longBylineText": + longBylineText == null ? null : longBylineText.toJson(), + }; +} + +class TitleClass { + TitleClass({ + this.runs, + }); + + final List runs; + + factory TitleClass.fromRawJson(String str) => + TitleClass.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory TitleClass.fromJson(Map json) => TitleClass( + runs: json["runs"] == null + ? null + : List.from(json["runs"].map((x) => TextRun.fromJson(x))), + ); + + Map toJson() => { + "runs": runs == null + ? null + : List.from(runs.map((x) => x.toJson())), + }; +} + +class TextRun { + TextRun({ + this.text, + }); + + final String text; + + factory TextRun.fromRawJson(String str) => TextRun.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory TextRun.fromJson(Map json) => TextRun( + text: json["text"] == null ? null : json["text"], + ); + + Map toJson() => { + "text": text == null ? null : text, + }; +} + +class Text { + Text({ + this.runs, + }); + + final List runs; + + factory Text.fromRawJson(String str) => Text.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Text.fromJson(Map json) => Text( + runs: json["runs"] == null + ? null + : List.from( + json["runs"].map((x) => LongBylineTextRun.fromJson(x))), + ); + + Map toJson() => { + "runs": runs == null + ? null + : List.from(runs.map((x) => x.toJson())), + }; +} + +class LongBylineTextRun { + LongBylineTextRun({ + this.text, + this.navigationEndpoint, + }); + + final String text; + final RunNavigationEndpoint navigationEndpoint; + + factory LongBylineTextRun.fromRawJson(String str) => + LongBylineTextRun.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory LongBylineTextRun.fromJson(Map json) => + LongBylineTextRun( + text: json["text"] == null ? null : json["text"], + navigationEndpoint: json["navigationEndpoint"] == null + ? null + : RunNavigationEndpoint.fromJson(json["navigationEndpoint"]), + ); + + Map toJson() => { + "text": text == null ? null : text, + "navigationEndpoint": + navigationEndpoint == null ? null : navigationEndpoint.toJson(), + }; +} + +class RunNavigationEndpoint { + RunNavigationEndpoint({ + this.clickTrackingParams, + this.commandMetadata, + this.browseEndpoint, + }); + + final String clickTrackingParams; + final NavigationEndpointCommandMetadata commandMetadata; + final NavigationEndpointBrowseEndpoint browseEndpoint; + + factory RunNavigationEndpoint.fromRawJson(String str) => + RunNavigationEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory RunNavigationEndpoint.fromJson(Map json) => + RunNavigationEndpoint( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : NavigationEndpointCommandMetadata.fromJson( + json["commandMetadata"]), + browseEndpoint: json["browseEndpoint"] == null + ? null + : NavigationEndpointBrowseEndpoint.fromJson(json["browseEndpoint"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "browseEndpoint": + browseEndpoint == null ? null : browseEndpoint.toJson(), + }; +} + +class NavigationEndpointBrowseEndpoint { + NavigationEndpointBrowseEndpoint({ + this.browseId, + this.canonicalBaseUrl, + }); + + final String browseId; + final String canonicalBaseUrl; + + factory NavigationEndpointBrowseEndpoint.fromRawJson(String str) => + NavigationEndpointBrowseEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NavigationEndpointBrowseEndpoint.fromJson( + Map json) => + NavigationEndpointBrowseEndpoint( + browseId: json["browseId"] == null ? null : json["browseId"], + canonicalBaseUrl: + json["canonicalBaseUrl"] == null ? null : json["canonicalBaseUrl"], + ); + + Map toJson() => { + "browseId": browseId == null ? null : browseId, + "canonicalBaseUrl": canonicalBaseUrl == null ? null : canonicalBaseUrl, + }; +} + +class NavigationEndpointCommandMetadata { + NavigationEndpointCommandMetadata({ + this.webCommandMetadata, + }); + + final FluffyWebCommandMetadata webCommandMetadata; + + factory NavigationEndpointCommandMetadata.fromRawJson(String str) => + NavigationEndpointCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NavigationEndpointCommandMetadata.fromJson( + Map json) => + NavigationEndpointCommandMetadata( + webCommandMetadata: json["webCommandMetadata"] == null + ? null + : FluffyWebCommandMetadata.fromJson(json["webCommandMetadata"]), + ); + + Map toJson() => { + "webCommandMetadata": + webCommandMetadata == null ? null : webCommandMetadata.toJson(), + }; +} + +class FluffyWebCommandMetadata { + FluffyWebCommandMetadata({ + this.url, + this.webPageType, + this.rootVe, + }); + + final String url; + final WebPageType webPageType; + final int rootVe; + + factory FluffyWebCommandMetadata.fromRawJson(String str) => + FluffyWebCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory FluffyWebCommandMetadata.fromJson(Map json) => + FluffyWebCommandMetadata( + url: json["url"] == null ? null : json["url"], + webPageType: json["webPageType"] == null + ? null + : webPageTypeValues.map[json["webPageType"]], + rootVe: json["rootVe"] == null ? null : json["rootVe"], + ); + + Map toJson() => { + "url": url == null ? null : url, + "webPageType": + webPageType == null ? null : webPageTypeValues.reverse[webPageType], + "rootVe": rootVe == null ? null : rootVe, + }; +} + +enum WebPageType { + WEB_PAGE_TYPE_CHANNEL, + WEB_PAGE_TYPE_UNKNOWN, + WEB_PAGE_TYPE_SEARCH, + WEB_PAGE_TYPE_WATCH, + WEB_PAGE_TYPE_BROWSE +} + +final webPageTypeValues = EnumValues({ + "WEB_PAGE_TYPE_BROWSE": WebPageType.WEB_PAGE_TYPE_BROWSE, + "WEB_PAGE_TYPE_CHANNEL": WebPageType.WEB_PAGE_TYPE_CHANNEL, + "WEB_PAGE_TYPE_SEARCH": WebPageType.WEB_PAGE_TYPE_SEARCH, + "WEB_PAGE_TYPE_UNKNOWN": WebPageType.WEB_PAGE_TYPE_UNKNOWN, + "WEB_PAGE_TYPE_WATCH": WebPageType.WEB_PAGE_TYPE_WATCH +}); + +class A11YSkipNavigationButtonClass { + A11YSkipNavigationButtonClass({ + this.buttonRenderer, + }); + + final A11YSkipNavigationButtonButtonRenderer buttonRenderer; + + factory A11YSkipNavigationButtonClass.fromRawJson(String str) => + A11YSkipNavigationButtonClass.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory A11YSkipNavigationButtonClass.fromJson(Map json) => + A11YSkipNavigationButtonClass( + buttonRenderer: json["buttonRenderer"] == null + ? null + : A11YSkipNavigationButtonButtonRenderer.fromJson( + json["buttonRenderer"]), + ); + + Map toJson() => { + "buttonRenderer": + buttonRenderer == null ? null : buttonRenderer.toJson(), + }; +} + +class A11YSkipNavigationButtonButtonRenderer { + A11YSkipNavigationButtonButtonRenderer({ + this.style, + this.size, + this.isDisabled, + this.text, + this.navigationEndpoint, + this.trackingParams, + this.command, + this.accessibility, + }); + + final ButtonRendererStyle style; + final Size size; + final bool isDisabled; + final TitleClass text; + final PurpleNavigationEndpoint navigationEndpoint; + final String trackingParams; + final Command command; + final ButtonRendererAccessibility accessibility; + + factory A11YSkipNavigationButtonButtonRenderer.fromRawJson(String str) => + A11YSkipNavigationButtonButtonRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory A11YSkipNavigationButtonButtonRenderer.fromJson( + Map json) => + A11YSkipNavigationButtonButtonRenderer( + style: json["style"] == null + ? null + : buttonRendererStyleValues.map[json["style"]], + size: json["size"] == null ? null : sizeValues.map[json["size"]], + isDisabled: json["isDisabled"] == null ? null : json["isDisabled"], + text: json["text"] == null ? null : TitleClass.fromJson(json["text"]), + navigationEndpoint: json["navigationEndpoint"] == null + ? null + : PurpleNavigationEndpoint.fromJson(json["navigationEndpoint"]), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + command: + json["command"] == null ? null : Command.fromJson(json["command"]), + accessibility: json["accessibility"] == null + ? null + : ButtonRendererAccessibility.fromJson(json["accessibility"]), + ); + + Map toJson() => { + "style": + style == null ? null : buttonRendererStyleValues.reverse[style], + "size": size == null ? null : sizeValues.reverse[size], + "isDisabled": isDisabled == null ? null : isDisabled, + "text": text == null ? null : text.toJson(), + "navigationEndpoint": + navigationEndpoint == null ? null : navigationEndpoint.toJson(), + "trackingParams": trackingParams == null ? null : trackingParams, + "command": command == null ? null : command.toJson(), + "accessibility": accessibility == null ? null : accessibility.toJson(), + }; +} + +class ButtonRendererAccessibility { + ButtonRendererAccessibility({ + this.label, + }); + + final String label; + + factory ButtonRendererAccessibility.fromRawJson(String str) => + ButtonRendererAccessibility.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ButtonRendererAccessibility.fromJson(Map json) => + ButtonRendererAccessibility( + label: json["label"] == null ? null : json["label"], + ); + + Map toJson() => { + "label": label == null ? null : label, + }; +} + +class Command { + Command({ + this.clickTrackingParams, + this.commandMetadata, + this.signalServiceEndpoint, + }); + + final String clickTrackingParams; + final CommandCommandMetadata commandMetadata; + final CommandSignalServiceEndpoint signalServiceEndpoint; + + factory Command.fromRawJson(String str) => Command.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Command.fromJson(Map json) => Command( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : CommandCommandMetadata.fromJson(json["commandMetadata"]), + signalServiceEndpoint: json["signalServiceEndpoint"] == null + ? null + : CommandSignalServiceEndpoint.fromJson( + json["signalServiceEndpoint"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "signalServiceEndpoint": signalServiceEndpoint == null + ? null + : signalServiceEndpoint.toJson(), + }; +} + +class CommandCommandMetadata { + CommandCommandMetadata({ + this.webCommandMetadata, + }); + + final TentacledWebCommandMetadata webCommandMetadata; + + factory CommandCommandMetadata.fromRawJson(String str) => + CommandCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CommandCommandMetadata.fromJson(Map json) => + CommandCommandMetadata( + webCommandMetadata: json["webCommandMetadata"] == null + ? null + : TentacledWebCommandMetadata.fromJson(json["webCommandMetadata"]), + ); + + Map toJson() => { + "webCommandMetadata": + webCommandMetadata == null ? null : webCommandMetadata.toJson(), + }; +} + +class TentacledWebCommandMetadata { + TentacledWebCommandMetadata({ + this.url, + this.sendPost, + }); + + final Url url; + final bool sendPost; + + factory TentacledWebCommandMetadata.fromRawJson(String str) => + TentacledWebCommandMetadata.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory TentacledWebCommandMetadata.fromJson(Map json) => + TentacledWebCommandMetadata( + url: json["url"] == null ? null : urlValues.map[json["url"]], + sendPost: json["sendPost"] == null ? null : json["sendPost"], + ); + + Map toJson() => { + "url": url == null ? null : urlValues.reverse[url], + "sendPost": sendPost == null ? null : sendPost, + }; +} + +class CommandSignalServiceEndpoint { + CommandSignalServiceEndpoint({ + this.signal, + this.actions, + }); + + final SignalEnum signal; + final List actions; + + factory CommandSignalServiceEndpoint.fromRawJson(String str) => + CommandSignalServiceEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory CommandSignalServiceEndpoint.fromJson(Map json) => + CommandSignalServiceEndpoint( + signal: json["signal"] == null + ? null + : signalEnumValues.map[json["signal"]], + actions: json["actions"] == null + ? null + : List.from( + json["actions"].map((x) => PurpleAction.fromJson(x))), + ); + + Map toJson() => { + "signal": signal == null ? null : signalEnumValues.reverse[signal], + "actions": actions == null + ? null + : List.from(actions.map((x) => x.toJson())), + }; +} + +class PurpleAction { + PurpleAction({ + this.clickTrackingParams, + this.signalAction, + }); + + final String clickTrackingParams; + final Signal signalAction; + + factory PurpleAction.fromRawJson(String str) => + PurpleAction.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurpleAction.fromJson(Map json) => PurpleAction( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + signalAction: json["signalAction"] == null + ? null + : Signal.fromJson(json["signalAction"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "signalAction": signalAction == null ? null : signalAction.toJson(), + }; +} + +class Signal { + Signal({ + this.signal, + }); + + final String signal; + + factory Signal.fromRawJson(String str) => Signal.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Signal.fromJson(Map json) => Signal( + signal: json["signal"] == null ? null : json["signal"], + ); + + Map toJson() => { + "signal": signal == null ? null : signal, + }; +} + +enum SignalEnum { CLIENT_SIGNAL } + +final signalEnumValues = + EnumValues({"CLIENT_SIGNAL": SignalEnum.CLIENT_SIGNAL}); + +class PurpleNavigationEndpoint { + PurpleNavigationEndpoint({ + this.clickTrackingParams, + this.commandMetadata, + this.signInEndpoint, + }); + + final String clickTrackingParams; + final NavigationEndpointCommandMetadata commandMetadata; + final PurpleSignInEndpoint signInEndpoint; + + factory PurpleNavigationEndpoint.fromRawJson(String str) => + PurpleNavigationEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurpleNavigationEndpoint.fromJson(Map json) => + PurpleNavigationEndpoint( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : NavigationEndpointCommandMetadata.fromJson( + json["commandMetadata"]), + signInEndpoint: json["signInEndpoint"] == null + ? null + : PurpleSignInEndpoint.fromJson(json["signInEndpoint"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "signInEndpoint": + signInEndpoint == null ? null : signInEndpoint.toJson(), + }; +} + +class PurpleSignInEndpoint { + PurpleSignInEndpoint({ + this.nextEndpoint, + this.continueAction, + }); + + final NextEndpointClass nextEndpoint; + final String continueAction; + + factory PurpleSignInEndpoint.fromRawJson(String str) => + PurpleSignInEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PurpleSignInEndpoint.fromJson(Map json) => + PurpleSignInEndpoint( + nextEndpoint: json["nextEndpoint"] == null + ? null + : NextEndpointClass.fromJson(json["nextEndpoint"]), + continueAction: + json["continueAction"] == null ? null : json["continueAction"], + ); + + Map toJson() => { + "nextEndpoint": nextEndpoint == null ? null : nextEndpoint.toJson(), + "continueAction": continueAction == null ? null : continueAction, + }; +} + +class NextEndpointClass { + NextEndpointClass({ + this.clickTrackingParams, + this.commandMetadata, + this.searchEndpoint, + }); + + final String clickTrackingParams; + final NavigationEndpointCommandMetadata commandMetadata; + final NextEndpointSearchEndpoint searchEndpoint; + + factory NextEndpointClass.fromRawJson(String str) => + NextEndpointClass.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NextEndpointClass.fromJson(Map json) => + NextEndpointClass( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : NavigationEndpointCommandMetadata.fromJson( + json["commandMetadata"]), + searchEndpoint: json["searchEndpoint"] == null + ? null + : NextEndpointSearchEndpoint.fromJson(json["searchEndpoint"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "searchEndpoint": + searchEndpoint == null ? null : searchEndpoint.toJson(), + }; +} + +class NextEndpointSearchEndpoint { + NextEndpointSearchEndpoint({ + this.query, + }); + + final Query query; + + factory NextEndpointSearchEndpoint.fromRawJson(String str) => + NextEndpointSearchEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NextEndpointSearchEndpoint.fromJson(Map json) => + NextEndpointSearchEndpoint( + query: json["query"] == null ? null : queryValues.map[json["query"]], + ); + + Map toJson() => { + "query": query == null ? null : queryValues.reverse[query], + }; +} + +enum Query { HEXAH, EMPTY } + +final queryValues = EnumValues({"": Query.EMPTY, "hexah": Query.HEXAH}); + +enum Size { SIZE_DEFAULT } + +final sizeValues = EnumValues({"SIZE_DEFAULT": Size.SIZE_DEFAULT}); + +enum ButtonRendererStyle { + STYLE_DESTRUCTIVE, + STYLE_DEFAULT, + STYLE_BLUE_TEXT, + STYLE_TEXT +} + +final buttonRendererStyleValues = EnumValues({ + "STYLE_BLUE_TEXT": ButtonRendererStyle.STYLE_BLUE_TEXT, + "STYLE_DEFAULT": ButtonRendererStyle.STYLE_DEFAULT, + "STYLE_DESTRUCTIVE": ButtonRendererStyle.STYLE_DESTRUCTIVE, + "STYLE_TEXT": ButtonRendererStyle.STYLE_TEXT +}); + +class PublishedTimeText { + PublishedTimeText({ + this.simpleText, + }); + + final String simpleText; + + factory PublishedTimeText.fromRawJson(String str) => + PublishedTimeText.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory PublishedTimeText.fromJson(Map json) => + PublishedTimeText( + simpleText: json["simpleText"] == null ? null : json["simpleText"], + ); + + Map toJson() => { + "simpleText": simpleText == null ? null : simpleText, + }; +} + +class SubscriptionButton { + SubscriptionButton({ + this.subscribed, + }); + + final bool subscribed; + + factory SubscriptionButton.fromRawJson(String str) => + SubscriptionButton.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SubscriptionButton.fromJson(Map json) => + SubscriptionButton( + subscribed: json["subscribed"] == null ? null : json["subscribed"], + ); + + Map toJson() => { + "subscribed": subscribed == null ? null : subscribed, + }; +} + +class ChannelRendererThumbnail { + ChannelRendererThumbnail({ + this.thumbnails, + }); + + final List thumbnails; + + factory ChannelRendererThumbnail.fromRawJson(String str) => + ChannelRendererThumbnail.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ChannelRendererThumbnail.fromJson(Map json) => + ChannelRendererThumbnail( + thumbnails: json["thumbnails"] == null + ? null + : List.from( + json["thumbnails"].map((x) => ThumbnailElement.fromJson(x))), + ); + + Map toJson() => { + "thumbnails": thumbnails == null + ? null + : List.from(thumbnails.map((x) => x.toJson())), + }; +} + +class ThumbnailElement { + ThumbnailElement({ + this.url, + this.width, + this.height, + }); + + final String url; + final int width; + final int height; + + factory ThumbnailElement.fromRawJson(String str) => + ThumbnailElement.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory ThumbnailElement.fromJson(Map json) => + ThumbnailElement( + url: json["url"] == null ? null : json["url"], + width: json["width"] == null ? null : json["width"], + height: json["height"] == null ? null : json["height"], + ); + + Map toJson() => { + "url": url == null ? null : url, + "width": width == null ? null : width, + "height": height == null ? null : height, + }; +} + +class HorizontalCardListRenderer { + HorizontalCardListRenderer({ + this.cards, + this.trackingParams, + this.header, + this.style, + }); + + final List cards; + final String trackingParams; + final Header header; + final HorizontalCardListRendererStyle style; + + factory HorizontalCardListRenderer.fromRawJson(String str) => + HorizontalCardListRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory HorizontalCardListRenderer.fromJson(Map json) => + HorizontalCardListRenderer( + cards: json["cards"] == null + ? null + : List.from(json["cards"].map((x) => Card.fromJson(x))), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + header: json["header"] == null ? null : Header.fromJson(json["header"]), + style: json["style"] == null + ? null + : HorizontalCardListRendererStyle.fromJson(json["style"]), + ); + + Map toJson() => { + "cards": cards == null + ? null + : List.from(cards.map((x) => x.toJson())), + "trackingParams": trackingParams == null ? null : trackingParams, + "header": header == null ? null : header.toJson(), + "style": style == null ? null : style.toJson(), + }; +} + +class Card { + Card({ + this.searchRefinementCardRenderer, + }); + + final SearchRefinementCardRenderer searchRefinementCardRenderer; + + factory Card.fromRawJson(String str) => Card.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Card.fromJson(Map json) => Card( + searchRefinementCardRenderer: + json["searchRefinementCardRenderer"] == null + ? null + : SearchRefinementCardRenderer.fromJson( + json["searchRefinementCardRenderer"]), + ); + + Map toJson() => { + "searchRefinementCardRenderer": searchRefinementCardRenderer == null + ? null + : searchRefinementCardRenderer.toJson(), + }; +} + +class SearchRefinementCardRenderer { + SearchRefinementCardRenderer({ + this.thumbnail, + this.query, + this.searchEndpoint, + this.trackingParams, + }); + + final ChannelRendererThumbnail thumbnail; + final TitleClass query; + final NavigationEndpointClass searchEndpoint; + final String trackingParams; + + factory SearchRefinementCardRenderer.fromRawJson(String str) => + SearchRefinementCardRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SearchRefinementCardRenderer.fromJson(Map json) => + SearchRefinementCardRenderer( + thumbnail: json["thumbnail"] == null + ? null + : ChannelRendererThumbnail.fromJson(json["thumbnail"]), + query: + json["query"] == null ? null : TitleClass.fromJson(json["query"]), + searchEndpoint: json["searchEndpoint"] == null + ? null + : NavigationEndpointClass.fromJson(json["searchEndpoint"]), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + ); + + Map toJson() => { + "thumbnail": thumbnail == null ? null : thumbnail.toJson(), + "query": query == null ? null : query.toJson(), + "searchEndpoint": + searchEndpoint == null ? null : searchEndpoint.toJson(), + "trackingParams": trackingParams == null ? null : trackingParams, + }; +} + +class NavigationEndpointClass { + NavigationEndpointClass({ + this.clickTrackingParams, + this.commandMetadata, + this.searchEndpoint, + }); + + final String clickTrackingParams; + final NavigationEndpointCommandMetadata commandMetadata; + final NavigationEndpointSearchEndpoint searchEndpoint; + + factory NavigationEndpointClass.fromRawJson(String str) => + NavigationEndpointClass.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NavigationEndpointClass.fromJson(Map json) => + NavigationEndpointClass( + clickTrackingParams: json["clickTrackingParams"] == null + ? null + : json["clickTrackingParams"], + commandMetadata: json["commandMetadata"] == null + ? null + : NavigationEndpointCommandMetadata.fromJson( + json["commandMetadata"]), + searchEndpoint: json["searchEndpoint"] == null + ? null + : NavigationEndpointSearchEndpoint.fromJson(json["searchEndpoint"]), + ); + + Map toJson() => { + "clickTrackingParams": + clickTrackingParams == null ? null : clickTrackingParams, + "commandMetadata": + commandMetadata == null ? null : commandMetadata.toJson(), + "searchEndpoint": + searchEndpoint == null ? null : searchEndpoint.toJson(), + }; +} + +class NavigationEndpointSearchEndpoint { + NavigationEndpointSearchEndpoint({ + this.query, + this.params, + }); + + final String query; + final String params; + + factory NavigationEndpointSearchEndpoint.fromRawJson(String str) => + NavigationEndpointSearchEndpoint.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory NavigationEndpointSearchEndpoint.fromJson( + Map json) => + NavigationEndpointSearchEndpoint( + query: json["query"] == null ? null : json["query"], + params: json["params"] == null ? null : json["params"], + ); + + Map toJson() => { + "query": query == null ? null : query, + "params": params == null ? null : params, + }; +} + +class Header { + Header({ + this.richListHeaderRenderer, + }); + + final RichListHeaderRenderer richListHeaderRenderer; + + factory Header.fromRawJson(String str) => Header.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory Header.fromJson(Map json) => Header( + richListHeaderRenderer: json["richListHeaderRenderer"] == null + ? null + : RichListHeaderRenderer.fromJson(json["richListHeaderRenderer"]), + ); + + Map toJson() => { + "richListHeaderRenderer": richListHeaderRenderer == null + ? null + : richListHeaderRenderer.toJson(), + }; +} + +class RichListHeaderRenderer { + RichListHeaderRenderer({ + this.title, + this.trackingParams, + this.icon, + }); + + final AlertMessage title; + final String trackingParams; + final SecurityIcon icon; + + factory RichListHeaderRenderer.fromRawJson(String str) => + RichListHeaderRenderer.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory RichListHeaderRenderer.fromJson(Map json) => + RichListHeaderRenderer( + title: + json["title"] == null ? null : AlertMessage.fromJson(json["title"]), + trackingParams: + json["trackingParams"] == null ? null : json["trackingParams"], + icon: json["icon"] == null ? null : SecurityIcon.fromJson(json["icon"]), + ); + + Map toJson() => { + "title": title == null ? null : title.toJson(), + "trackingParams": trackingParams == null ? null : trackingParams, + "icon": icon == null ? null : icon.toJson(), + }; +} + +class SecurityIcon { + SecurityIcon({ + this.iconType, + }); + + final String iconType; + + factory SecurityIcon.fromRawJson(String str) => + SecurityIcon.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory SecurityIcon.fromJson(Map json) => SecurityIcon( + iconType: json["iconType"] == null ? null : json["iconType"], + ); + + Map toJson() => { + "iconType": iconType == null ? null : iconType, + }; +} + +class AlertMessage { + AlertMessage({ + this.runs, + }); + + final List runs; + + factory AlertMessage.fromRawJson(String str) => + AlertMessage.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory AlertMessage.fromJson(Map json) => AlertMessage( + runs: json["runs"] == null + ? null + : List.from( + json["runs"].map((x) => AlertMessageRun.fromJson(x))), + ); + + Map toJson() => { + "runs": runs == null + ? null + : List.from(runs.map((x) => x.toJson())), + }; +} + +class AlertMessageRun { + AlertMessageRun({ + this.text, + this.bold, + }); + + final String text; + final bool bold; + + factory AlertMessageRun.fromRawJson(String str) => + AlertMessageRun.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory AlertMessageRun.fromJson(Map json) => + AlertMessageRun( + text: json["text"] == null ? null : json["text"], + bold: json["bold"] == null ? null : json["bold"], + ); + + Map toJson() => { + "text": text == null ? null : text, + "bold": bold == null ? null : bold, + }; +} + +class HorizontalCardListRendererStyle { + HorizontalCardListRendererStyle({ + this.type, + }); + + final String type; + + factory HorizontalCardListRendererStyle.fromRawJson(String str) => + HorizontalCardListRendererStyle.fromJson(json.decode(str)); + + String toRawJson() => json.encode(toJson()); + + factory HorizontalCardListRendererStyle.fromJson(Map json) => + HorizontalCardListRendererStyle( + type: json["type"] == null ? null : json["type"], + ); + + Map toJson() => { + "type": type == null ? null : type, + }; +} + +class RadioRenderer { + RadioRenderer({ + this.playlistId, + this.title, + this.thumbnail, + this.videoCountText, + this.navigationEndpoint, + this.shortBylineText, + this.trackingParams, + this.videos, + this.thumbnailText, + this.longBylineText, + this.thumbnailOverlays, + this.videoCountShortText, + }); + + final String playlistId; + final PublishedTimeText title; + final ChannelRendererThumbnail thumbnail; + final TitleClass videoCountText; + final RadioRendererNavigationEndpoint navigationEndpoint; + final PublishedTimeText shortBylineText; + final String trackingParams; + final List