chromium/google_apis/youtube_music/youtube_music_api_response_types.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "google_apis/youtube_music/youtube_music_api_response_types.h"

#include <string>

#include "base/json/json_value_converter.h"
#include "base/strings/stringprintf.h"

namespace google_apis::youtube_music {
namespace {

using ::base::JSONValueConverter;

constexpr char kApiResponseNameKey[] = "name";
constexpr char kApiResponseTitleKey[] = "title";
constexpr char kApiResponseMusicRecommendationsKey[] = "musicRecommendations";
constexpr char kApiResponseMusicSectionKey[] = "musicSection";
constexpr char kApiResponseWidthKey[] = "widthPixels";
constexpr char kApiResponseHeightKey[] = "heightPixels";
constexpr char kApiResponseUriKey[] = "uri";
constexpr char kApiResponsePlaybackReportingTokenKey[] =
    "playbackReportingToken";
constexpr char kApiResponseDescriptionKey[] = "description";
constexpr char kApiResponseItemCountKey[] = "itemCount";
constexpr char kApiResponseImagesKey[] = "images";
constexpr char kApiResponseArtistKey[] = "artist";
constexpr char kApiResponseArtistReferencesKey[] = "artistReferences";
constexpr char kApiResponseOwnerKey[] = "owner";
constexpr char kApiResponsePlaylistKey[] = "playlist";
constexpr char kApiResponseContextKey[] = "context";
constexpr char kApiResponseSizeKey[] = "size";
constexpr char kApiResponseQueueKey[] = "queue";
constexpr char kApiResponseDurationKey[] = "duration";
constexpr char kApiResponseExplicitTypeKey[] = "explicitType";
constexpr char kApiResponseTrackKey[] = "track";
constexpr char kApiResponseStreamsKey[] = "streams";
constexpr char kApiResponseItemKey[] = "item";
constexpr char kApiResponseManifestKey[] = "manifest";

bool ConvertToGurl(std::string_view input, GURL* output) {
  *output = GURL(input);
  return true;
}

}  // namespace

Image::Image() = default;
Image::~Image() = default;

// static
void Image::RegisterJSONConverter(JSONValueConverter<Image>* converter) {
  converter->RegisterIntField(kApiResponseWidthKey, &Image::width_);
  converter->RegisterIntField(kApiResponseHeightKey, &Image::height_);
  converter->RegisterCustomField<GURL>(kApiResponseUriKey, &Image::url_,
                                       &ConvertToGurl);
}

std::string Image::ToString() const {
  return base::StringPrintf("Image(width=%d, height=%d, url=\"%s\")", width_,
                            height_, url_.spec().c_str());
}

Owner::Owner() = default;
Owner::~Owner() = default;

// static
void Owner::RegisterJSONConverter(JSONValueConverter<Owner>* converter) {
  converter->RegisterStringField(kApiResponseTitleKey, &Owner::title_);
}

std::string Owner::ToString() const {
  return base::StringPrintf("Owner(title=\"%s\"", title_.c_str());
}

Playlist::Playlist() = default;
Playlist::~Playlist() = default;

// static
void Playlist::RegisterJSONConverter(JSONValueConverter<Playlist>* converter) {
  converter->RegisterStringField(kApiResponseNameKey, &Playlist::name_);
  converter->RegisterStringField(kApiResponseTitleKey, &Playlist::title_);
  converter->RegisterStringField(kApiResponseDescriptionKey,
                                 &Playlist::description_);
  converter->RegisterIntField(kApiResponseItemCountKey, &Playlist::item_count_);
  converter->RegisterRepeatedMessage<Image>(kApiResponseImagesKey,
                                            &Playlist::images_);
  converter->RegisterNestedField(kApiResponseOwnerKey, &Playlist::owner_);
}

// static
std::unique_ptr<Playlist> Playlist::CreateFrom(const base::Value& value) {
  auto playlist = std::make_unique<Playlist>();
  JSONValueConverter<Playlist> converter;
  if (!converter.Convert(value, playlist.get())) {
    DVLOG(1) << "Unable to construct `Playlist` from parsed json.";
    return nullptr;
  }
  return playlist;
}

std::string Playlist::ToString() const {
  std::string s;
  for (size_t i = 0; i < images_.size(); i++) {
    s += (i ? ", " : "") + images_[i]->ToString();
  }
  return base::StringPrintf(
      "Playlist(name=\"%s\", title=\"%s\", description=\"%s\", item_count=%d, "
      "images=[%s], owner=%s)",
      name_.c_str(), title_.c_str(), description_.c_str(), item_count_,
      s.c_str(), owner_.ToString().c_str());
}

MusicRecommendation::MusicRecommendation() = default;
MusicRecommendation::~MusicRecommendation() = default;

// static
void MusicRecommendation::RegisterJSONConverter(
    JSONValueConverter<MusicRecommendation>* converter) {
  converter->RegisterNestedField(kApiResponsePlaylistKey,
                                 &MusicRecommendation::playlist_);
}

std::string MusicRecommendation::ToString() const {
  return base::StringPrintf("MusicRecommendation(playlist=%s)",
                            playlist_.ToString().c_str());
}

MusicSection::MusicSection() = default;
MusicSection::~MusicSection() = default;

// static
void MusicSection::RegisterJSONConverter(
    JSONValueConverter<MusicSection>* converter) {
  converter->RegisterStringField(kApiResponseNameKey, &MusicSection::name_);
  converter->RegisterStringField(kApiResponseTitleKey, &MusicSection::title_);
  converter->RegisterRepeatedMessage<MusicRecommendation>(
      kApiResponseMusicRecommendationsKey,
      &MusicSection::music_recommendations_);
}

// static
std::unique_ptr<MusicSection> MusicSection::CreateFrom(
    const base::Value& value) {
  auto music_section = std::make_unique<MusicSection>();
  JSONValueConverter<MusicSection> converter;
  if (!converter.Convert(value, music_section.get())) {
    DVLOG(1) << "Unable to construct `MusicSection` from parsed json.";
    return nullptr;
  }
  return music_section;
}

std::string MusicSection::ToString() const {
  std::string s;
  for (size_t i = 0; i < music_recommendations_.size(); i++) {
    s += (i ? ", " : "") + music_recommendations_[i]->ToString();
  }
  return base::StringPrintf(
      "MusicSection(name=\"%s\", title=\"%s\", "
      "music_recommendations=[%s])",
      name_.c_str(), title_.c_str(), s.c_str());
}

TopLevelMusicRecommendation::TopLevelMusicRecommendation() = default;
TopLevelMusicRecommendation::~TopLevelMusicRecommendation() = default;

// static
void TopLevelMusicRecommendation::RegisterJSONConverter(
    JSONValueConverter<TopLevelMusicRecommendation>* converter) {
  converter->RegisterNestedField(kApiResponseMusicSectionKey,
                                 &TopLevelMusicRecommendation::music_section_);
}

// static
std::unique_ptr<TopLevelMusicRecommendation>
TopLevelMusicRecommendation::CreateFrom(const base::Value& value) {
  auto top_level_music_recommendation =
      std::make_unique<TopLevelMusicRecommendation>();
  JSONValueConverter<TopLevelMusicRecommendation> converter;
  if (!converter.Convert(value, top_level_music_recommendation.get())) {
    DVLOG(1) << "Unable to construct `TopLevelMusicRecommendation` from parsed "
                "json.";
    return nullptr;
  }
  return top_level_music_recommendation;
}

std::string TopLevelMusicRecommendation::ToString() const {
  return base::StringPrintf("TopLevelMusicRecommendation(music_section=%s)",
                            music_section_.ToString().c_str());
}

TopLevelMusicRecommendations::TopLevelMusicRecommendations() = default;
TopLevelMusicRecommendations::~TopLevelMusicRecommendations() = default;

// static
void TopLevelMusicRecommendations::RegisterJSONConverter(
    JSONValueConverter<TopLevelMusicRecommendations>* converter) {
  converter->RegisterRepeatedMessage<TopLevelMusicRecommendation>(
      kApiResponseMusicRecommendationsKey,
      &TopLevelMusicRecommendations::top_level_music_recommendations_);
}

// static
std::unique_ptr<TopLevelMusicRecommendations>
TopLevelMusicRecommendations::CreateFrom(const base::Value& value) {
  auto top_level_music_recommendations =
      std::make_unique<TopLevelMusicRecommendations>();
  JSONValueConverter<TopLevelMusicRecommendations> converter;
  if (!converter.Convert(value, top_level_music_recommendations.get())) {
    DVLOG(1) << "Unable to construct `TopLevelMusicRecommendations` from "
                "parsed json.";
    return nullptr;
  }
  return top_level_music_recommendations;
}

std::string TopLevelMusicRecommendations::ToString() const {
  std::string s;
  for (size_t i = 0; i < top_level_music_recommendations_.size(); i++) {
    s += (i ? ", " : "") + top_level_music_recommendations_[i]->ToString();
  }
  return base::StringPrintf(
      "TopLevelMusicRecommendations(top_level_music_recommendations=[%s])",
      s.c_str());
}

ArtistReference::ArtistReference() = default;
ArtistReference::~ArtistReference() = default;

// static
void ArtistReference::RegisterJSONConverter(
    JSONValueConverter<ArtistReference>* converter) {
  converter->RegisterStringField(kApiResponseArtistKey,
                                 &ArtistReference::artist_);
  converter->RegisterStringField(kApiResponseTitleKey,
                                 &ArtistReference::title_);
}

// static
std::unique_ptr<ArtistReference> ArtistReference::CreateFrom(
    const base::Value& value) {
  auto artist_reference = std::make_unique<ArtistReference>();
  JSONValueConverter<ArtistReference> converter;
  if (!converter.Convert(value, artist_reference.get())) {
    DVLOG(1) << "Unable to construct `ArtistReference` from parsed json.";
    return nullptr;
  }
  return artist_reference;
}

std::string ArtistReference::ToString() const {
  return base::StringPrintf("ArtistReference(artist=\"%s\", title=\"%s\"",
                            artist_.c_str(), title_.c_str());
}

Track::Track() = default;
Track::~Track() = default;

// static
void Track::RegisterJSONConverter(JSONValueConverter<Track>* converter) {
  converter->RegisterStringField(kApiResponseNameKey, &Track::name_);
  converter->RegisterStringField(kApiResponseTitleKey, &Track::title_);
  converter->RegisterStringField(kApiResponseDurationKey, &Track::duration_);
  converter->RegisterStringField(kApiResponseExplicitTypeKey,
                                 &Track::explicit_type_);
  converter->RegisterRepeatedMessage<Image>(kApiResponseImagesKey,
                                            &Track::images_);
  converter->RegisterRepeatedMessage<ArtistReference>(
      kApiResponseArtistReferencesKey, &Track::artist_references_);
}

// static
std::unique_ptr<Track> Track::CreateFrom(const base::Value& value) {
  auto track = std::make_unique<Track>();
  JSONValueConverter<Track> converter;
  if (!converter.Convert(value, track.get())) {
    DVLOG(1) << "Unable to construct `Track` from parsed json.";
    return nullptr;
  }
  return track;
}

std::string Track::ToString() const {
  std::string s;
  for (size_t i = 0; i < images_.size(); i++) {
    s += (i ? ", " : "") + images_[i]->ToString();
  }
  return base::StringPrintf(
      "Track(name=\"%s\", title=\"%s\", duration=\"%s\", explicit_type_=%s, "
      "images=[%s])",
      name_.c_str(), title_.c_str(), duration_.c_str(), explicit_type_.c_str(),
      s.c_str());
}

QueueItem::QueueItem() = default;
QueueItem::~QueueItem() = default;

// static
void QueueItem::RegisterJSONConverter(
    JSONValueConverter<QueueItem>* converter) {
  converter->RegisterNestedField(kApiResponseTrackKey, &QueueItem::track_);
}

// static
std::unique_ptr<QueueItem> QueueItem::CreateFrom(const base::Value& value) {
  auto queue_item = std::make_unique<QueueItem>();
  JSONValueConverter<QueueItem> converter;
  if (!converter.Convert(value, queue_item.get())) {
    DVLOG(1) << "Unable to construct `QueueItem` from parsed json.";
    return nullptr;
  }
  return queue_item;
}

std::string QueueItem::ToString() const {
  return base::StringPrintf("QueueItem(track=%s)", track_.ToString().c_str());
}

Stream::Stream() = default;
Stream::~Stream() = default;

// static
void Stream::RegisterJSONConverter(JSONValueConverter<Stream>* converter) {
  converter->RegisterCustomField<GURL>(kApiResponseUriKey, &Stream::url_,
                                       &ConvertToGurl);
  converter->RegisterStringField(kApiResponsePlaybackReportingTokenKey,
                                 &Stream::playback_reporting_token_);
}

// static
std::unique_ptr<Stream> Stream::CreateFrom(const base::Value& value) {
  auto stream = std::make_unique<Stream>();
  JSONValueConverter<Stream> converter;
  if (!converter.Convert(value, stream.get())) {
    DVLOG(1) << "Unable to construct `Stream` from parsed json.";
    return nullptr;
  }
  return stream;
}

std::string Stream::ToString() const {
  return base::StringPrintf(
      "Stream(url=\"%s\", playback_reporting_token=\"%s\")",
      url_.spec().c_str(), playback_reporting_token_.c_str());
}

PlaybackManifest::PlaybackManifest() = default;
PlaybackManifest::~PlaybackManifest() = default;

// static
void PlaybackManifest::RegisterJSONConverter(
    JSONValueConverter<PlaybackManifest>* converter) {
  converter->RegisterRepeatedMessage<Stream>(kApiResponseStreamsKey,
                                             &PlaybackManifest::streams_);
}

// static
std::unique_ptr<PlaybackManifest> PlaybackManifest::CreateFrom(
    const base::Value& value) {
  auto playback_manifest = std::make_unique<PlaybackManifest>();
  JSONValueConverter<PlaybackManifest> converter;
  if (!converter.Convert(value, playback_manifest.get())) {
    DVLOG(1) << "Unable to construct `PlaybackManifest` from parsed json.";
    return nullptr;
  }
  return playback_manifest;
}

std::string PlaybackManifest::ToString() const {
  std::string s;
  for (size_t i = 0; i < streams_.size(); i++) {
    s += (i ? ", " : "") + streams_[i]->ToString();
  }
  return base::StringPrintf("PlaybackManifest(streams=[%s])", s.c_str());
}

PlaybackContext::PlaybackContext() = default;
PlaybackContext::~PlaybackContext() = default;

// static
void PlaybackContext::RegisterJSONConverter(
    JSONValueConverter<PlaybackContext>* converter) {
  converter->RegisterNestedField(kApiResponseItemKey,
                                 &PlaybackContext::queue_item_);
  converter->RegisterNestedField(kApiResponseManifestKey,
                                 &PlaybackContext::playback_manifest_);
}

// static
std::unique_ptr<PlaybackContext> PlaybackContext::CreateFrom(
    const base::Value& value) {
  auto playback_context = std::make_unique<PlaybackContext>();
  JSONValueConverter<PlaybackContext> converter;
  if (!converter.Convert(value, playback_context.get())) {
    DVLOG(1) << "Unable to construct `PlaybackManifest` from parsed json.";
    return nullptr;
  }
  return playback_context;
}

std::string PlaybackContext::ToString() const {
  return base::StringPrintf(
      "PlaybackContext(queue_item=%s, playback_manifest=%s)",
      queue_item_.ToString().c_str(), playback_manifest_.ToString().c_str());
}

Queue::Queue() = default;
Queue::~Queue() = default;

// static
void Queue::RegisterJSONConverter(JSONValueConverter<Queue>* converter) {
  converter->RegisterStringField(kApiResponseNameKey, &Queue::name_);
  converter->RegisterIntField(kApiResponseSizeKey, &Queue::size_);
  converter->RegisterNestedField(kApiResponseContextKey,
                                 &Queue::playback_context_);
}

// static
std::unique_ptr<Queue> Queue::CreateFrom(const base::Value& value) {
  auto queue = std::make_unique<Queue>();
  JSONValueConverter<Queue> converter;
  if (!converter.Convert(value, queue.get())) {
    DVLOG(1) << "Unable to construct `Queue` from parsed json.";
    return nullptr;
  }
  return queue;
}

std::string Queue::ToString() const {
  return base::StringPrintf("Queue(name=\"%s\", size=%d, playback_context=%s)",
                            name_.c_str(), size_,
                            playback_context_.ToString().c_str());
}

QueueContainer::QueueContainer() = default;
QueueContainer::~QueueContainer() = default;

// static
void QueueContainer::RegisterJSONConverter(
    JSONValueConverter<QueueContainer>* converter) {
  converter->RegisterNestedField(kApiResponseQueueKey, &QueueContainer::queue_);
}

// static
std::unique_ptr<QueueContainer> QueueContainer::CreateFrom(
    const base::Value& value) {
  auto queue_container = std::make_unique<QueueContainer>();
  JSONValueConverter<QueueContainer> converter;
  if (!converter.Convert(value, queue_container.get())) {
    DVLOG(1) << "Unable to construct `QueueContainer` from parsed json.";
    return nullptr;
  }
  return queue_container;
}

std::string QueueContainer::ToString() const {
  return base::StringPrintf("QueueContainer(queue=%s)",
                            queue_.ToString().c_str());
}

ReportPlaybackResult::ReportPlaybackResult() = default;
ReportPlaybackResult::~ReportPlaybackResult() = default;

// static
void ReportPlaybackResult::RegisterJSONConverter(
    JSONValueConverter<ReportPlaybackResult>* converter) {
  converter->RegisterStringField(
      kApiResponsePlaybackReportingTokenKey,
      &ReportPlaybackResult::playback_reporting_token_);
}

// static
std::unique_ptr<ReportPlaybackResult> ReportPlaybackResult::CreateFrom(
    const base::Value& value) {
  auto report_playback_result = std::make_unique<ReportPlaybackResult>();
  JSONValueConverter<ReportPlaybackResult> converter;
  if (!converter.Convert(value, report_playback_result.get())) {
    DVLOG(1) << "Unable to construct `ReportPlaybackResult` from parsed json.";
    return nullptr;
  }
  return report_playback_result;
}

std::string ReportPlaybackResult::ToString() const {
  return base::StringPrintf("ReportPlaybackResult(playback_reporting_token=%s)",
                            playback_reporting_token_.c_str());
}

}  // namespace google_apis::youtube_music