package org.schabi.newpipe.player.mediaitem; import android.net.Uri; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem.RequestMetadata; import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.Player; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; import java.util.List; import java.util.Optional; import java.util.UUID; import androidx.annotation.NonNull; import androidx.annotation.Nullable; /** * Metadata container and accessor used by player internals. * * This interface ensures consistency of fetching metadata on each stream, * which is encapsulated in a {@link MediaItem} and delivered via ExoPlayer's * {@link Player.Listener} on event triggers to the downstream users. **/ public interface MediaItemTag { List getErrors(); int getServiceId(); String getTitle(); String getUploaderName(); long getDurationSeconds(); String getStreamUrl(); String getThumbnailUrl(); String getUploaderUrl(); StreamType getStreamType(); @NonNull default Optional getMaybeStreamInfo() { return Optional.empty(); } @NonNull default Optional getMaybeQuality() { return Optional.empty(); } Optional getMaybeExtras(@NonNull Class type); MediaItemTag withExtras(@NonNull T extra); @NonNull static Optional from(@Nullable final MediaItem mediaItem) { if (mediaItem == null || mediaItem.localConfiguration == null || !(mediaItem.localConfiguration.tag instanceof MediaItemTag)) { return Optional.empty(); } return Optional.of((MediaItemTag) mediaItem.localConfiguration.tag); } @NonNull default String makeMediaId() { return UUID.randomUUID().toString() + "[" + getTitle() + "]"; } @NonNull default MediaItem asMediaItem() { final MediaMetadata mediaMetadata = new MediaMetadata.Builder() .setArtworkUri(Uri.parse(getThumbnailUrl())) .setArtist(getUploaderName()) .setDescription(getTitle()) .setDisplayTitle(getTitle()) .setTitle(getTitle()) .build(); final RequestMetadata requestMetaData = new RequestMetadata.Builder() .setMediaUri(Uri.parse(getStreamUrl())) .build(); return MediaItem.fromUri(getStreamUrl()) .buildUpon() .setMediaId(makeMediaId()) .setMediaMetadata(mediaMetadata) .setRequestMetadata(requestMetaData) .setTag(this) .build(); } final class Quality { @NonNull private final List sortedVideoStreams; private final int selectedVideoStreamIndex; private Quality(@NonNull final List sortedVideoStreams, final int selectedVideoStreamIndex) { this.sortedVideoStreams = sortedVideoStreams; this.selectedVideoStreamIndex = selectedVideoStreamIndex; } static Quality of(@NonNull final List sortedVideoStreams, final int selectedVideoStreamIndex) { return new Quality(sortedVideoStreams, selectedVideoStreamIndex); } @NonNull public List getSortedVideoStreams() { return sortedVideoStreams; } public int getSelectedVideoStreamIndex() { return selectedVideoStreamIndex; } @Nullable public VideoStream getSelectedVideoStream() { return selectedVideoStreamIndex < 0 || selectedVideoStreamIndex >= sortedVideoStreams.size() ? null : sortedVideoStreams.get(selectedVideoStreamIndex); } } }