mirror of
https://github.com/antebudimir/tempus.git
synced 2026-04-15 08:17:26 +00:00
feat: radio logos support for AndroidAuto (#435)
* feat: radio logos support for AndroidAuto * resolve a merge conflict. * fix auto lint * fix auto lint * fix auto break line * fix auto break line * fix auto break line * fix: add alternate serialized name for InternetRadioStation homePageUrl to support both `homePageUrl` and `homepageUrl` JSON keys. * improve internet radio station cover art handling by prioritizing home page URLs * fix: remove unnecessary blank line and adjust formatting in MusicUtil * refactor: improve formatting and clean up whitespace in MappingUtil and MusicUtil
This commit is contained in:
parent
a49f2b97a2
commit
b403d69982
7 changed files with 59 additions and 7 deletions
|
|
@ -195,11 +195,20 @@ class SessionMediaItem() {
|
|||
title = internetRadioStation.name
|
||||
streamUrl = internetRadioStation.streamUrl
|
||||
type = Constants.MEDIA_TYPE_RADIO
|
||||
|
||||
val homePageUrl = internetRadioStation.homePageUrl
|
||||
if (homePageUrl != null && homePageUrl.isNotEmpty() && MusicUtil.isImageUrl(homePageUrl)) {
|
||||
val encodedUrl = android.util.Base64.encodeToString(
|
||||
homePageUrl.toByteArray(java.nio.charset.StandardCharsets.UTF_8),
|
||||
android.util.Base64.URL_SAFE or android.util.Base64.NO_WRAP
|
||||
)
|
||||
coverArtId = "ir_$encodedUrl"
|
||||
}
|
||||
}
|
||||
|
||||
fun getMediaItem(): MediaItem {
|
||||
val uri: Uri = getStreamUri()
|
||||
val artworkUri = AlbumArtContentProvider.contentUri(coverArtId)
|
||||
val artworkUri = if (coverArtId != null) AlbumArtContentProvider.contentUri(coverArtId!!) else null
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putString("id", id)
|
||||
|
|
@ -229,7 +238,7 @@ class SessionMediaItem() {
|
|||
bundle.putLong("starred", starred?.time ?: 0)
|
||||
bundle.putString("albumId", albumId)
|
||||
bundle.putString("artistId", artistId)
|
||||
bundle.putString("type", Constants.MEDIA_TYPE_MUSIC)
|
||||
bundle.putString("type", type)
|
||||
bundle.putLong("bookmarkPosition", bookmarkPosition ?: 0)
|
||||
bundle.putInt("originalWidth", originalWidth ?: 0)
|
||||
bundle.putInt("originalHeight", originalHeight ?: 0)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import android.content.UriMatcher;
|
|||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -53,7 +54,15 @@ public class AlbumArtContentProvider extends ContentProvider {
|
|||
public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {
|
||||
Context context = getContext();
|
||||
String albumId = uri.getLastPathSegment();
|
||||
Uri artworkUri = Uri.parse(CustomGlideRequest.createUrl(albumId, Preferences.getImageSize()));
|
||||
Uri artworkUri;
|
||||
|
||||
if (albumId != null && albumId.startsWith("ir_")) {
|
||||
String encodedUrl = albumId.substring("ir_".length());
|
||||
String decodedUrl = new String(Base64.decode(encodedUrl, Base64.URL_SAFE | Base64.NO_WRAP));
|
||||
artworkUri = Uri.parse(decodedUrl);
|
||||
} else {
|
||||
artworkUri = Uri.parse(CustomGlideRequest.createUrl(albumId, Preferences.getImageSize()));
|
||||
}
|
||||
|
||||
try {
|
||||
// use pipe to communicate between background thread and caller of openFile()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.cappielloantonio.tempo.subsonic.models
|
|||
import android.os.Parcelable
|
||||
import androidx.annotation.Keep
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
@Keep
|
||||
@Parcelize
|
||||
|
|
@ -10,5 +11,6 @@ class InternetRadioStation(
|
|||
var id: String? = null,
|
||||
var name: String? = null,
|
||||
var streamUrl: String? = null,
|
||||
@SerializedName("homePageUrl", alternate = ["homepageUrl"])
|
||||
var homePageUrl: String? = null,
|
||||
) : Parcelable
|
||||
|
|
@ -42,8 +42,13 @@ public class InternetRadioStationAdapter extends RecyclerView.Adapter<InternetRa
|
|||
holder.item.internetRadioStationTitleTextView.setText(internetRadioStation.getName());
|
||||
holder.item.internetRadioStationSubtitleTextView.setText(internetRadioStation.getStreamUrl());
|
||||
|
||||
String imageId = internetRadioStation.getHomePageUrl();
|
||||
if (imageId == null || imageId.isEmpty()) {
|
||||
imageId = internetRadioStation.getStreamUrl();
|
||||
}
|
||||
|
||||
CustomGlideRequest.Builder
|
||||
.from(holder.itemView.getContext(), internetRadioStation.getStreamUrl(), CustomGlideRequest.ResourceType.Radio)
|
||||
.from(holder.itemView.getContext(), imageId, CustomGlideRequest.ResourceType.Radio)
|
||||
.build()
|
||||
.into(holder.item.internetRadioStationCoverImageView);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import android.content.ContentResolver;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.util.Base64;
|
||||
|
||||
import androidx.annotation.OptIn;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
|
|
@ -25,6 +26,7 @@ import com.google.common.collect.ImmutableList;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@OptIn(markerClass = UnstableApi.class)
|
||||
public class MappingUtil {
|
||||
|
|
@ -207,6 +209,16 @@ public class MappingUtil {
|
|||
|
||||
public static MediaItem mapInternetRadioStation(InternetRadioStation internetRadioStation) {
|
||||
Uri uri = Uri.parse(internetRadioStation.getStreamUrl());
|
||||
Uri artworkUri = null;
|
||||
String homePageUrl = internetRadioStation.getHomePageUrl();
|
||||
String coverArtId = null;
|
||||
|
||||
if (homePageUrl != null && !homePageUrl.isEmpty() && MusicUtil.isImageUrl(homePageUrl)) {
|
||||
String encodedUrl = Base64.encodeToString(homePageUrl.getBytes(StandardCharsets.UTF_8),
|
||||
Base64.URL_SAFE | Base64.NO_WRAP);
|
||||
coverArtId = "ir_" + encodedUrl;
|
||||
artworkUri = AlbumArtContentProvider.contentUri(coverArtId);
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("id", internetRadioStation.getId());
|
||||
|
|
@ -214,13 +226,17 @@ public class MappingUtil {
|
|||
bundle.putString("stationName", internetRadioStation.getName());
|
||||
bundle.putString("uri", uri.toString());
|
||||
bundle.putString("type", Constants.MEDIA_TYPE_RADIO);
|
||||
bundle.putString("coverArtId", coverArtId);
|
||||
if (homePageUrl != null) {
|
||||
bundle.putString("homepageUrl", homePageUrl);
|
||||
}
|
||||
|
||||
return new MediaItem.Builder()
|
||||
.setMediaId(internetRadioStation.getId())
|
||||
.setMediaMetadata(
|
||||
new MediaMetadata.Builder()
|
||||
.setTitle(internetRadioStation.getName())
|
||||
.setMediaType(MediaMetadata.MEDIA_TYPE_RADIO_STATION)
|
||||
.setArtworkUri(artworkUri)
|
||||
.setExtras(bundle)
|
||||
.setIsBrowsable(false)
|
||||
.setIsPlayable(true)
|
||||
|
|
@ -331,4 +347,4 @@ public class MappingUtil {
|
|||
}
|
||||
ExternalAudioReader.getRefreshEvents().observe(owner, event -> onRefresh.run());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -377,4 +377,15 @@ public class MusicUtil {
|
|||
|
||||
toFilter.addAll(filtered);
|
||||
}
|
||||
|
||||
public static boolean isImageUrl(String url) {
|
||||
if (url == null || url.isEmpty())
|
||||
return false;
|
||||
String path = url.toLowerCase().trim().split("\\?")[0];
|
||||
|
||||
return path.endsWith(".jpg") || path.endsWith(".jpeg") ||
|
||||
path.endsWith(".png") || path.endsWith(".webp") ||
|
||||
path.endsWith(".gif") || path.endsWith(".bmp") ||
|
||||
path.endsWith(".svg");
|
||||
}
|
||||
}
|
||||
|
|
@ -375,7 +375,7 @@ open class MediaLibrarySessionCallback(
|
|||
automotiveRepository.internetRadioStations,
|
||||
{ result ->
|
||||
val stations = result?.value
|
||||
val selected = stations?.find { it.mediaId == firstItem?.mediaId }
|
||||
val selected = stations?.find { item -> item.mediaId == firstItem?.mediaId }
|
||||
if (selected != null) {
|
||||
val updatedSelected = selected.buildUpon()
|
||||
.setMimeType(selected.localConfiguration?.mimeType)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue