diff --git a/app/src/main/java/com/cappielloantonio/tempo/repository/OpenRepository.java b/app/src/main/java/com/cappielloantonio/tempo/repository/OpenRepository.java new file mode 100644 index 00000000..86216034 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/repository/OpenRepository.java @@ -0,0 +1,37 @@ +package com.cappielloantonio.tempo.repository; + +import androidx.annotation.NonNull; +import androidx.lifecycle.MutableLiveData; + +import com.cappielloantonio.tempo.App; +import com.cappielloantonio.tempo.subsonic.base.ApiResponse; +import com.cappielloantonio.tempo.subsonic.models.LyricsList; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class OpenRepository { + public MutableLiveData getLyricsBySongId(String id) { + MutableLiveData lyricsList = new MutableLiveData<>(); + + App.getSubsonicClientInstance(false) + .getOpenClient() + .getLyricsBySongId(id) + .enqueue(new Callback() { + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getLyricsList() != null) { + lyricsList.setValue(response.body().getSubsonicResponse().getLyricsList()); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + + } + }); + + return lyricsList; + } +} diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/Subsonic.java b/app/src/main/java/com/cappielloantonio/tempo/subsonic/Subsonic.java index c401bca7..de4b36b7 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/Subsonic.java +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/Subsonic.java @@ -7,6 +7,7 @@ import com.cappielloantonio.tempo.subsonic.api.internetradio.InternetRadioClient import com.cappielloantonio.tempo.subsonic.api.mediaannotation.MediaAnnotationClient; import com.cappielloantonio.tempo.subsonic.api.medialibraryscanning.MediaLibraryScanningClient; import com.cappielloantonio.tempo.subsonic.api.mediaretrieval.MediaRetrievalClient; +import com.cappielloantonio.tempo.subsonic.api.open.OpenClient; import com.cappielloantonio.tempo.subsonic.api.playlist.PlaylistClient; import com.cappielloantonio.tempo.subsonic.api.podcast.PodcastClient; import com.cappielloantonio.tempo.subsonic.api.searching.SearchingClient; @@ -35,6 +36,7 @@ public class Subsonic { private BookmarksClient bookmarksClient; private InternetRadioClient internetRadioClient; private SharingClient sharingClient; + private OpenClient openClient; public Subsonic(SubsonicPreferences preferences) { this.preferences = preferences; @@ -128,6 +130,13 @@ public class Subsonic { return sharingClient; } + public OpenClient getOpenClient() { + if (openClient == null) { + openClient = new OpenClient(this); + } + return openClient; + } + public String getUrl() { String url = preferences.getServerUrl() + "/rest/"; return url.replace("//rest", "/rest"); diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenClient.java b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenClient.java new file mode 100644 index 00000000..b37b03bb --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenClient.java @@ -0,0 +1,26 @@ +package com.cappielloantonio.tempo.subsonic.api.open; + +import android.util.Log; + +import com.cappielloantonio.tempo.subsonic.RetrofitClient; +import com.cappielloantonio.tempo.subsonic.Subsonic; +import com.cappielloantonio.tempo.subsonic.base.ApiResponse; + +import retrofit2.Call; + +public class OpenClient { + private static final String TAG = "OpenClient"; + + private final Subsonic subsonic; + private final OpenService openService; + + public OpenClient(Subsonic subsonic) { + this.subsonic = subsonic; + this.openService = new RetrofitClient(subsonic).getRetrofit().create(OpenService.class); + } + + public Call getLyricsBySongId(String id) { + Log.d(TAG, "getLyricsBySongId()"); + return openService.getLyricsBySongId(subsonic.getParams(), id); + } +} diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenService.java b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenService.java new file mode 100644 index 00000000..3122a97c --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/api/open/OpenService.java @@ -0,0 +1,15 @@ +package com.cappielloantonio.tempo.subsonic.api.open; + +import com.cappielloantonio.tempo.subsonic.base.ApiResponse; + +import java.util.Map; + +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Query; +import retrofit2.http.QueryMap; + +public interface OpenService { + @GET("getLyricsBySongId") + Call getLyricsBySongId(@QueryMap Map params, @Query("id") String id); +} diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Line.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Line.kt new file mode 100644 index 00000000..1809091e --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Line.kt @@ -0,0 +1,9 @@ +package com.cappielloantonio.tempo.subsonic.models + +import androidx.annotation.Keep + +@Keep +class Line { + var start: Int? = null + lateinit var value: String +} \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/LyricsList.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/LyricsList.kt new file mode 100644 index 00000000..9c3b65e8 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/LyricsList.kt @@ -0,0 +1,8 @@ +package com.cappielloantonio.tempo.subsonic.models + +import androidx.annotation.Keep + +@Keep +class LyricsList { + var structuredLyrics: List? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/OpenSubsonicExtension.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/OpenSubsonicExtension.kt new file mode 100644 index 00000000..dd170c83 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/OpenSubsonicExtension.kt @@ -0,0 +1,9 @@ +package com.cappielloantonio.tempo.subsonic.models + +import androidx.annotation.Keep + +@Keep +class OpenSubsonicExtension { + var name: String? = null + var versions: List? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/StructuredLyrics.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/StructuredLyrics.kt new file mode 100644 index 00000000..d77b2e03 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/StructuredLyrics.kt @@ -0,0 +1,13 @@ +package com.cappielloantonio.tempo.subsonic.models + +import androidx.annotation.Keep + +@Keep +class StructuredLyrics { + var displayArtist: String? = null + var displayTitle: String? = null + var lang: String? = null + var offset: Int = 0 + var synced: Boolean = false + var line: List? = null +} \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/SubsonicResponse.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/SubsonicResponse.kt index 6a43c2da..f886f55c 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/SubsonicResponse.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/SubsonicResponse.kt @@ -51,4 +51,7 @@ class SubsonicResponse { var version: String? = null var type: String? = null var serverVersion: String? = null + var openSubsonic: Boolean? = null + var openSubsonicExtensions: List? = null + var lyricsList: LyricsList? = null } \ No newline at end of file diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/OpenSubsonicExtensionsUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/OpenSubsonicExtensionsUtil.java new file mode 100644 index 00000000..78c59fb9 --- /dev/null +++ b/app/src/main/java/com/cappielloantonio/tempo/util/OpenSubsonicExtensionsUtil.java @@ -0,0 +1,41 @@ +package com.cappielloantonio.tempo.util; + +import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; + +import java.util.List; + +public class OpenSubsonicExtensionsUtil { + private static List getOpenSubsonicExtensions() { + List extensions = null; + + if (Preferences.isOpenSubsonic() && Preferences.getOpenSubsonicExtensions() != null) { + extensions = new Gson().fromJson( + Preferences.getOpenSubsonicExtensions(), + new TypeToken>() { + }.getType() + ); + } + + return extensions; + } + + private static OpenSubsonicExtension getOpenSubsonicExtension(String extensionName) { + if (getOpenSubsonicExtensions() == null) return null; + + return getOpenSubsonicExtensions().stream().filter(openSubsonicExtension -> openSubsonicExtension.getName().equals(extensionName)).findAny().orElse(null); + } + + public static boolean isTranscodeOffsetExtensionAvailable() { + return getOpenSubsonicExtension("transcodeOffset") != null; + } + + public static boolean isFormPostExtensionAvailable() { + return getOpenSubsonicExtension("formPost") != null; + } + + public static boolean isSongLyricsExtensionAvailable() { + return getOpenSubsonicExtension("songLyrics") != null; + } +} diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt index 71c031ff..718fba28 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/util/Preferences.kt @@ -1,6 +1,11 @@ package com.cappielloantonio.tempo.util import com.cappielloantonio.tempo.App +import com.cappielloantonio.tempo.subsonic.models.OpenSubsonicExtension +import com.google.gson.Gson + + + object Preferences { const val THEME = "theme" @@ -12,6 +17,8 @@ object Preferences { private const val LOW_SECURITY = "low_security" private const val BATTERY_OPTIMIZATION = "battery_optimization" private const val SERVER_ID = "server_id" + private const val OPEN_SUBSONIC = "open_subsonic" + private const val OPEN_SUBSONIC_EXTENSIONS = "open_subsonic_extensions" private const val PLAYBACK_SPEED = "playback_speed" private const val SKIP_SILENCE = "skip_silence" private const val IMAGE_CACHE_SIZE = "image_cache_size" @@ -119,6 +126,26 @@ object Preferences { App.getInstance().preferences.edit().putString(SERVER_ID, serverId).apply() } + @JvmStatic + fun isOpenSubsonic(): Boolean { + return App.getInstance().preferences.getBoolean(OPEN_SUBSONIC, false) + } + + @JvmStatic + fun setOpenSubsonic(isOpenSubsonic: Boolean) { + App.getInstance().preferences.edit().putBoolean(OPEN_SUBSONIC, isOpenSubsonic).apply() + } + + @JvmStatic + fun getOpenSubsonicExtensions(): String? { + return App.getInstance().preferences.getString(OPEN_SUBSONIC_EXTENSIONS, null) + } + + @JvmStatic + fun setOpenSubsonicExtensions(extension: List) { + App.getInstance().preferences.edit().putString(OPEN_SUBSONIC_EXTENSIONS, Gson().toJson(extension)).apply() + } + @JvmStatic fun askForOptimization(): Boolean { return App.getInstance().preferences.getBoolean(BATTERY_OPTIMIZATION, true)