chromium/ash/system/focus_mode/sounds/youtube_music/youtube_music_util.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 "ash/system/focus_mode/sounds/youtube_music/youtube_music_util.h"

#include <algorithm>

#include "ash/system/focus_mode/sounds/youtube_music/youtube_music_types.h"
#include "google_apis/youtube_music/youtube_music_api_response_types.h"

namespace ash::youtube_music {

Image GetImageFromApiImage(const google_apis::youtube_music::Image* api_iamge) {
  Image image;
  if (api_iamge) {
    image.width = api_iamge->width();
    image.height = api_iamge->height();
    image.url = api_iamge->url();
  }
  return image;
}

std::vector<Image> GetImagesFromApiImages(
    const std::vector<std::unique_ptr<google_apis::youtube_music::Image>>&
        api_images) {
  std::vector<Image> images;
  for (const auto& api_image : api_images) {
    images.emplace_back(GetImageFromApiImage(api_image.get()));
  }
  return images;
}

std::optional<Playlist> GetPlaylistFromApiPlaylist(
    const google_apis::youtube_music::Playlist* playlist) {
  if (!playlist) {
    return std::nullopt;
  }

  return Playlist(playlist->name(), playlist->title(),
                  playlist->owner().title(),
                  FindBestImage(GetImagesFromApiImages(playlist->images())));
}

std::optional<std::vector<Playlist>>
GetPlaylistsFromApiTopLevelMusicRecommendations(
    const google_apis::youtube_music::TopLevelMusicRecommendations*
        top_level_music_recommendations) {
  if (!top_level_music_recommendations) {
    return std::nullopt;
  }

  std::vector<Playlist> playlists;
  for (auto& top_level_recommendation :
       top_level_music_recommendations->top_level_music_recommendations()) {
    for (auto& music_recommendation :
         top_level_recommendation->music_section().music_recommendations()) {
      auto& playlist = music_recommendation->playlist();
      playlists.emplace_back(
          playlist.name(), playlist.title(), playlist.owner().title(),
          FindBestImage(GetImagesFromApiImages(playlist.images())));
    }
  }
  return playlists;
}

std::optional<PlaybackContext> GetPlaybackContextFromApiQueue(
    const google_apis::youtube_music::Queue* queue) {
  if (!queue) {
    return std::nullopt;
  }

  const auto& playback_context = queue->playback_context();
  const auto& track = playback_context.queue_item().track();
  // TODO(yongshun): Consider to add retry when there is no stream in the
  // response.
  GURL stream_url = GURL();
  std::string playback_reporting_token;
  if (auto& streams = playback_context.playback_manifest().streams();
      !streams.empty()) {
    const auto* stream = streams.begin()->get();
    stream_url = stream->url();
    playback_reporting_token = stream->playback_reporting_token();
  }

  std::string track_artists;
  for (size_t i = 0; i < track.artist_references().size(); i++) {
    track_artists += (i ? ", " : "") + track.artist_references()[i]->title();
  }

  return PlaybackContext(track.name(), track.title(), track_artists,
                         track.explicit_type(),
                         FindBestImage(GetImagesFromApiImages(track.images())),
                         stream_url, playback_reporting_token, queue->name());
}

Image FindBestImage(const std::vector<Image>& images) {
  if (images.empty()) {
    return Image();
  }

  auto smaller_in_size = [](const Image& img1, const Image& img2) {
    return img1.width * img1.height < img2.width * img2.height;
  };
  auto qualified = [](const Image& img) {
    return img.width >= kImageMinimalWidth && img.height >= kImageMinimalHeight;
  };

  size_t smallest_qualified_index = images.size();
  for (size_t i = 0; i < images.size(); i++) {
    if (qualified(images[i]) &&
        (smallest_qualified_index == images.size() ||
         smaller_in_size(images[i], images[smallest_qualified_index]))) {
      smallest_qualified_index = i;
    }
  }

  return smallest_qualified_index < images.size()
             ? images[smallest_qualified_index]
             : *std::max_element(images.begin(), images.end(), smaller_in_size);
}

}  // namespace ash::youtube_music