content: package allen.town.podcast.playback.cast;
  
  import android.net.Uri;
  import android.text.TextUtils;
  
  import androidx.annotation.Nullable;
  
  import com.google.android.gms.cast.MediaInfo;
  import com.google.android.gms.cast.MediaMetadata;
  import com.google.android.gms.common.images.WebImage;
  import allen.town.podcast.model.feed.Feed;
  import allen.town.podcast.model.feed.FeedItem;
  import allen.town.podcast.model.feed.FeedMedia;
  import allen.town.podcast.model.playback.RemoteMedia;
  import java.util.Calendar;
  
  public class MediaInfoCreator {
      public static MediaInfo from(RemoteMedia media) {
          MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_GENERIC);
  
          metadata.putString(MediaMetadata.KEY_TITLE, media.getEpisodeTitle());
          metadata.putString(MediaMetadata.KEY_SUBTITLE, media.getFeedTitle());
          if (!TextUtils.isEmpty(media.getImageLocation())) {
              metadata.addImage(new WebImage(Uri.parse(media.getImageLocation())));
          }
          Calendar calendar = Calendar.getInstance();
          calendar.setTime(media.getPubDate());
          metadata.putDate(MediaMetadata.KEY_RELEASE_DATE, calendar);
          if (!TextUtils.isEmpty(media.getFeedAuthor())) {
              metadata.putString(MediaMetadata.KEY_ARTIST, media.getFeedAuthor());
          }
          if (!TextUtils.isEmpty(media.getFeedUrl())) {
              metadata.putString(CastUtils.KEY_FEED_URL, media.getFeedUrl());
          }
          if (!TextUtils.isEmpty(media.getFeedLink())) {
              metadata.putString(CastUtils.KEY_FEED_WEBSITE, media.getFeedLink());
          }
          if (!TextUtils.isEmpty(media.getEpisodeIdentifier())) {
              metadata.putString(CastUtils.KEY_EPISODE_IDENTIFIER, media.getEpisodeIdentifier());
          } else {
              metadata.putString(CastUtils.KEY_EPISODE_IDENTIFIER, media.getDownloadUrl());
          }
          if (!TextUtils.isEmpty(media.getEpisodeLink())) {
              metadata.putString(CastUtils.KEY_EPISODE_LINK, media.getEpisodeLink());
          }
          String notes = media.getNotes();
          if (notes != null) {
              metadata.putString(CastUtils.KEY_EPISODE_NOTES, notes);
          }
          // Default id value
          metadata.putInt(CastUtils.KEY_MEDIA_ID, 0);
          metadata.putInt(CastUtils.KEY_FORMAT_VERSION, CastUtils.FORMAT_VERSION_VALUE);
          metadata.putString(CastUtils.KEY_STREAM_URL, media.getStreamUrl());
  
          MediaInfo.Builder builder = new MediaInfo.Builder(media.getDownloadUrl())
                  .setContentType(media.getMimeType())
                  .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
                  .setMetadata(metadata);
          if (media.getDuration() > 0) {
              builder.setStreamDuration(media.getDuration());
          }
          return builder.build();
      }
  
      /**
       * Converts {@link FeedMedia} objects into a format suitable for sending to a Cast Device.
       * Before using this method, one should make sure isCastable(Playable) returns
       * {@code true}. This method should not run on the main thread.
       *
       * @param media The {@link FeedMedia} object to be converted.
       * @return {@link MediaInfo} object in a format proper for casting.
       */
      public static MediaInfo from(FeedMedia media) {
          if (media == null) {
              return null;
          }
          MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_GENERIC);
          if (media.getItem() == null) {
              throw new IllegalStateException("item is null");
          }
          FeedItem feedItem = media.getItem();
          if (feedItem != null) {
              metadata.putString(MediaMetadata.KEY_TITLE, media.getEpisodeTitle());
              String subtitle = media.getFeedTitle();
              if (subtitle != null) {
                  metadata.putString(MediaMetadata.KEY_SUBTITLE, subtitle);
              }
  
              final @Nullable Feed feed = feedItem.getFeed();
              // Manual because cast does not support embedded images
              String url = (feedItem.getImageUrl() == null && feed != null) ? feed.getImageUrl() : feedItem.getImageUrl();
              if (!TextUtils.isEmpty(url)) {
                  metadata.addImage(new WebImage(Uri.parse(url)));
              }
              Calendar calendar = Calendar.getInstance();
              calendar.setTime(media.getItem().getPubDate());
              metadata.putDate(MediaMetadata.KEY_RELEASE_DATE, calendar);
              if (feed != null) {
                  if (!TextUtils.isEmpty(feed.getAuthor())) {
                      metadata.putString(MediaMetadata.KEY_ARTIST, feed.getAuthor());
                  }
                  if (!TextUtils.isEmpty(feed.getDownload_url())) {
                      metadata.putString(CastUtils.KEY_FEED_URL, feed.getDownload_url());
                  }
                  if (!TextUtils.isEmpty(feed.getLink())) {
                      metadata.putString(CastUtils.KEY_FEED_WEBSITE, feed.getLink());
                  }
              }
              if (!TextUtils.isEmpty(feedItem.getItemIdentifier())) {
                  metadata.putString(CastUtils.KEY_EPISODE_IDENTIFIER, feedItem.getItemIdentifier());
              } else {
                  metadata.putString(CastUtils.KEY_EPISODE_IDENTIFIER, media.getStreamUrl());
              }
              if (!TextUtils.isEmpty(feedItem.getLink())) {
                  metadata.putString(CastUtils.KEY_EPISODE_LINK, feedItem.getLink());
              }
          }
          // This field only identifies the id on the device that has the original version.
          // Idea is to perhaps, on a first approach, check if the version on the local DB with the
          // same id matches the remote object, and if not then search for episode and feed identifiers.
          // This at least should make media recognition for a single device much quicker.
          metadata.putInt(CastUtils.KEY_MEDIA_ID, ((Long) media.getIdentifier()).intValue());
          // A way to identify different casting media formats in case we change it in the future and
          // senders with different versions share a casting device.
          metadata.putInt(CastUtils.KEY_FORMAT_VERSION, CastUtils.FORMAT_VERSION_VALUE);
          metadata.putString(CastUtils.KEY_STREAM_URL, media.getStreamUrl());
  
          MediaInfo.Builder builder = new MediaInfo.Builder(media.getStreamUrl())
                  .setContentType(media.getMime_type())
                  .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
                  .setMetadata(metadata);
          if (media.getDuration() > 0) {
              builder.setStreamDuration(media.getDuration());
          }
          return builder.build();
      }
  }
  