diff --git a/.gitignore b/.gitignore index 0f48176e..1047677c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,7 @@ .cxx /.idea/ .env -.vscode/settings.json \ No newline at end of file +.vscode/settings.json +# release / debug files +tempus-release-key.jks +app/tempo/ \ No newline at end of file diff --git a/README.md b/README.md index cf157638..00680d8d 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ This fork is my attempt to keep development moving forward and merge in PR's tha Moved details to [CHANGELOG.md](https://github.com/eddyizm/tempo/blob/main/CHANGELOG.md) +Fork [**sponsorship here**](https://ko-fi.com/eddyizm). + ## Features - **Subsonic Integration**: Tempo seamlessly integrates with your Subsonic server, providing you with easy access to your entire music collection on the go. - **Sleek and Intuitive UI**: Enjoy a clean and user-friendly interface designed to enhance your music listening experience, tailored to your preferences and listening history. @@ -41,21 +43,11 @@ Moved details to [CHANGELOG.md](https://github.com/eddyizm/tempo/blob/main/CHANG - **Transcoding Support**: Activate transcoding of tracks on your Subsonic server, allowing you to set a transcoding profile for optimized streaming directly from the app. This feature requires support from your Subsonic server. - **Android Auto Support**: Enjoy your favorite music on the go with full Android Auto integration, allowing you to seamlessly control and listen to your tracks directly from your mobile device while driving. -

- - - - - - - - -

