mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-27 08:57:44 +01:00
Updated Subsonic API version handling
This commit is contained in:
parent
0edaa29303
commit
ca2bfbf14b
@ -14,7 +14,7 @@ abstract class SubsonicAPIClientTest {
|
|||||||
protected lateinit var client: SubsonicAPIClient
|
protected lateinit var client: SubsonicAPIClient
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
open fun setUp() {
|
||||||
config = SubsonicClientConfiguration(
|
config = SubsonicClientConfiguration(
|
||||||
mockWebServerRule.mockWebServer.url("/").toString(),
|
mockWebServerRule.mockWebServer.url("/").toString(),
|
||||||
USERNAME,
|
USERNAME,
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package org.moire.ultrasonic.api.subsonic
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import okhttp3.mockwebserver.MockResponse
|
||||||
|
import org.amshove.kluent.`should be`
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration test for [VersionAwareJacksonConverterFactory].
|
||||||
|
*/
|
||||||
|
class VersionAwareJacksonConverterFactoryTest : SubsonicAPIClientTest() {
|
||||||
|
private val initialProtocolVersion = SubsonicAPIVersions.V1_1_0
|
||||||
|
private var updatedProtocolVersion = SubsonicAPIVersions.V1_1_0
|
||||||
|
|
||||||
|
@Before
|
||||||
|
override fun setUp() {
|
||||||
|
config = SubsonicClientConfiguration(
|
||||||
|
mockWebServerRule.mockWebServer.url("/").toString(),
|
||||||
|
USERNAME,
|
||||||
|
PASSWORD,
|
||||||
|
initialProtocolVersion,
|
||||||
|
CLIENT_ID
|
||||||
|
)
|
||||||
|
client = SubsonicAPIClient(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Should update version from response`() {
|
||||||
|
mockWebServerRule.enqueueResponse("ping_ok.json")
|
||||||
|
|
||||||
|
client.api.ping().execute()
|
||||||
|
|
||||||
|
client.protocolVersion.`should be`(SubsonicAPIVersions.V1_13_0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Should update version from response with utf-8 bom`() {
|
||||||
|
mockWebServerRule.enqueueResponse("ping_ok_utf8_bom.json")
|
||||||
|
|
||||||
|
client.api.ping().execute()
|
||||||
|
|
||||||
|
client.protocolVersion.`should be`(SubsonicAPIVersions.V1_16_0)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Should not update version if response json doesn't contain version`() {
|
||||||
|
mockWebServerRule.enqueueResponse("non_subsonic_response.json")
|
||||||
|
|
||||||
|
client.api.stream("1234").execute()
|
||||||
|
|
||||||
|
client.protocolVersion.`should be`(initialProtocolVersion)
|
||||||
|
}
|
||||||
|
}
|
@ -14,12 +14,9 @@ import org.moire.ultrasonic.api.subsonic.enqueueResponse
|
|||||||
*/
|
*/
|
||||||
class VersionInterceptorTest : BaseInterceptorTest() {
|
class VersionInterceptorTest : BaseInterceptorTest() {
|
||||||
private val initialProtocolVersion = SubsonicAPIVersions.V1_1_0
|
private val initialProtocolVersion = SubsonicAPIVersions.V1_1_0
|
||||||
private var updatedProtocolVersion = SubsonicAPIVersions.V1_1_0
|
|
||||||
|
|
||||||
override val interceptor: Interceptor by lazy(NONE) {
|
override val interceptor: Interceptor by lazy(NONE) {
|
||||||
VersionInterceptor(initialProtocolVersion) {
|
VersionInterceptor(initialProtocolVersion)
|
||||||
updatedProtocolVersion = it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -33,55 +30,4 @@ class VersionInterceptorTest : BaseInterceptorTest() {
|
|||||||
|
|
||||||
requestLine `should contain` "v=${initialProtocolVersion.restApiVersion}"
|
requestLine `should contain` "v=${initialProtocolVersion.restApiVersion}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Should update version from response`() {
|
|
||||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
|
||||||
|
|
||||||
client.newCall(createRequest {}).execute()
|
|
||||||
|
|
||||||
(interceptor as VersionInterceptor)
|
|
||||||
.protocolVersion `should equal` SubsonicAPIVersions.V1_13_0
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Should update version from response with utf-8 bom`() {
|
|
||||||
mockWebServerRule.enqueueResponse("ping_ok_utf8_bom.json")
|
|
||||||
|
|
||||||
client.newCall(createRequest {}).execute()
|
|
||||||
|
|
||||||
(interceptor as VersionInterceptor)
|
|
||||||
.protocolVersion `should equal` SubsonicAPIVersions.V1_16_0
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Should not update version if response json doesn't contain version`() {
|
|
||||||
mockWebServerRule.enqueueResponse("non_subsonic_response.json")
|
|
||||||
|
|
||||||
client.newCall(createRequest {}).execute()
|
|
||||||
|
|
||||||
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Should not update version on non-json response`() {
|
|
||||||
mockWebServerRule.mockWebServer.enqueue(
|
|
||||||
MockResponse()
|
|
||||||
.setBody("asdqwnekjnqwkjen")
|
|
||||||
.setHeader("Content-Type", "application/octet-stream")
|
|
||||||
)
|
|
||||||
|
|
||||||
client.newCall(createRequest {}).execute()
|
|
||||||
|
|
||||||
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `Should notify notifier on version change`() {
|
|
||||||
mockWebServerRule.enqueueResponse("ping_ok.json")
|
|
||||||
|
|
||||||
client.newCall(createRequest {}).execute()
|
|
||||||
|
|
||||||
updatedProtocolVersion `should equal` SubsonicAPIVersions.V1_13_0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,11 @@ import java.io.IOException
|
|||||||
* Special [IOException] to indicate that called api is not yet supported
|
* Special [IOException] to indicate that called api is not yet supported
|
||||||
* by current server api version.
|
* by current server api version.
|
||||||
*/
|
*/
|
||||||
class ApiNotSupportedException(
|
class ApiNotSupportedException : IOException {
|
||||||
serverApiVersion: SubsonicAPIVersions
|
val serverApiVersion: String
|
||||||
) : IOException("Server api $serverApiVersion does not support this call")
|
constructor(
|
||||||
|
apiVersion: SubsonicAPIVersions
|
||||||
|
) : super("Server api $apiVersion does not support this call") {
|
||||||
|
serverApiVersion = apiVersion.restApiVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,7 +21,6 @@ import org.moire.ultrasonic.api.subsonic.response.StreamResponse
|
|||||||
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse
|
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
import retrofit2.converter.jackson.JacksonConverterFactory
|
|
||||||
|
|
||||||
private const val READ_TIMEOUT = 60_000L
|
private const val READ_TIMEOUT = 60_000L
|
||||||
|
|
||||||
@ -39,9 +38,7 @@ class SubsonicAPIClient(
|
|||||||
config: SubsonicClientConfiguration,
|
config: SubsonicClientConfiguration,
|
||||||
baseOkClient: OkHttpClient = OkHttpClient.Builder().build()
|
baseOkClient: OkHttpClient = OkHttpClient.Builder().build()
|
||||||
) {
|
) {
|
||||||
private val versionInterceptor = VersionInterceptor(config.minimalProtocolVersion) {
|
private val versionInterceptor = VersionInterceptor(config.minimalProtocolVersion)
|
||||||
protocolVersion = it
|
|
||||||
}
|
|
||||||
|
|
||||||
private val proxyPasswordInterceptor = ProxyPasswordInterceptor(
|
private val proxyPasswordInterceptor = ProxyPasswordInterceptor(
|
||||||
config.minimalProtocolVersion,
|
config.minimalProtocolVersion,
|
||||||
@ -58,6 +55,7 @@ class SubsonicAPIClient(
|
|||||||
field = value
|
field = value
|
||||||
proxyPasswordInterceptor.apiVersion = field
|
proxyPasswordInterceptor.apiVersion = field
|
||||||
wrappedApi.currentApiVersion = field
|
wrappedApi.currentApiVersion = field
|
||||||
|
versionInterceptor.protocolVersion = field
|
||||||
}
|
}
|
||||||
|
|
||||||
private val okHttpClient = baseOkClient.newBuilder()
|
private val okHttpClient = baseOkClient.newBuilder()
|
||||||
@ -87,7 +85,12 @@ class SubsonicAPIClient(
|
|||||||
private val retrofit = Retrofit.Builder()
|
private val retrofit = Retrofit.Builder()
|
||||||
.baseUrl("${config.baseUrl}/rest/")
|
.baseUrl("${config.baseUrl}/rest/")
|
||||||
.client(okHttpClient)
|
.client(okHttpClient)
|
||||||
.addConverterFactory(JacksonConverterFactory.create(jacksonMapper))
|
.addConverterFactory(
|
||||||
|
VersionAwareJacksonConverterFactory.create(
|
||||||
|
{ protocolVersion = it },
|
||||||
|
jacksonMapper
|
||||||
|
)
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private val wrappedApi = ApiVersionCheckWrapper(
|
private val wrappedApi = ApiVersionCheckWrapper(
|
||||||
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.JsonParser
|
|||||||
import com.fasterxml.jackson.databind.DeserializationContext
|
import com.fasterxml.jackson.databind.DeserializationContext
|
||||||
import com.fasterxml.jackson.databind.JsonDeserializer
|
import com.fasterxml.jackson.databind.JsonDeserializer
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||||
|
import java.lang.NumberFormatException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subsonic REST API versions.
|
* Subsonic REST API versions.
|
||||||
@ -31,28 +32,45 @@ enum class SubsonicAPIVersions(val subsonicVersions: String, val restApiVersion:
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic @Throws(IllegalArgumentException::class)
|
@JvmStatic @Throws(IllegalArgumentException::class)
|
||||||
fun fromApiVersion(apiVersion: String): SubsonicAPIVersions {
|
fun getClosestKnownClientApiVersion(apiVersion: String): SubsonicAPIVersions {
|
||||||
when (apiVersion) {
|
val versionComponents = apiVersion.split(".")
|
||||||
"1.1.0" -> return V1_1_0
|
if (versionComponents.size < 2)
|
||||||
"1.1.1" -> return V1_1_1
|
throw IllegalArgumentException("Unknown api version $apiVersion")
|
||||||
"1.2.0" -> return V1_2_0
|
|
||||||
"1.3.0" -> return V1_3_0
|
try {
|
||||||
"1.4.0" -> return V1_4_0
|
val majorVersion = versionComponents[0].toInt()
|
||||||
"1.5.0" -> return V1_5_0
|
val minorVersion = versionComponents[1].toInt()
|
||||||
"1.6.0" -> return V1_6_0
|
val patchVersion = if (versionComponents.size > 2) versionComponents[2].toInt()
|
||||||
"1.7.0" -> return V1_7_0
|
else 0
|
||||||
"1.8.0" -> return V1_8_0
|
|
||||||
"1.9.0" -> return V1_9_0
|
when (majorVersion) {
|
||||||
"1.10.2" -> return V1_10_2
|
1 -> when {
|
||||||
"1.10.5" -> return V1_10_2 // Non standard version of Madsonic Server 5.1
|
minorVersion < 1 ->
|
||||||
"1.11.0" -> return V1_11_0
|
throw IllegalArgumentException("Unknown api version $apiVersion")
|
||||||
"1.12.0" -> return V1_12_0
|
minorVersion < 2 && patchVersion < 1 -> return V1_1_0
|
||||||
"1.13.0" -> return V1_13_0
|
minorVersion < 2 -> return V1_1_1
|
||||||
"1.14.0" -> return V1_14_0
|
minorVersion < 3 -> return V1_2_0
|
||||||
"1.15.0" -> return V1_15_0
|
minorVersion < 4 -> return V1_3_0
|
||||||
"1.16.0" -> return V1_16_0
|
minorVersion < 5 -> return V1_4_0
|
||||||
"1.16.1" -> return V1_16_0 // Fast and dirty fix to Subsonic 6.1.4
|
minorVersion < 6 -> return V1_5_0
|
||||||
else -> throw IllegalArgumentException("Unknown api version $apiVersion")
|
minorVersion < 7 -> return V1_6_0
|
||||||
|
minorVersion < 8 -> return V1_7_0
|
||||||
|
minorVersion < 9 -> return V1_8_0
|
||||||
|
minorVersion < 10 -> return V1_9_0
|
||||||
|
minorVersion < 11 -> return V1_10_2
|
||||||
|
minorVersion < 12 -> return V1_11_0
|
||||||
|
minorVersion < 13 -> return V1_12_0
|
||||||
|
minorVersion < 14 -> return V1_13_0
|
||||||
|
minorVersion < 15 -> return V1_14_0
|
||||||
|
minorVersion < 16 -> return V1_15_0
|
||||||
|
else -> return V1_16_0
|
||||||
|
}
|
||||||
|
// Subsonic API specifies that the client's and the server's major API version
|
||||||
|
// must be the same
|
||||||
|
else -> throw IllegalArgumentException("Unknown api version $apiVersion")
|
||||||
|
}
|
||||||
|
} catch (exception: NumberFormatException) {
|
||||||
|
throw IllegalArgumentException("Malformed api version $apiVersion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,7 +82,7 @@ enum class SubsonicAPIVersions(val subsonicVersions: String, val restApiVersion:
|
|||||||
if (p.currentName != "version") {
|
if (p.currentName != "version") {
|
||||||
throw JsonParseException(p, "Not valid token for API version!")
|
throw JsonParseException(p, "Not valid token for API version!")
|
||||||
}
|
}
|
||||||
return fromApiVersion(p.text)
|
return getClosestKnownClientApiVersion(p.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
package org.moire.ultrasonic.api.subsonic
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JavaType
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.databind.ObjectReader
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse
|
||||||
|
import retrofit2.Converter
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.jackson.JacksonConverterFactory
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrofit Converter Factory which uses Jackson for conversion and maintains the
|
||||||
|
* version of the Subsonic API.
|
||||||
|
* @param notifier: callback function to call when the Subsonic API version changes
|
||||||
|
*/
|
||||||
|
class VersionAwareJacksonConverterFactory(
|
||||||
|
private val notifier: (SubsonicAPIVersions) -> Unit = {}
|
||||||
|
) : Converter.Factory() {
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
notifier: (SubsonicAPIVersions) -> Unit = {},
|
||||||
|
mapper: ObjectMapper
|
||||||
|
) : this(notifier) {
|
||||||
|
this.mapper = mapper
|
||||||
|
jacksonConverterFactory = JacksonConverterFactory.create(mapper)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var mapper: ObjectMapper? = null
|
||||||
|
private var jacksonConverterFactory: JacksonConverterFactory? = null
|
||||||
|
|
||||||
|
override fun responseBodyConverter(
|
||||||
|
type: Type,
|
||||||
|
annotations: Array<Annotation>,
|
||||||
|
retrofit: Retrofit
|
||||||
|
): Converter<ResponseBody, *>? {
|
||||||
|
val javaType: JavaType = mapper!!.typeFactory.constructType(type)
|
||||||
|
val reader: ObjectReader? = mapper!!.readerFor(javaType)
|
||||||
|
return VersionAwareResponseBodyConverter<Any>(notifier, reader!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun requestBodyConverter(
|
||||||
|
type: Type,
|
||||||
|
parameterAnnotations: Array<Annotation>,
|
||||||
|
methodAnnotations: Array<Annotation>,
|
||||||
|
retrofit: Retrofit
|
||||||
|
): Converter<*, RequestBody>? {
|
||||||
|
return jacksonConverterFactory?.requestBodyConverter(
|
||||||
|
type, parameterAnnotations, methodAnnotations, retrofit
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmOverloads // Guarding public API nullability.
|
||||||
|
fun create(
|
||||||
|
notifier: (SubsonicAPIVersions) -> Unit = {},
|
||||||
|
mapper: ObjectMapper? = ObjectMapper()
|
||||||
|
): VersionAwareJacksonConverterFactory {
|
||||||
|
if (mapper == null) throw NullPointerException("mapper == null")
|
||||||
|
return VersionAwareJacksonConverterFactory(notifier, mapper)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class VersionAwareResponseBodyConverter<T> (
|
||||||
|
private val notifier: (SubsonicAPIVersions) -> Unit = {},
|
||||||
|
private val adapter: ObjectReader
|
||||||
|
) : Converter<ResponseBody, T> {
|
||||||
|
override fun convert(value: ResponseBody): T {
|
||||||
|
value.use {
|
||||||
|
// The response stream contains the version of the API for parsing the stream
|
||||||
|
// to an object. Currently the parsing is independent from the version as new
|
||||||
|
// versions only contain extra optional fields.
|
||||||
|
val response: T = adapter.readValue(value.charStream())
|
||||||
|
if (response is SubsonicResponse) {
|
||||||
|
try {
|
||||||
|
notifier(response.version)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,16 @@
|
|||||||
package org.moire.ultrasonic.api.subsonic.interceptors
|
package org.moire.ultrasonic.api.subsonic.interceptors
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonFactory
|
|
||||||
import com.fasterxml.jackson.core.JsonParseException
|
|
||||||
import com.fasterxml.jackson.core.JsonToken
|
|
||||||
import java.io.IOException
|
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Interceptor.Chain
|
import okhttp3.Interceptor.Chain
|
||||||
import okhttp3.Response
|
|
||||||
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
|
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
|
||||||
|
|
||||||
private const val DEFAULT_PEEK_BYTE_COUNT = 1000L
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Special [Interceptor] that adds client supported version to request and tries to update it
|
* Special [Interceptor] that adds client supported version to request
|
||||||
* from server response.
|
|
||||||
*
|
|
||||||
* Optionally [notifier] will be invoked on version change.
|
|
||||||
*
|
|
||||||
* @author Yahor Berdnikau
|
* @author Yahor Berdnikau
|
||||||
*/
|
*/
|
||||||
internal class VersionInterceptor(
|
internal class VersionInterceptor(
|
||||||
internal var protocolVersion: SubsonicAPIVersions,
|
internal var protocolVersion: SubsonicAPIVersions
|
||||||
private val notifier: (SubsonicAPIVersions) -> Unit = {}
|
|
||||||
) : Interceptor {
|
) : Interceptor {
|
||||||
private val jsonFactory = JsonFactory()
|
|
||||||
|
|
||||||
override fun intercept(chain: Chain): okhttp3.Response {
|
override fun intercept(chain: Chain): okhttp3.Response {
|
||||||
val originalRequest = chain.request()
|
val originalRequest = chain.request()
|
||||||
@ -38,44 +25,6 @@ internal class VersionInterceptor(
|
|||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
val response = chain.proceed(newRequest)
|
return chain.proceed(newRequest)
|
||||||
if (response.isSuccessful) {
|
|
||||||
val isJson = response.body()?.contentType()?.subtype()?.equals("json", true) ?: false
|
|
||||||
if (isJson) {
|
|
||||||
tryUpdateProtocolVersion(response)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tryUpdateProtocolVersion(response: Response) {
|
|
||||||
val content = response.peekBody(DEFAULT_PEEK_BYTE_COUNT).byteStream()
|
|
||||||
|
|
||||||
try {
|
|
||||||
val jsonReader = jsonFactory.createParser(content)
|
|
||||||
jsonReader.nextToken()
|
|
||||||
if (jsonReader.currentToken == JsonToken.START_OBJECT) {
|
|
||||||
while (
|
|
||||||
jsonReader.currentName != "version" &&
|
|
||||||
jsonReader.currentToken != null
|
|
||||||
) {
|
|
||||||
jsonReader.nextToken()
|
|
||||||
}
|
|
||||||
val versionStr = jsonReader.nextTextValue()
|
|
||||||
if (versionStr != null) {
|
|
||||||
try {
|
|
||||||
protocolVersion = SubsonicAPIVersions.fromApiVersion(versionStr)
|
|
||||||
notifier(protocolVersion)
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (io: IOException) {
|
|
||||||
// no-op
|
|
||||||
} catch (parse: JsonParseException) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,11 @@ class SubsonicAPIVersionsTest(private val apiVersion: SubsonicAPIVersions) {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Should proper convert api version to enum`() {
|
fun `Should proper convert api version to enum`() {
|
||||||
SubsonicAPIVersions.fromApiVersion(apiVersion.restApiVersion) `should equal` apiVersion
|
SubsonicAPIVersions.getClosestKnownClientApiVersion(apiVersion.restApiVersion) `should equal` apiVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
@Test(expected = IllegalArgumentException::class)
|
||||||
fun `Should throw IllegalArgumentException for unknown api version`() {
|
fun `Should throw IllegalArgumentException for unknown api version`() {
|
||||||
SubsonicAPIVersions.fromApiVersion(apiVersion.restApiVersion.substring(0, 2))
|
SubsonicAPIVersions.getClosestKnownClientApiVersion(apiVersion.restApiVersion.substring(0, 2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import android.os.Handler;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import com.fasterxml.jackson.core.JsonParseException;
|
import com.fasterxml.jackson.core.JsonParseException;
|
||||||
import org.moire.ultrasonic.R;
|
import org.moire.ultrasonic.R;
|
||||||
|
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException;
|
||||||
import org.moire.ultrasonic.service.SubsonicRESTException;
|
import org.moire.ultrasonic.service.SubsonicRESTException;
|
||||||
import org.moire.ultrasonic.subsonic.RestErrorMapper;
|
import org.moire.ultrasonic.subsonic.RestErrorMapper;
|
||||||
|
|
||||||
@ -86,7 +87,10 @@ public abstract class BackgroundTask<T> implements ProgressListener
|
|||||||
} else {
|
} else {
|
||||||
return activity.getResources().getString(R.string.background_task_ssl_error);
|
return activity.getResources().getString(R.string.background_task_ssl_error);
|
||||||
}
|
}
|
||||||
} else if (error instanceof IOException) {
|
} else if (error instanceof ApiNotSupportedException) {
|
||||||
|
return activity.getResources().getString(R.string.background_task_unsupported_api,
|
||||||
|
((ApiNotSupportedException) error).getServerApiVersion());
|
||||||
|
} else if (error instanceof IOException) {
|
||||||
return activity.getResources().getString(R.string.background_task_network_error);
|
return activity.getResources().getString(R.string.background_task_network_error);
|
||||||
} else if (error instanceof SubsonicRESTException) {
|
} else if (error instanceof SubsonicRESTException) {
|
||||||
return RestErrorMapper.getLocalizedErrorMessage((SubsonicRESTException) error, activity);
|
return RestErrorMapper.getLocalizedErrorMessage((SubsonicRESTException) error, activity);
|
||||||
|
@ -78,7 +78,7 @@ val musicServiceModule = module(MUSIC_SERVICE_CONTEXT) {
|
|||||||
baseUrl = "http://localhost",
|
baseUrl = "http://localhost",
|
||||||
username = "",
|
username = "",
|
||||||
password = "",
|
password = "",
|
||||||
minimalProtocolVersion = SubsonicAPIVersions.fromApiVersion(
|
minimalProtocolVersion = SubsonicAPIVersions.getClosestKnownClientApiVersion(
|
||||||
Constants.REST_PROTOCOL_VERSION
|
Constants.REST_PROTOCOL_VERSION
|
||||||
),
|
),
|
||||||
clientID = Constants.REST_CLIENT_ID,
|
clientID = Constants.REST_CLIENT_ID,
|
||||||
@ -91,7 +91,7 @@ val musicServiceModule = module(MUSIC_SERVICE_CONTEXT) {
|
|||||||
baseUrl = serverUrl,
|
baseUrl = serverUrl,
|
||||||
username = username,
|
username = username,
|
||||||
password = password,
|
password = password,
|
||||||
minimalProtocolVersion = SubsonicAPIVersions.fromApiVersion(
|
minimalProtocolVersion = SubsonicAPIVersions.getClosestKnownClientApiVersion(
|
||||||
Constants.REST_PROTOCOL_VERSION
|
Constants.REST_PROTOCOL_VERSION
|
||||||
),
|
),
|
||||||
clientID = Constants.REST_CLIENT_ID,
|
clientID = Constants.REST_CLIENT_ID,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Lade…</string>
|
<string name="background_task.loading">Lade…</string>
|
||||||
<string name="background_task.network_error">Ein Netzwerkfehler ist aufgetreten. Bitte die Serveradresse prüfen oder später noch einmal versuchen.</string>
|
<string name="background_task.network_error">Ein Netzwerkfehler ist aufgetreten. Bitte die Serveradresse prüfen oder später noch einmal versuchen.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Dieses Programm benötigt eine Netzwerkverbindung. Bitte das WLAN oder Mobilfunk einschalten.</string>
|
<string name="background_task.no_network">Dieses Programm benötigt eine Netzwerkverbindung. Bitte das WLAN oder Mobilfunk einschalten.</string>
|
||||||
<string name="background_task.not_found">Ressource nicht gefunden. Bitte die Serveradresse überprüfen.</string>
|
<string name="background_task.not_found">Ressource nicht gefunden. Bitte die Serveradresse überprüfen.</string>
|
||||||
<string name="background_task.parse_error">Antwort nicht verstanden. Bitte die Serveradresse überprüfen.</string>
|
<string name="background_task.parse_error">Antwort nicht verstanden. Bitte die Serveradresse überprüfen.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Cargando…</string>
|
<string name="background_task.loading">Cargando…</string>
|
||||||
<string name="background_task.network_error">Se ha producido un error de red. Por favor comprueba la dirección del servidor o reinténtalo mas tarde.</string>
|
<string name="background_task.network_error">Se ha producido un error de red. Por favor comprueba la dirección del servidor o reinténtalo mas tarde.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Este programa requiere acceso a la red. Por favor enciende la Wi-Fi o la red móvil.</string>
|
<string name="background_task.no_network">Este programa requiere acceso a la red. Por favor enciende la Wi-Fi o la red móvil.</string>
|
||||||
<string name="background_task.not_found">Recurso no encontrado. Por favor comprueba la dirección del servidor.</string>
|
<string name="background_task.not_found">Recurso no encontrado. Por favor comprueba la dirección del servidor.</string>
|
||||||
<string name="background_task.parse_error">No se entiende la respuesta. Por favor comprueba la dirección del servidor.</string>
|
<string name="background_task.parse_error">No se entiende la respuesta. Por favor comprueba la dirección del servidor.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Chargement…</string>
|
<string name="background_task.loading">Chargement…</string>
|
||||||
<string name="background_task.network_error">Une erreur réseau est survenue. Veuillez vérifier l\'adresse du serveur ou réessayer plus tard.</string>
|
<string name="background_task.network_error">Une erreur réseau est survenue. Veuillez vérifier l\'adresse du serveur ou réessayer plus tard.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Cette application requiert un accès au réseau. Veuillez activer le Wi-Fi ou le réseau mobile.</string>
|
<string name="background_task.no_network">Cette application requiert un accès au réseau. Veuillez activer le Wi-Fi ou le réseau mobile.</string>
|
||||||
<string name="background_task.not_found">Ressources introuvables. Veuillez vérifier l\'adresse du serveur.</string>
|
<string name="background_task.not_found">Ressources introuvables. Veuillez vérifier l\'adresse du serveur.</string>
|
||||||
<string name="background_task.parse_error">Réponse incorrecte. Veuillez vérifier l\'adresse du serveur.</string>
|
<string name="background_task.parse_error">Réponse incorrecte. Veuillez vérifier l\'adresse du serveur.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Betöltés…</string>
|
<string name="background_task.loading">Betöltés…</string>
|
||||||
<string name="background_task.network_error">Hálózati hiba történt! Kérjük, ellenőrizze a kiszolgáló címét vagy próbálja később!</string>
|
<string name="background_task.network_error">Hálózati hiba történt! Kérjük, ellenőrizze a kiszolgáló címét vagy próbálja később!</string>
|
||||||
|
<string name="background_task.unsupported_api">A v%1$s verziójú Szerver api nem támogatja ezt a funkciót.</string>
|
||||||
<string name="background_task.no_network">Az alkalmazás hálózati hozzáférést igényel. Kérjük, kapcsolja be a Wi-Fi-t vagy a mobilhálózatot!</string>
|
<string name="background_task.no_network">Az alkalmazás hálózati hozzáférést igényel. Kérjük, kapcsolja be a Wi-Fi-t vagy a mobilhálózatot!</string>
|
||||||
<string name="background_task.not_found">Az erőforrás nem található! Kérjük, ellenőrizze a kiszolgáló címét!</string>
|
<string name="background_task.not_found">Az erőforrás nem található! Kérjük, ellenőrizze a kiszolgáló címét!</string>
|
||||||
<string name="background_task.parse_error">Értelmezhetetlen válasz! Kérjük, ellenőrizze a kiszolgáló címét!</string>
|
<string name="background_task.parse_error">Értelmezhetetlen válasz! Kérjük, ellenőrizze a kiszolgáló címét!</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Bezig met laden…</string>
|
<string name="background_task.loading">Bezig met laden…</string>
|
||||||
<string name="background_task.network_error">Er is een netwerkfout opgetreden. Controleer het serveradres of probeer het later opnieuw.</string>
|
<string name="background_task.network_error">Er is een netwerkfout opgetreden. Controleer het serveradres of probeer het later opnieuw.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Deze app vereist netwerktoegang. Schakel Wi-Fi of mobiel internet in.</string>
|
<string name="background_task.no_network">Deze app vereist netwerktoegang. Schakel Wi-Fi of mobiel internet in.</string>
|
||||||
<string name="background_task.not_found">Bron niet gevonden. Controleer het serveradres.</string>
|
<string name="background_task.not_found">Bron niet gevonden. Controleer het serveradres.</string>
|
||||||
<string name="background_task.parse_error">Het antwoord werd niet begrepen. Controleer het serveradres.</string>
|
<string name="background_task.parse_error">Het antwoord werd niet begrepen. Controleer het serveradres.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Ładowanie…</string>
|
<string name="background_task.loading">Ładowanie…</string>
|
||||||
<string name="background_task.network_error">Wystąpił błąd sieci. Proszę sprawdzić adres serwera i spróbować później.</string>
|
<string name="background_task.network_error">Wystąpił błąd sieci. Proszę sprawdzić adres serwera i spróbować później.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Ta aplikacja wymaga dostępu do sieci. Proszę włączyć wi-fi lub dane komórkowe.</string>
|
<string name="background_task.no_network">Ta aplikacja wymaga dostępu do sieci. Proszę włączyć wi-fi lub dane komórkowe.</string>
|
||||||
<string name="background_task.not_found">Nie znaleziono zasobów. Proszę sprawdzić adres serwera.</string>
|
<string name="background_task.not_found">Nie znaleziono zasobów. Proszę sprawdzić adres serwera.</string>
|
||||||
<string name="background_task.parse_error">Brak prawidłowej odpowiedzi. Proszę sprawdzić adres serwera.</string>
|
<string name="background_task.parse_error">Brak prawidłowej odpowiedzi. Proszę sprawdzić adres serwera.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Carregando…</string>
|
<string name="background_task.loading">Carregando…</string>
|
||||||
<string name="background_task.network_error">Ocorreu um erro de rede. Verifique o endereço do servidor ou tente mais tarde.</string>
|
<string name="background_task.network_error">Ocorreu um erro de rede. Verifique o endereço do servidor ou tente mais tarde.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Este aplicativo requer acesso à rede. Ligue o Wi-Fi ou a rede de dados.</string>
|
<string name="background_task.no_network">Este aplicativo requer acesso à rede. Ligue o Wi-Fi ou a rede de dados.</string>
|
||||||
<string name="background_task.not_found">Recurso não encontrado. Verifique o endereço do servidor.</string>
|
<string name="background_task.not_found">Recurso não encontrado. Verifique o endereço do servidor.</string>
|
||||||
<string name="background_task.parse_error">Não entendi a resposta. Verifique o endereço do servidor.</string>
|
<string name="background_task.parse_error">Não entendi a resposta. Verifique o endereço do servidor.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Carregando…</string>
|
<string name="background_task.loading">Carregando…</string>
|
||||||
<string name="background_task.network_error">Ocorreu um erro de rede. Verifique o endereço do servidor ou tente mais tarde.</string>
|
<string name="background_task.network_error">Ocorreu um erro de rede. Verifique o endereço do servidor ou tente mais tarde.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">Este aplicativo requer acesso à rede. Ligue o Wi-Fi ou a rede de dados.</string>
|
<string name="background_task.no_network">Este aplicativo requer acesso à rede. Ligue o Wi-Fi ou a rede de dados.</string>
|
||||||
<string name="background_task.not_found">Recurso não encontrado. Verifique o endereço do servidor.</string>
|
<string name="background_task.not_found">Recurso não encontrado. Verifique o endereço do servidor.</string>
|
||||||
<string name="background_task.parse_error">Não entendi a resposta. Verifique o endereço do servidor.</string>
|
<string name="background_task.parse_error">Não entendi a resposta. Verifique o endereço do servidor.</string>
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
<string name="background_task.loading">Loading…</string>
|
<string name="background_task.loading">Loading…</string>
|
||||||
<string name="background_task.network_error">A network error occurred. Please check the server address or try again later.</string>
|
<string name="background_task.network_error">A network error occurred. Please check the server address or try again later.</string>
|
||||||
|
<string name="background_task.unsupported_api">Server api v%1$s does not support this function.</string>
|
||||||
<string name="background_task.no_network">This program requires network access. Please turn on Wi-Fi or mobile network.</string>
|
<string name="background_task.no_network">This program requires network access. Please turn on Wi-Fi or mobile network.</string>
|
||||||
<string name="background_task.not_found">Resource not found. Please check the server address.</string>
|
<string name="background_task.not_found">Resource not found. Please check the server address.</string>
|
||||||
<string name="background_task.parse_error">Didn\'t understand the reply. Please check the server address.</string>
|
<string name="background_task.parse_error">Didn\'t understand the reply. Please check the server address.</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user