16 Commits

Author SHA1 Message Date
eddyizm
0fb6e55b12 chore: update changelog and fastlane 2026-01-26 21:32:07 -08:00
eddyizm
dd7aa2291b chore: bump version 2026-01-26 21:29:40 -08:00
eddyizm
ec33c32c89 fix: updated dialog import to address crashing on android 15 (#392)
resolves #362
2026-01-26 21:25:27 -08:00
Jaime García
e0ad4e3701 fix: Avoid crash when server has no songs (#389) 2026-01-26 16:24:23 -08:00
eddyizm
253f8033c5 Merge branch 'development' 2026-01-25 11:41:50 -08:00
eddyizm
c1aed1a4c1 chore: version/changelog/fastlane bumps 2026-01-25 11:41:26 -08:00
eddyizm
23f58439ba Merge branch 'development' 2026-01-25 11:34:27 -08:00
eddyizm
4c99ced597 chore: version/changelog/fastlane bumps 2026-01-25 11:34:16 -08:00
eddyizm
8d215a7f1c feat: add configurable timeout (#386) 2026-01-25 11:27:12 -08:00
eddyizm
38fc4a0936 chore: forget to check in fastlane change log 2026-01-25 08:06:29 -08:00
eddyizm
d9949349da chore: forget to check in fastlane change log 2026-01-25 08:06:06 -08:00
Jaime García
877d29d285 chore(i18n): Update Spanish translation (#381) 2026-01-24 14:05:52 -08:00
Jaime García
9a17aa8b98 fix: Proper raw stream detection (#382) 2026-01-24 14:05:36 -08:00
eddyizm
fd41395ab8 chore: bump version for tag 2026-01-24 09:11:41 -08:00
eddyizm
269066e036 Merge branch 'development' 2026-01-24 09:09:23 -08:00
eddyizm
04e692e5e9 chore: fixed read me donate link 2026-01-24 07:51:30 -08:00
15 changed files with 119 additions and 12 deletions

View File

@@ -3,7 +3,22 @@
## Pending release
## What's Changed
## [4.9.0](https://github.com/eddyizm/tempo/releases/tag/v4.9.0) (2026-01-24)
## [4.9.5](https://github.com/eddyizm/tempo/releases/tag/v4.9.5) (2026-01-26)
* fix: Avoid crash when server has no songs by @jaime-grj in https://github.com/eddyizm/tempus/pull/389
* fix: updated dialog import to address crashing on android 15 by @eddyizm in https://github.com/eddyizm/tempus/pull/392
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.9.3...v4.9.5
## What's Changed
## [4.9.3](https://github.com/eddyizm/tempo/releases/tag/v4.9.3) (2026-01-25)
* fix: Proper raw stream detection by @jaime-grj in https://github.com/eddyizm/tempus/pull/382
* chore(i18n): Update Spanish translation by @jaime-grj in https://github.com/eddyizm/tempus/pull/381
* feat: add configurable timeout by @eddyizm in https://github.com/eddyizm/tempus/pull/386
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.9.1...v4.9.3
## What's Changed
## [4.9.1](https://github.com/eddyizm/tempo/releases/tag/v4.9.1) (2026-01-24)
* chore: i18n: Add Romanian translation (including locale_config this time!) by @DevMatei in https://github.com/eddyizm/tempus/pull/357
* French localization update by @benoit-smith in https://github.com/eddyizm/tempus/pull/356
* chore(i18n): Update Spanish translation by @jaime-grj in https://github.com/eddyizm/tempus/pull/364
@@ -20,7 +35,7 @@
## New Contributors
* @pgrit made their first contribution in https://github.com/eddyizm/tempus/pull/375
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.6.4...v4.9.0
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.6.4...v4.9.1
## What's Changed
## [4.6.4](https://github.com/eddyizm/tempo/releases/tag/v4.6.4) (2026-01-13)

View File

@@ -10,8 +10,8 @@ android {
minSdkVersion 24
targetSdk 35
versionCode 14
versionName '4.9.0'
versionCode 16
versionName '4.9.5'
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
javaCompileOptions {

View File

@@ -283,7 +283,10 @@ public class SongRepository {
@Override public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
List<Child> songs = new ArrayList<>();
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null) {
songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getRandomSongs().getSongs()));
List<Child> returned = response.body().getSubsonicResponse().getRandomSongs().getSongs();
if (returned != null) {
songs.addAll(returned);
}
}
randomSongsSample.setValue(songs);
}
@@ -299,7 +302,10 @@ public class SongRepository {
@Override public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
List<Child> songs = new ArrayList<>();
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getRandomSongs() != null) {
songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getRandomSongs().getSongs()));
List<Child> returned = response.body().getSubsonicResponse().getRandomSongs().getSongs();
if (returned != null) {
songs.addAll(returned);
}
}
randomSongsSample.setValue(songs);
}
@@ -342,7 +348,10 @@ public class SongRepository {
@Override public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
List<Child> songs = new ArrayList<>();
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getSongsByGenre() != null) {
songs.addAll(Objects.requireNonNull(response.body().getSubsonicResponse().getSongsByGenre().getSongs()));
List<Child> returned = response.body().getSubsonicResponse().getSongsByGenre().getSongs();
if (returned != null) {
songs.addAll(returned);
}
}
songsByGenre.setValue(songs);
}