- ## Sponsors +Thanks to the original repo/creator [CappielloAntonio](https://github.com/CappielloAntonio) (3.9.0) + Tempo is an open-source project developed and maintained solely by me. I would like to express my heartfelt thanks to all the users who have shown their love and support for Tempo. Your contributions and encouragement mean a lot to me, and they help drive the development and improvement of the app. -If you would like to sponsor the project and show your support, you can make a donation or contribution by visiting the [**sponsorship page**](https://www.buymeacoffee.com/a.cappiello). Your generosity will help cover the costs of development and further enhancements. ## Screenshot diff --git a/app/build.gradle b/app/build.gradle index ea649294..0aace15a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { minSdkVersion 24 targetSdk 35 - versionCode 27 - versionName '3.11.2' + versionCode 28 + versionName '3.12.0' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java b/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java index 84afcb6a..f866c250 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java @@ -15,6 +15,8 @@ import com.cappielloantonio.tempo.util.MusicUtil; import com.cappielloantonio.tempo.util.Preferences; import com.google.android.material.dialog.MaterialAlertDialogBuilder; +import java.util.Objects; + public class TrackInfoDialog extends DialogFragment { private DialogTrackInfoBinding bind; @@ -51,7 +53,12 @@ public class TrackInfoDialog extends DialogFragment { private void setTrackInfo() { bind.trakTitleInfoTextView.setText(mediaMetadata.title); - bind.trakArtistInfoTextView.setText(mediaMetadata.artist); + bind.trakArtistInfoTextView.setText( + mediaMetadata.artist != null + ? mediaMetadata.artist + : mediaMetadata.extras != null && Objects.equals(mediaMetadata.extras.getString("type"), Constants.MEDIA_TYPE_RADIO) + ? mediaMetadata.extras.getString("uri", getString(R.string.label_placeholder)) + : ""); if (mediaMetadata.extras != null) { CustomGlideRequest.Builder @@ -62,20 +69,20 @@ public class TrackInfoDialog extends DialogFragment { bind.titleValueSector.setText(mediaMetadata.extras.getString("title", getString(R.string.label_placeholder))); bind.albumValueSector.setText(mediaMetadata.extras.getString("album", getString(R.string.label_placeholder))); bind.artistValueSector.setText(mediaMetadata.extras.getString("artist", getString(R.string.label_placeholder))); - bind.trackNumberValueSector.setText(String.valueOf(mediaMetadata.extras.getInt("track", 0))); - bind.yearValueSector.setText(String.valueOf(mediaMetadata.extras.getInt("year", 0))); + bind.trackNumberValueSector.setText(mediaMetadata.extras.getInt("track", 0) != 0 ? String.valueOf(mediaMetadata.extras.getInt("track", 0)) : getString(R.string.label_placeholder)); + bind.yearValueSector.setText(mediaMetadata.extras.getInt("year", 0) != 0 ? String.valueOf(mediaMetadata.extras.getInt("year", 0)) : getString(R.string.label_placeholder)); bind.genreValueSector.setText(mediaMetadata.extras.getString("genre", getString(R.string.label_placeholder))); - bind.sizeValueSector.setText(MusicUtil.getReadableByteCount(mediaMetadata.extras.getLong("size", 0))); + bind.sizeValueSector.setText(mediaMetadata.extras.getLong("size", 0) != 0 ? MusicUtil.getReadableByteCount(mediaMetadata.extras.getLong("size", 0)) : getString(R.string.label_placeholder)); bind.contentTypeValueSector.setText(mediaMetadata.extras.getString("contentType", getString(R.string.label_placeholder))); bind.suffixValueSector.setText(mediaMetadata.extras.getString("suffix", getString(R.string.label_placeholder))); bind.transcodedContentTypeValueSector.setText(mediaMetadata.extras.getString("transcodedContentType", getString(R.string.label_placeholder))); bind.transcodedSuffixValueSector.setText(mediaMetadata.extras.getString("transcodedSuffix", getString(R.string.label_placeholder))); - bind.durationValueSector.setText(MusicUtil.getReadableDurationString(mediaMetadata.extras.getInt("duration", 0), false)); - bind.bitrateValueSector.setText(mediaMetadata.extras.getInt("bitrate", 0) + " kbps"); + bind.durationValueSector.setText(mediaMetadata.extras.getInt("duration", 0) != 0 ? MusicUtil.getReadableDurationString(mediaMetadata.extras.getInt("duration", 0), false) : getString(R.string.label_placeholder)); + bind.bitrateValueSector.setText(mediaMetadata.extras.getInt("bitrate", 0) != 0 ? mediaMetadata.extras.getInt("bitrate", 0) + " kbps" : getString(R.string.label_placeholder)); bind.samplingRateValueSector.setText(mediaMetadata.extras.getInt("samplingRate", 0) != 0 ? mediaMetadata.extras.getInt("samplingRate", 0) + " Hz" : getString(R.string.label_placeholder)); bind.bitDepthValueSector.setText(mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + " bits" : getString(R.string.label_placeholder)); bind.pathValueSector.setText(mediaMetadata.extras.getString("path", getString(R.string.label_placeholder))); - bind.discNumberValueSector.setText(String.valueOf(mediaMetadata.extras.getInt("discNumber", 0))); + bind.discNumberValueSector.setText(mediaMetadata.extras.getInt("discNumber", 0) != 0 ? String.valueOf(mediaMetadata.extras.getInt("discNumber", 0)) : getString(R.string.label_placeholder)); } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerBottomSheetFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerBottomSheetFragment.java index b3755ee3..6841f247 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerBottomSheetFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerBottomSheetFragment.java @@ -174,7 +174,12 @@ public class PlayerBottomSheetFragment extends Fragment { playerBottomSheetViewModel.setLiveDescription(mediaMetadata.extras.getString("description", null)); bind.playerHeaderLayout.playerHeaderMediaTitleLabel.setText(mediaMetadata.extras.getString("title")); - bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setText(mediaMetadata.extras.getString("artist")); + bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setText( + mediaMetadata.artist != null + ? mediaMetadata.artist + : Objects.equals(mediaMetadata.extras.getString("type"), Constants.MEDIA_TYPE_RADIO) + ? mediaMetadata.extras.getString("uri", getString(R.string.label_placeholder)) + : ""); CustomGlideRequest.Builder .from(requireContext(), mediaMetadata.extras.getString("coverArtId"), CustomGlideRequest.ResourceType.Song) @@ -182,7 +187,11 @@ public class PlayerBottomSheetFragment extends Fragment { .into(bind.playerHeaderLayout.playerHeaderMediaCoverImage); bind.playerHeaderLayout.playerHeaderMediaTitleLabel.setVisibility(mediaMetadata.extras.getString("title") != null && !Objects.equals(mediaMetadata.extras.getString("title"), "") ? View.VISIBLE : View.GONE); - bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setVisibility(mediaMetadata.extras.getString("artist") != null && !Objects.equals(mediaMetadata.extras.getString("artist"), "") ? View.VISIBLE : View.GONE); + bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setVisibility( + (mediaMetadata.extras.getString("artist") != null && !Objects.equals(mediaMetadata.extras.getString("artist"), "")) + || (Objects.equals(mediaMetadata.extras.getString("type"), Constants.MEDIA_TYPE_RADIO) && mediaMetadata.extras.getString("uri") != null) + ? View.VISIBLE + : View.GONE); } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java index 37cd9f10..a07d58ec 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java @@ -10,6 +10,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.TextView; import android.widget.ToggleButton; +import android.widget.RatingBar; import androidx.annotation.NonNull; import androidx.constraintlayout.widget.ConstraintLayout; @@ -36,6 +37,7 @@ import com.cappielloantonio.tempo.util.Constants; import com.cappielloantonio.tempo.util.MusicUtil; import com.cappielloantonio.tempo.util.Preferences; import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel; +import com.cappielloantonio.tempo.viewmodel.RatingViewModel; import com.google.android.material.chip.Chip; import com.google.android.material.elevation.SurfaceColors; import com.google.common.util.concurrent.ListenableFuture; @@ -53,6 +55,8 @@ public class PlayerControllerFragment extends Fragment { private InnerFragmentPlayerControllerBinding bind; private ViewPager2 playerMediaCoverViewPager; private ToggleButton buttonFavorite; + private RatingViewModel ratingViewModel; + private RatingBar songRatingBar; private TextView playerMediaTitleLabel; private TextView playerArtistNameLabel; private Button playbackSpeedButton; @@ -75,6 +79,7 @@ public class PlayerControllerFragment extends Fragment { View view = bind.getRoot(); playerBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(PlayerBottomSheetViewModel.class); + ratingViewModel = new ViewModelProvider(requireActivity()).get(RatingViewModel.class); init(); initQuickActionView(); @@ -117,6 +122,7 @@ public class PlayerControllerFragment extends Fragment { playerQuickActionView = bind.getRoot().findViewById(R.id.player_quick_action_view); playerOpenQueueButton = bind.getRoot().findViewById(R.id.player_open_queue_button); playerTrackInfo = bind.getRoot().findViewById(R.id.player_info_track); + songRatingBar = bind.getRoot().findViewById(R.id.song_rating_bar); } private void initQuickActionView() { @@ -146,7 +152,6 @@ public class PlayerControllerFragment extends Fragment { bind.nowPlayingMediaControllerView.setPlayer(mediaBrowser); mediaBrowser.setShuffleModeEnabled(Preferences.isShuffleModeEnabled()); mediaBrowser.setRepeatMode(Preferences.getRepeatMode()); - setMediaControllerListener(mediaBrowser); } catch (Exception e) { e.printStackTrace(); @@ -181,18 +186,27 @@ public class PlayerControllerFragment extends Fragment { private void setMetadata(MediaMetadata mediaMetadata) { playerMediaTitleLabel.setText(String.valueOf(mediaMetadata.title)); - playerArtistNameLabel.setText(String.valueOf(mediaMetadata.artist)); + playerArtistNameLabel.setText( + mediaMetadata.artist != null + ? String.valueOf(mediaMetadata.artist) + : mediaMetadata.extras != null && Objects.equals(mediaMetadata.extras.getString("type"), Constants.MEDIA_TYPE_RADIO) + ? mediaMetadata.extras.getString("uri", getString(R.string.label_placeholder)) + : ""); playerMediaTitleLabel.setSelected(true); playerArtistNameLabel.setSelected(true); playerMediaTitleLabel.setVisibility(mediaMetadata.title != null && !Objects.equals(mediaMetadata.title, "") ? View.VISIBLE : View.GONE); - playerArtistNameLabel.setVisibility(mediaMetadata.artist != null && !Objects.equals(mediaMetadata.artist, "") ? View.VISIBLE : View.GONE); + playerArtistNameLabel.setVisibility( + (mediaMetadata.artist != null && !Objects.equals(mediaMetadata.artist, "")) + || mediaMetadata.extras != null && Objects.equals(mediaMetadata.extras.getString("type"), Constants.MEDIA_TYPE_RADIO) && mediaMetadata.extras.getString("uri") != null + ? View.VISIBLE + : View.GONE); } private void setMediaInfo(MediaMetadata mediaMetadata) { if (mediaMetadata.extras != null) { - String extension = mediaMetadata.extras.getString("suffix", "Unknown format"); + String extension = mediaMetadata.extras.getString("suffix", getString(R.string.player_unknown_format)); String bitrate = mediaMetadata.extras.getInt("bitrate", 0) != 0 ? mediaMetadata.extras.getInt("bitrate", 0) + "kbps" : "Original"; String samplingRate = mediaMetadata.extras.getInt("samplingRate", 0) != 0 ? new DecimalFormat("0.#").format(mediaMetadata.extras.getInt("samplingRate", 0) / 1000.0) + "kHz" : ""; String bitDepth = mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + "b" : ""; @@ -218,8 +232,8 @@ public class PlayerControllerFragment extends Fragment { boolean isTranscodingBitrate = !MusicUtil.getBitratePreference().equals("0"); if (isTranscodingExtension || isTranscodingBitrate) { - playerMediaExtension.setText("Transcoding"); - playerMediaBitrate.setText("requested"); + playerMediaExtension.setText(MusicUtil.getTranscodingFormatPreference() + " (" + getString(R.string.player_transcoding) + ")"); + playerMediaBitrate.setText(!MusicUtil.getBitratePreference().equals("0") ? MusicUtil.getBitratePreference() + "kbps" : getString(R.string.player_transcoding_requested)); } playerTrackInfo.setOnClickListener(view -> { @@ -305,6 +319,7 @@ public class PlayerControllerFragment extends Fragment { private void initMediaListenable() { playerBottomSheetViewModel.getLiveMedia().observe(getViewLifecycleOwner(), media -> { if (media != null) { + ratingViewModel.setSong(media); buttonFavorite.setChecked(media.getStarred() != null); buttonFavorite.setOnClickListener(v -> playerBottomSheetViewModel.setFavorite(requireContext(), media)); buttonFavorite.setOnLongClickListener(v -> { @@ -315,9 +330,29 @@ public class PlayerControllerFragment extends Fragment { dialog.setArguments(bundle); dialog.show(requireActivity().getSupportFragmentManager(), null); + return true; }); + Integer currentRating = media.getUserRating(); + + if (currentRating != null) { + songRatingBar.setRating(currentRating); + } else { + songRatingBar.setRating(0); + } + + songRatingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() { + @Override + public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) { + if (fromUser) { + ratingViewModel.rate((int) rating); + media.setUserRating((int) rating); + } + } + }); + + if (getActivity() != null) { playerBottomSheetViewModel.refreshMediaInfo(requireActivity(), media); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java index 1b88774d..f8f15f07 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java @@ -140,7 +140,6 @@ public class MappingUtil { Bundle bundle = new Bundle(); bundle.putString("id", internetRadioStation.getId()); bundle.putString("title", internetRadioStation.getName()); - bundle.putString("artist", uri.toString()); bundle.putString("uri", uri.toString()); bundle.putString("type", Constants.MEDIA_TYPE_RADIO); @@ -149,7 +148,6 @@ public class MappingUtil { .setMediaMetadata( new MediaMetadata.Builder() .setTitle(internetRadioStation.getName()) - .setArtist(internetRadioStation.getStreamUrl()) .setExtras(bundle) .setIsBrowsable(false) .setIsPlayable(true) diff --git a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java index 3e712479..bf90fa65 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java +++ b/app/src/main/java/com/cappielloantonio/tempo/viewmodel/PlayerBottomSheetViewModel.java @@ -103,7 +103,6 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel { favoriteRepository.starLater(media.getId(), null, null, false); } }); - media.setStarred(null); } @@ -131,7 +130,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel { } } - public LiveData getLiveLyrics() { + public LiveData getLiveLyrics() { return lyricsLiveData; } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 106500a5..01edf7f5 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -47,6 +47,8 @@ android:layout_height="wrap_content" android:gravity="center" android:text="@string/activity_info_offline_mode" - android:textSize="6sp" + android:textSize="12sp" + android:textStyle="bold" android:visibility="gone" /> + diff --git a/app/src/main/res/layout/inner_fragment_player_controller_layout.xml b/app/src/main/res/layout/inner_fragment_player_controller_layout.xml index ac318326..9063e242 100644 --- a/app/src/main/res/layout/inner_fragment_player_controller_layout.xml +++ b/app/src/main/res/layout/inner_fragment_player_controller_layout.xml @@ -104,6 +104,37 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/player_media_title_label" /> + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 1df280e0..c2b2a527 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -103,6 +103,9 @@ Sichern Startseite anpassen Die Anwendung muss neu gestartet werden, um die Änderungen auszuführen. + Musik + Podcast + Radio Top Tracks Deiner Lieblingskünstler Ein Mix von einem deiner Lieblingslieder erstellen Radio hinzufügen @@ -286,6 +289,7 @@ Github Bilder Auflösung anpassen Sprache + Systemsprache Abmelden Bitrate für Downloads Bitrate bei mobiler Nutzung @@ -392,6 +396,7 @@ Titel Album Künstler + Bit-Tiefe Track Nummer Jahr Genre @@ -402,6 +407,7 @@ Transkodiertes Suffix Länge Bitrate + Abtastrate Pfad Disk Nummer Diese Datei wurde mit den Subsonic APIs heruntergeladen. Der Codec und die Bitrate sind unverändert zur original Datei. diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 4f7beefd..518931af 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -196,6 +196,9 @@ %1$.2fx Limpiar la cola de reproducción Prioridad del servidor + Formato desconocido + Transcodificando + solicitado Catálogo de listas de reproducción Explorar listas de reproducción No hay listas de reproducción diff --git a/app/src/main/res/values-fr/arrays.xml b/app/src/main/res/values-fr/arrays.xml index dfc37679..7d0198c0 100644 --- a/app/src/main/res/values-fr/arrays.xml +++ b/app/src/main/res/values-fr/arrays.xml @@ -32,6 +32,21 @@ 300 + + Désactivé + 128 MiB + 256 MiB + 512 MiB + 1024 MiB + + + 0 + 128 + 256 + 512 + 1024 + + Original 32 kbps diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index aebaee19..a41b43fa 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -24,7 +24,10 @@ Albums Similaire Lire + Sorti le %1$s + Sorti le %1$s, initialement %2$s Mélanger + %1$d titres • %2$d minutes Tempo Recherche… Mix instantané @@ -51,13 +54,16 @@ Annuler Activer l\'économie de données OK - L\'accès au serveur Subsonic sur des connexions autres que le Wi-Fi ont été bloquées. Pour empêcher cette alerte de réapparaître, désactiver la vérification de la connexion dans les paramètres de l\'app. + L\'accès au serveur Subsonic sur des connexions autres que le Wi-Fi a été bloqué. Pour empêcher cette alerte de réapparaître, désactiver la vérification de la connexion dans les paramètres de l\'app. Wi-Fi déconnecté + Mélanger Annuler Continuer - Sachez que la poursuite de cette action entraînera la suppression permanente de tous les éléments sauvegardés et téléchargés à partir de tous les serveurs + Attention, la poursuite de cette action entraînera la suppression définitive de tous les éléments sauvegardés et téléchargés à partir de tous les serveurs Supprimer les éléments téléchargés Aucune description disponible + Disque %1$s - %2$s + Disque %1$s Annuler Télécharger Toutes les pistes dans ce dossier seront téléchargées. Les pistes dans les sous-dossiers ne seront pas téléchargées. @@ -66,8 +72,9 @@ Aucun téléchargement pour l\'instant %1$s • %2$s éléments %1$s éléments + Tout mélanger Redémarrez l\'application pour appliquer les changements. - Changer la destination des téléchargements d\'un espace de stockage à un autre résultera en la suppression immédiate de tous les fichiers précédemment téléchargés dans l\'autre espace de stockage. + Modifier le chemin de stockage des téléchargements entraînera la suppression immédiate de tous les fichiers précédemment téléchargés dans le nouvel espace de stockage. Sélectionnez l\'option de stockage Externe Interne @@ -84,8 +91,23 @@ Sélectionnez deux filtres ou plus Filtrer Filtrer par genre + (%1$d) + (+%1$d) Catalogue des Genres Parcourir les Genres + Me rappeler plus tard + Me soutenir + Télécharger maintenant + Une version plus récente de l\'app est disponible sur Github. + Mise à jour disponible + Annuler + Réinitialiser + Sauvegarder + Réorganiser l\'écran d\'accueil + Veuillez noter que ces changements ne s\'appliqueront qu\'après redémarrage de l\'application. + Musique + Podcast + Radio Meilleurs morceaux de vos artistes préférés Commencez le mix à partir d\'une chanson que vous aimez Ajouter une radio @@ -102,11 +124,14 @@ Écouté dernièrement Voir tout Sur la dernière semaine + Sur le dernier mois + Sur la dernière année Faits pour vous Les plus écoutés Voir tout Nouvelles sorties Nouveau podcasts + Playlists Chaînes Voir tout Stations radio @@ -120,6 +145,7 @@ ★ Titres favoris Voir tout Vos morceaux préférés + Réorganiser Albums Voir tout Artistes @@ -144,13 +170,23 @@ Genre Piste Année - Home - Librairie + Accueil + Sur la dernière semaine + Sur le dernier mois + Sur la dernière année + Bibliothèque Rechercher Paramètres Artiste Nom Aléatoire + Récemment ajoutés + Récemment lus + Plus lus + Favoris les plus récents + Favoris les plus anciens + Ajouter à l\'écran d\'accueil + Retirer de l\'écran d\'accueil Année %1$.2fx Vider la file d\'attente @@ -161,8 +197,11 @@ Annuler Créer Ajouter à une playlist + Titre ajouté à la playlist + Échec d\'ajout du titre à la playlist %1$d titres • %2$s Durée • %1$s + Appui long pour supprimer Nom de la playlist Annuler Supprimer @@ -208,6 +247,8 @@ Artistes Pistes Sécurité basse + Appui long pour supprimer + URL local Nom du serveur Mot de passe URL du serveur @@ -221,8 +262,9 @@ Continuer quand même Le serveur est injoignable. Si vous décidez de continuer, cette fenêtre n\'apparaîtra plus pendant une heure. Serveur injoignable - Tempo est un client open source et léger pour Subsonic, développé et build nativement pour Android. + Tempo est un client open source et léger pour Subsonic, développé et compilé nativement pour Android. À propos + Toujours visible Format de transcodage Si activé, Tempo ne forcera pas le téléchargement de la piste avec les paramètres de transcodage ci-dessous. Prioriser les paramètres du serveurs, utilisés pour le streaming, dans les téléchargements @@ -238,6 +280,8 @@ La priorité au transcodage de la piste est donnée au serveur Stratégie de mise en mémoire tampon Redémarrez l\'application pour appliquer les changements. + Permet de prolonger la lecture après la fin d\'une playlist avec des titres similaires + Lecture continue Taille du cache des illustrations Pour réduire la consommation de données, éviter de télécharger les illustrations. Limiter l\'utilisation des données mobiles @@ -252,14 +296,18 @@ Définir la résolution des images Langue Se déconnecter - Bitrate pour les téléchargements - Bitrate en données mobile - Bitrate en Wi-Fi + Débit binaire pour les téléchargements + Débit binaire en données mobile + Débit binaire en Wi-Fi Taille du cache des fichiers audios Afficher les dossiers Si activé, rend possible la navigation dans les répertoires. À noter que pour que la navigation dans les dossiers fonctionne correctement, le serveur doit supporter cette fonctionnalité. Voir les podcasts Si activé, rend visible la section Podcast + Afficher la qualité audio + Le débit binaire et le format audio seront affichés pour chaque piste. + Afficher la note + Si activé, la note et le statut de mise en favori de l\'élément seront affichés. Minuteur de synchronisation Si activé, l\'utilisateur pourra sauvegarder sa file d\'attente et la recharger au démarrage de l\'application. Synchroniser la file d\'attente pour cet utilisateur @@ -272,15 +320,19 @@ Si activé, arrondi les angles des illustrations. Les modifications prendront effet au redémarrage. Scanner la bibliothèque Activer le scrobbling + Langue du système Activer le partage de musique + Taille du cache de streaming + Emplacement du cache de streaming À noter que le scrobbling doit être activé sur le serveur pour qu\'il puisse recevoir ces données Lors de l\'écoute de la radio d\'un artiste, d\'un mix instantané ou de tout la bibliothèque en aléatoire, les pistes en dessous d\'une certaine note seront ignorées. Le Replay Gain est une fonctionnalité qui vous permet d\'ajuster le volume des pistes audio pour une expérience d\'écoute cohérente. Fonctionne uniquement si la piste contient les métadonnées nécessaires. Le scrobbling permet à votre appareil d\'envoyer des informations sur les musiques que vous écoutez au serveur afin de créer des recommendations personnalisées basées sur vos préférences musicales. Permet à l\'utilisateur de partager de la musique via un lien. Cette fonctionnalité doit être supportée et activée sur le serveur et est limitée aux pistes, albums et playlists individuellement. Renvoie l\'état de la file d\'attente de cet utilisateur. Cela inclut les pistes dans la file, la piste actuellement écoutée et la position dans la piste. Cette fonctionnalité doit être supportée par le serveur. - Le mode de transcodage à prioriser. Si reglé sur \"Lecture directe\", le bitrate du fichier ne sera pas modifié. - Télécharge les médias transcodés. Si activé, les paramètres de transcodage suivants seront utilisés pour les téléchargements.\n\n Si le format de transcodage est reglé à \"Téléchargement direct\", le bitrate du fichier ne sera pas modifé. + %1$s \nUtilisé actuellement : %2$s MiB + Le mode de transcodage à prioriser. Si réglé sur \"Lecture directe\", le débit binaire du fichier ne sera pas modifié. + Télécharge les médias transcodés. Si activé, les paramètres de transcodage suivants seront utilisés pour les téléchargements.\n\n Si le format de transcodage est reglé à \"Téléchargement direct\", le débit binaire du fichier ne sera pas modifé. Quand le fichier est transcodé à la volé, en général, le client n\'affiche pas la durée de la piste. Il est possible de demander aux serveurs qui le supportent d\'estimer la durée de la piste écoutée, mais les temps de réponses peuvent être plus longs. Si activé, les pistes favorites seront téléchargées pour l\'écoute hors-ligne Synchronisation des pistes favorites pour écoute hors-ligne @@ -291,7 +343,7 @@ Replay Gain Scrobble Ignorer des musiques selon leur note - Musiques avec une note de: + Musiques avec une note de : Partage Synchronisation Transcodage @@ -336,9 +388,16 @@ Continuer et télécharger Le téléchargement des titres favoris pourrer utiliser beaucoup de données. Synchroniser les titres favoris + Veuillez redémarrer l\'app pour appliquer les changements. + Modifier le chemin de stockage des fichiers mis en cache risque de provoquer la suppression de tous les fichiers précédemment mis en cache dans le nouvel espace de stockage. + Sélectionner une option de stockage + Externe + Interne + https://buymeacoffee.com/a.cappiello Album Artiste - Bitrate + Résolution audio + Débit binaire Type de contenu OK Infos piste @@ -346,14 +405,15 @@ Durée Genre Chemin + Fréquence d\'échantillonnage Taille Suffixe - Le fichier a été téléchargé depuis les APIs Subsonic. Le codec et le bitrate du fichier demeure inchangé du fichier d\'origine. - L\'application demandera au serveur de transcoder le fichier et de modifier son bitrate. Le codec demandé par l\'utilisateur est %1$s, avec un bitrate de %2$s. Toute modification éventuelle du codec et du bitrate du fichier dans le format choisi sera gérée par le serveur, qui peut ou non prendre en charge l\'opération. - L\'application ne lira que le fichier original tel que fourni par le serveur. L\'application demandera explicitement au serveur le fichier non transcodé avec le bitrate de la source originale. - La qualité du fichier à lire est laissée à l\'appréciation du serveur. L\'application n\'impose pas le choix du codec et du bitrate pour un éventuel transcodage. - L\'application demandera au serveur de modifier le bitrate du fichier. L\'utilisateur a choisi un bitrate de %1$s, tandis que le codec du fichier restera le même. Toute modification du bitrate du fichier dans le format choisi sera effectuée par le serveur, qui peut ou non prendre en charge l\'opération. - L\'application demandera au serveur de transcoder le fichier. Le codec choisi par l\'utilisateur est le %1$s, tandis que le bitrate sera le même que celui du fichier source. Le transcodage éventuel du fichier dans le codec choisi dépend du serveur, qui peut ou non prendre en charge l\'opération. + Le fichier a été téléchargé depuis les APIs Subsonic. Le codec et le débit binaire du fichier demeurent identiques à ceux du fichier d\'origine. + L\'application demandera au serveur de transcoder le fichier et de modifier son débit binaire. Le codec demandé par l\'utilisateur est %1$s, avec un débit binaire de %2$s. Toute modification éventuelle du codec et du débit binaire du fichier dans le format choisi sera gérée par le serveur, qui peut ou non prendre en charge l\'opération. + L\'application ne lira que le fichier original tel que fourni par le serveur. L\'application demandera explicitement au serveur le fichier non transcodé avec le débit binaire de la source originale. + La qualité du fichier à lire est laissée à l\'appréciation du serveur. L\'application n\'impose pas le choix du codec et du débit binaire pour un éventuel transcodage. + L\'application demandera au serveur de modifier le débit binaire du fichier. L\'utilisateur a choisi un débit binaire de %1$s, tandis que le codec du fichier restera le même. Toute modification du débit binaire du fichier dans le format choisi sera effectuée par le serveur, qui peut ou non prendre en charge l\'opération. + L\'application demandera au serveur de transcoder le fichier. Le codec choisi par l\'utilisateur est le %1$s, tandis que le débit binaire sera le même que celui du fichier source. Le transcodage éventuel du fichier dans le codec choisi dépend du serveur, qui peut ou non prendre en charge l\'opération. Titre Numéro de piste Transcodé type de contenu diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml index 4725c4a3..e62f234f 100644 --- a/app/src/main/res/values-night/styles.xml +++ b/app/src/main/res/values-night/styles.xml @@ -41,7 +41,7 @@ \ No newline at end of file diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 37f1685a..ddaca1b2 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -103,7 +103,13 @@ Reset Zapisz Zmień układ strony głównej - Weź pod uwagę to że, żeby zmiany nastąpiły, musisz zrestartować aplikację. + Weź pod uwagę to że, żeby zmiany nastąpiły, musisz zrestartować aplikację. + Muzyka + Podcasty + Radio + Głębia bitowa + Częstotliwość próbkowania + Język systemu Top piosenki od twoich ulubionych wykonawców Stwórz miks z piosenki którą lubisz Dodaj nowe radio @@ -415,4 +421,4 @@ unDraw Specjalne podziękowania dla unDraw bez którego ilustracji nie mogliśmy uczynić tej aplikacji jeszcze piękniejszą. https://undraw.co/ - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index faea756e..dd2b066e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -193,6 +193,9 @@ %1$.2fx Clean play queue Server Priority + Unknown format + Transcoding + requested Playlist Catalogue Browse Playlists No playlists created diff --git a/app/src/notquitemy/java/com/cappielloantonio/tempo/service/MediaService.kt b/app/src/notquitemy/java/com/cappielloantonio/tempo/service/MediaService.kt index b8a7179b..92c4b9b3 100644 --- a/app/src/notquitemy/java/com/cappielloantonio/tempo/service/MediaService.kt +++ b/app/src/notquitemy/java/com/cappielloantonio/tempo/service/MediaService.kt @@ -138,10 +138,19 @@ class MediaService : MediaLibraryService() { controller: ControllerInfo, mediaItems: List ): ListenableFuture> { - val updatedMediaItems = mediaItems.map { - it.buildUpon() - .setUri(it.requestMetadata.mediaUri) - .setMediaMetadata(it.mediaMetadata) + val updatedMediaItems = mediaItems.map { mediaItem -> + val mediaMetadata = mediaItem.mediaMetadata + + val newMetadata = mediaMetadata.buildUpon() + .setArtist( + if (mediaMetadata.artist != null) mediaMetadata.artist + else mediaMetadata.extras?.getString("uri") ?: "" + ) + .build() + + mediaItem.buildUpon() + .setUri(mediaItem.requestMetadata.mediaUri) + .setMediaMetadata(newMetadata) .setMimeType(MimeTypes.BASE_TYPE_AUDIO) .build() }