View File

@@ -24,13 +24,15 @@ public class SystemClient {
public Call<ApiResponse> ping() {
Log.d(TAG, "ping()");
int timeoutSeconds = Preferences.getNetworkPingTimeout();
Call<ApiResponse> pingCall = systemService.ping(subsonic.getParams());
if (Preferences.isInUseServerAddressLocal()) {
pingCall.timeout()
.timeout(1, TimeUnit.SECONDS);
.timeout(timeoutSeconds, TimeUnit.SECONDS);
} else {
int finalTimeout = Math.min(timeoutSeconds * 2, 10);
pingCall.timeout()
.timeout(3, TimeUnit.SECONDS);
.timeout(finalTimeout, TimeUnit.SECONDS);
}
return pingCall;
}

View File

@@ -1,6 +1,6 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import androidx.appcompat.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;

View File

@@ -9,6 +9,8 @@ import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.text.InputFilter;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -27,6 +29,7 @@ import androidx.media3.common.util.UnstableApi;
import androidx.navigation.NavController;
import androidx.navigation.NavOptions;
import androidx.navigation.fragment.NavHostFragment;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -141,6 +144,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
setStreamingCacheSize();
setAppLanguage();
setVersion();
setNetorkPingTimeoutBase();
actionLogout();
actionScan();
@@ -261,6 +265,30 @@ public class SettingsFragment extends PreferenceFragmentCompat {
}
}
private void setNetorkPingTimeoutBase() {
EditTextPreference networkPingTimeoutBase = findPreference("network_ping_timeout_base");
if (networkPingTimeoutBase != null) {
networkPingTimeoutBase.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
networkPingTimeoutBase.setOnBindEditTextListener(editText -> {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
editText.setFilters(new InputFilter[]{ (source, start, end, dest, dstart, dend) -> {
for (int i = start; i < end; i++) {
if (!Character.isDigit(source.charAt(i))) {
return "";
}
}
return null;
}});
});
networkPingTimeoutBase.setOnPreferenceChangeListener((preference, newValue) -> {
String input = (String) newValue;
return input != null && !input.isEmpty();
});
}
}
private void setStreamingCacheSize() {
ListPreference streamingCachePreference = findPreference("streaming_cache_size");

View File

@@ -49,8 +49,7 @@ class DynamicMediaSourceFactory(
val progressiveFactory = ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
val uri = mediaItem.localConfiguration?.uri
val isTranscoding = uri?.getQueryParameter("maxBitRate") != null ||
(uri?.getQueryParameter("format") != null && uri?.getQueryParameter("format") != "raw")
val isTranscoding = uri?.getQueryParameter("format") != null && uri.getQueryParameter("format") != "raw"
if (isTranscoding && OpenSubsonicExtensionsUtil.isTranscodeOffsetExtensionAvailable()) {
TranscodingMediaSource(mediaItem, dataSourceFactory, progressiveFactory)

View File

@@ -85,6 +85,8 @@ object Preferences {
private const val ARTIST_SORT_BY_ALBUM_COUNT= "artist_sort_by_album_count"
private const val SORT_SEARCH_CHRONOLOGICALLY= "sort_search_chronologically"
private const val ARTIST_DISPLAY_BIOGRAPHY= "artist_display_biography"
private const val NETWORK_PING_TIMEOUT = "network_ping_timeout_base"
@JvmStatic
fun getServer(): String? {
@@ -96,6 +98,19 @@ object Preferences {
App.getInstance().preferences.edit().putString(SERVER, server).apply()
}
@JvmStatic
fun getNetworkPingTimeout(): Int {
val timeoutString = App.getInstance().preferences.getString(NETWORK_PING_TIMEOUT, "2") ?: "2"
return (timeoutString.toIntOrNull() ?: 2).coerceAtLeast(1)
}
@JvmStatic
fun setNetworkPingTimeout(pingTimeout: String?) {
App.getInstance().preferences.edit().putString(NETWORK_PING_TIMEOUT, pingTimeout).apply()
}
@JvmStatic
fun getUser(): String? {
return App.getInstance().preferences.getString(USER, null)

View File

@@ -240,6 +240,15 @@
<item>8</item>
</string-array>
<string-array name="playlist_sort_option_titles">
<item>Por nombre</item>
<item>Aleatoriamente</item>
</string-array>
<string-array name="playlist_sort_option_values">
<item>ORDER_BY_NAME</item>
<item>ORDER_BY_RANDOM</item>
</string-array>
<string-array name="skip_min_star_rating_titles">
<item>0 estrellas como mínimo</item>
<item>1 estrella como mínimo</item>

View File

@@ -333,6 +333,7 @@
<string name="settings_music_directory_summary">Si se habilita, se mostrará la sección de carpetas de música. Tenga en cuenta que para que la navegación funcione correctamente, el servidor debe soportar esta característica.</string>
<string name="settings_podcast">Mostrar pódcasts</string>
<string name="settings_podcast_summary">Si se habilita, se mostrará la sección de pódcasts. Reinicia la aplicación para que los cambios surtan efecto.</string>
<string name="settings_playlist_sort">Ordenar listas de reproducción</string>
<string name="settings_audio_quality">Mostrar calidad de audio</string>
<string name="settings_audio_quality_summary">La tasa de bits y el formato de audio se mostrarán para cada pista de audio.</string>
<string name="settings_song_rating_summary">Si se habilita, muestra la valoración de la pista como barra de 5 estrellas en la página del control de reproducción.\n\n*Requiere reiniciar la aplicación</string>

View File

@@ -353,6 +353,9 @@
<string name="settings_image_size">Set image resolution</string>
<string name="settings_language">Language</string>
<string name="settings_logout_title">Log out</string>
<string name="settings_ping_timeout_title">Server Ping Timeout</string>
<string name="settings_ping_timeout_summary">Set Local URL timeout. Default 2 seconds. (Remote server will use this value x3 up to 10 seconds max.)</string>
<string name="settings_ping_timeout_dialog">Set base timeout in seconds.</string>
<string name="settings_max_bitrate_download">Bitrate for downloads</string>
<string name="settings_max_bitrate_mobile">Bitrate in mobile</string>
<string name="settings_max_bitrate_wifi">Bitrate in Wi-Fi</string>

View File

@@ -17,6 +17,15 @@
android:key="scan_library"
android:title="@string/settings_scan_title" />
<EditTextPreference
android:key="network_ping_timeout_base"
android:title="@string/settings_ping_timeout_title"
app:summary="@string/settings_ping_timeout_summary"
android:dialogTitle="@string/settings_ping_timeout_dialog"
android:inputType="number"
android:singleLine="true"
android:defaultValue="2" />
<Preference
android:key="logout"
android:title="@string/settings_logout_title"/>

View File

@@ -0,0 +1,12 @@
chore: i18n: Add Romanian translation (including locale_config this time!)
chore: French localization update
chore(i18n): Update Spanish translation
docs: updated readme and added known issues for airsonic work around
fix: toast for made for you click indication
fix: sort playlist view
feat: sort preference for playlists
fix: use existing future when adding tracks, dialed random album tracks off in instant mix
chore(i18n): Update Polish translation
fix: Check for OpenSubsonic extensions also with password authentication, addressing lyric sync
feat: Implement duration and seeking for transcodes
feat: Playback speed controls for music

View File

@@ -0,0 +1,3 @@
fix: Proper raw stream detection
chore(i18n): Update Spanish translation
feat: add configurable timeout

View File

@@ -0,0 +1,2 @@
fix: Avoid crash when server has no songs
fix: updated dialog import to address crashing on android 15