Fix api error parses always in generic error.
Now it parses to right error representation. Also fix that right exception for error is not thrown on api call. Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
This commit is contained in:
parent
fa03cf3881
commit
3e1dbe3476
|
@ -59,14 +59,14 @@ fun parseDate(dateAsString: String): Calendar {
|
|||
|
||||
fun <T : SubsonicResponse> checkErrorCallParsed(mockWebServerRule: MockWebServerRule,
|
||||
apiRequest: () -> Response<T>): T {
|
||||
mockWebServerRule.enqueueResponse("generic_error_response.json")
|
||||
mockWebServerRule.enqueueResponse("request_data_not_found_error_response.json")
|
||||
|
||||
val response = apiRequest()
|
||||
|
||||
assertResponseSuccessful(response)
|
||||
with(response.body()) {
|
||||
status `should be` SubsonicResponse.Status.ERROR
|
||||
error `should be` SubsonicError.GENERIC
|
||||
error `should be` SubsonicError.RequestedDataWasNotFound
|
||||
}
|
||||
return response.body()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package org.moire.ultrasonic.api.subsonic
|
||||
|
||||
import org.amshove.kluent.`should equal`
|
||||
import org.amshove.kluent.`should not be`
|
||||
import org.amshove.kluent.`should throw`
|
||||
import org.junit.Test
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.Generic
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.WrongUsernameOrPassword
|
||||
import org.moire.ultrasonic.api.subsonic.response.SubsonicResponse
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Integration test that checks validity of api errors parsing.
|
||||
*/
|
||||
class SubsonicApiErrorsTest : SubsonicAPIClientTest() {
|
||||
@Test
|
||||
fun `Should parse wrong username or password error`() {
|
||||
mockWebServerRule.enqueueResponse("wrong_username_or_password_error.json")
|
||||
|
||||
val response = client.api.ping().execute()
|
||||
|
||||
response.assertError(WrongUsernameOrPassword)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should parse generic error with message`() {
|
||||
mockWebServerRule.enqueueResponse("generic_error.json")
|
||||
|
||||
val response = client.api.ping().execute()
|
||||
|
||||
response.assertError(Generic("Some generic error message."))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should fail on unknown error`() {
|
||||
mockWebServerRule.enqueueResponse("unexpected_error.json")
|
||||
|
||||
val fail = {
|
||||
client.api.ping().execute()
|
||||
}
|
||||
|
||||
fail `should throw` IOException::class
|
||||
}
|
||||
|
||||
private fun Response<SubsonicResponse>.assertError(expectedError: SubsonicError) =
|
||||
with(body()) {
|
||||
error `should not be` null
|
||||
error `should equal` expectedError
|
||||
}
|
||||
}
|
|
@ -13,14 +13,14 @@ import org.junit.Test
|
|||
class SubsonicApiGetAvatarTest : SubsonicAPIClientTest() {
|
||||
@Test
|
||||
fun `Should handle api error response`() {
|
||||
mockWebServerRule.enqueueResponse("generic_error_response.json")
|
||||
mockWebServerRule.enqueueResponse("request_data_not_found_error_response.json")
|
||||
|
||||
val response = client.getAvatar("some")
|
||||
|
||||
with(response) {
|
||||
stream `should be` null
|
||||
responseHttpCode `should equal to` 200
|
||||
apiError `should equal` SubsonicError.GENERIC
|
||||
apiError `should equal` SubsonicError.RequestedDataWasNotFound
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,14 @@ import org.junit.Test
|
|||
class SubsonicApiGetCoverArtTest : SubsonicAPIClientTest() {
|
||||
@Test
|
||||
fun `Should handle api error response`() {
|
||||
mockWebServerRule.enqueueResponse("generic_error_response.json")
|
||||
mockWebServerRule.enqueueResponse("request_data_not_found_error_response.json")
|
||||
|
||||
val response = client.getCoverArt("some-id")
|
||||
|
||||
with(response) {
|
||||
stream `should be` null
|
||||
responseHttpCode `should equal to` 200
|
||||
apiError `should equal` SubsonicError.GENERIC
|
||||
apiError `should equal` SubsonicError.RequestedDataWasNotFound
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,14 @@ import org.junit.Test
|
|||
class SubsonicApiStreamTest : SubsonicAPIClientTest() {
|
||||
@Test
|
||||
fun `Should handle api error response`() {
|
||||
mockWebServerRule.enqueueResponse("generic_error_response.json")
|
||||
mockWebServerRule.enqueueResponse("request_data_not_found_error_response.json")
|
||||
|
||||
val response = client.stream("some-id")
|
||||
|
||||
with(response) {
|
||||
stream `should be` null
|
||||
responseHttpCode `should equal to` 200
|
||||
apiError `should equal` SubsonicError.GENERIC
|
||||
apiError `should equal` SubsonicError.RequestedDataWasNotFound
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"subsonic-response": {
|
||||
"status": "failed",
|
||||
"version": "1.15.0",
|
||||
"error": {
|
||||
"code": 0,
|
||||
"message": "Some generic error message."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
"status" : "failed",
|
||||
"version" : "1.13.0",
|
||||
"error" : {
|
||||
"code" : 0,
|
||||
"message" : "Generic error."
|
||||
"code" : 70,
|
||||
"message" : "Requested data was not found."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"subsonic-response": {
|
||||
"status": "failed",
|
||||
"version": "1.15.0",
|
||||
"error": {
|
||||
"code": 1000000,
|
||||
"message": "New funky error message."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"subsonic-response": {
|
||||
"status": "failed",
|
||||
"version": "1.15.0",
|
||||
"error": {
|
||||
"code": 40,
|
||||
"message": "Wrong username or password."
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,29 +9,41 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
|||
* Common API errors.
|
||||
*/
|
||||
@JsonDeserialize(using = SubsonicError.Companion.SubsonicErrorDeserializer::class)
|
||||
enum class SubsonicError(val code: Int) {
|
||||
GENERIC(0),
|
||||
REQUIRED_PARAM_MISSING(10),
|
||||
INCOMPATIBLE_CLIENT_PROTOCOL_VERSION(20),
|
||||
INCOMPATIBLE_SERVER_PROTOCOL_VERSION(30),
|
||||
WRONG_USERNAME_OR_PASSWORD(40),
|
||||
TOKEN_AUTH_NOT_SUPPORTED_FOR_LDAP(41),
|
||||
USER_NOT_AUTHORIZED_FOR_OPERATION(50),
|
||||
TRIAL_PERIOD_IS_OVER(60),
|
||||
REQUESTED_DATA_WAS_NOT_FOUND(70);
|
||||
sealed class SubsonicError(val code: Int) {
|
||||
data class Generic(val message: String) : SubsonicError(0)
|
||||
object RequiredParamMissing : SubsonicError(10)
|
||||
object IncompatibleClientProtocolVersion : SubsonicError(20)
|
||||
object IncompatibleServerProtocolVersion : SubsonicError(30)
|
||||
object WrongUsernameOrPassword : SubsonicError(40)
|
||||
object TokenAuthNotSupportedForLDAP : SubsonicError(41)
|
||||
object UserNotAuthorizedForOperation : SubsonicError(50)
|
||||
object TrialPeriodIsOver : SubsonicError(60)
|
||||
object RequestedDataWasNotFound : SubsonicError(70)
|
||||
|
||||
companion object {
|
||||
fun parseErrorFromJson(jsonErrorCode: Int) = SubsonicError.values()
|
||||
.filter { it.code == jsonErrorCode }.firstOrNull()
|
||||
?: throw IllegalArgumentException("Unknown code $jsonErrorCode")
|
||||
fun getError(code: Int, message: String) = when (code) {
|
||||
0 -> Generic(message)
|
||||
10 -> RequiredParamMissing
|
||||
20 -> IncompatibleClientProtocolVersion
|
||||
30 -> IncompatibleServerProtocolVersion
|
||||
40 -> WrongUsernameOrPassword
|
||||
41 -> TokenAuthNotSupportedForLDAP
|
||||
50 -> UserNotAuthorizedForOperation
|
||||
60 -> TrialPeriodIsOver
|
||||
70 -> RequestedDataWasNotFound
|
||||
else -> throw IllegalArgumentException("Unknown code $code")
|
||||
}
|
||||
|
||||
class SubsonicErrorDeserializer : JsonDeserializer<SubsonicError>() {
|
||||
override fun deserialize(p: JsonParser, ctxt: DeserializationContext?): SubsonicError {
|
||||
p.nextToken() // "code"
|
||||
val error = parseErrorFromJson(p.valueAsInt)
|
||||
p.nextToken() // "message"
|
||||
p.nextToken() // end of error object
|
||||
return error
|
||||
p.nextToken() // { -> "code"
|
||||
p.nextToken() // "code" -> codeValue
|
||||
val code = p.valueAsInt
|
||||
p.nextToken() // codeValue -> "message"
|
||||
p.nextToken() // "message" -> messageValue
|
||||
val message = p.text
|
||||
p.nextToken() // value -> }
|
||||
return getError(code, message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package org.moire.ultrasonic.api.subsonic
|
||||
|
||||
import org.amshove.kluent.`should equal`
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.Parameterized
|
||||
|
||||
/**
|
||||
* Unit test for [SubsonicError].
|
||||
*/
|
||||
@RunWith(Parameterized::class)
|
||||
class SubsonicErrorTest(private val error: SubsonicError) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@Parameterized.Parameters
|
||||
fun data(): List<SubsonicError> = SubsonicError.values().toList()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should proper convert error code to error`() {
|
||||
SubsonicError.parseErrorFromJson(error.code) `should equal` error
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun `Should throw IllegalArgumentException from unknown error code`() {
|
||||
SubsonicError.parseErrorFromJson(error.code + 10000)
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package org.moire.ultrasonic.api.subsonic.response
|
|||
|
||||
import org.amshove.kluent.`should equal to`
|
||||
import org.junit.Test
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.GENERIC
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.RequestedDataWasNotFound
|
||||
|
||||
/**
|
||||
* Unit test for [StreamResponse].
|
||||
|
@ -10,7 +10,8 @@ import org.moire.ultrasonic.api.subsonic.SubsonicError.GENERIC
|
|||
class StreamResponseTest {
|
||||
@Test
|
||||
fun `Should have error if subsonic error is not null`() {
|
||||
StreamResponse(apiError = GENERIC, responseHttpCode = 200).hasError() `should equal to` true
|
||||
StreamResponse(apiError = RequestedDataWasNotFound, responseHttpCode = 200)
|
||||
.hasError() `should equal to` true
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.moire.ultrasonic.R;
|
|||
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException;
|
||||
import org.moire.ultrasonic.domain.JukeboxStatus;
|
||||
import org.moire.ultrasonic.domain.PlayerState;
|
||||
import org.moire.ultrasonic.service.parser.SubsonicRESTException;
|
||||
import org.moire.ultrasonic.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
|
@ -89,7 +89,6 @@ import org.moire.ultrasonic.domain.SearchCriteria;
|
|||
import org.moire.ultrasonic.domain.SearchResult;
|
||||
import org.moire.ultrasonic.domain.Share;
|
||||
import org.moire.ultrasonic.domain.UserInfo;
|
||||
import org.moire.ultrasonic.service.parser.SubsonicRESTException;
|
||||
import org.moire.ultrasonic.util.CancellableTask;
|
||||
import org.moire.ultrasonic.util.FileUtil;
|
||||
import org.moire.ultrasonic.util.ProgressListener;
|
||||
|
@ -1077,7 +1076,7 @@ public class RESTMusicService implements MusicService {
|
|||
}
|
||||
|
||||
private void checkResponseSuccessful(@NonNull final Response<? extends SubsonicResponse> response)
|
||||
throws IOException {
|
||||
throws SubsonicRESTException, IOException {
|
||||
if (response.isSuccessful() &&
|
||||
response.body().getStatus() == SubsonicResponse.Status.OK) {
|
||||
return;
|
||||
|
@ -1087,7 +1086,7 @@ public class RESTMusicService implements MusicService {
|
|||
throw new IOException("Server error, code: " + response.code());
|
||||
} else if (response.body().getStatus() == SubsonicResponse.Status.ERROR &&
|
||||
response.body().getError() != null) {
|
||||
throw new IOException("Server error: " + response.body().getError().getCode());
|
||||
throw new SubsonicRESTException(response.body().getError());
|
||||
} else {
|
||||
throw new IOException("Failed to perform request: " + response.code());
|
||||
}
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package org.moire.ultrasonic.service.parser;
|
||||
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError;
|
||||
|
||||
/**
|
||||
* Exception returned by API with given {@code code}.
|
||||
*
|
||||
* @author Sindre Mehus
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SubsonicRESTException extends Exception {
|
||||
private final SubsonicError error;
|
||||
|
||||
public SubsonicRESTException(final SubsonicError error) {
|
||||
super("Api error: " + error.name());
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public int getCode()
|
||||
{
|
||||
return error.getCode();
|
||||
}
|
||||
|
||||
public SubsonicError getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import android.util.Log;
|
|||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
|
||||
import org.moire.ultrasonic.R;
|
||||
import org.moire.ultrasonic.service.parser.SubsonicRESTException;
|
||||
import org.moire.ultrasonic.service.SubsonicRESTException;
|
||||
import org.moire.ultrasonic.subsonic.RestErrorMapper;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package org.moire.ultrasonic.service
|
||||
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError
|
||||
|
||||
/**
|
||||
* Exception returned by API with given `code`.
|
||||
*/
|
||||
class SubsonicRESTException(val error: SubsonicError) : Exception("Api error: ${error.code}") {
|
||||
val code: Int get() = error.code
|
||||
}
|
|
@ -3,16 +3,16 @@ package org.moire.ultrasonic.subsonic
|
|||
|
||||
import android.content.Context
|
||||
import org.moire.ultrasonic.R
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.GENERIC
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.INCOMPATIBLE_CLIENT_PROTOCOL_VERSION
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.INCOMPATIBLE_SERVER_PROTOCOL_VERSION
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.REQUESTED_DATA_WAS_NOT_FOUND
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.REQUIRED_PARAM_MISSING
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.TOKEN_AUTH_NOT_SUPPORTED_FOR_LDAP
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.TRIAL_PERIOD_IS_OVER
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.USER_NOT_AUTHORIZED_FOR_OPERATION
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.WRONG_USERNAME_OR_PASSWORD
|
||||
import org.moire.ultrasonic.service.parser.SubsonicRESTException
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.Generic
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.IncompatibleClientProtocolVersion
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.IncompatibleServerProtocolVersion
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.RequestedDataWasNotFound
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.RequiredParamMissing
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.TokenAuthNotSupportedForLDAP
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.TrialPeriodIsOver
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.UserNotAuthorizedForOperation
|
||||
import org.moire.ultrasonic.api.subsonic.SubsonicError.WrongUsernameOrPassword
|
||||
import org.moire.ultrasonic.service.SubsonicRESTException
|
||||
|
||||
/**
|
||||
* Extension for [SubsonicRESTException] that returns localized error string, that can used to
|
||||
|
@ -20,19 +20,19 @@ import org.moire.ultrasonic.service.parser.SubsonicRESTException
|
|||
*/
|
||||
fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String =
|
||||
when (error) {
|
||||
GENERIC -> context.getString(R.string.api_subsonic_generic, message)
|
||||
REQUIRED_PARAM_MISSING -> context.getString(R.string.api_subsonic_param_missing)
|
||||
INCOMPATIBLE_CLIENT_PROTOCOL_VERSION -> context
|
||||
is Generic -> context
|
||||
.getString(R.string.api_subsonic_generic, (error as Generic).message)
|
||||
RequiredParamMissing -> context.getString(R.string.api_subsonic_param_missing)
|
||||
IncompatibleClientProtocolVersion -> context
|
||||
.getString(R.string.api_subsonic_upgrade_client)
|
||||
INCOMPATIBLE_SERVER_PROTOCOL_VERSION -> context
|
||||
IncompatibleServerProtocolVersion -> context
|
||||
.getString(R.string.api_subsonic_upgrade_server)
|
||||
WRONG_USERNAME_OR_PASSWORD -> context.getString(R.string.api_subsonic_not_authenticated)
|
||||
TOKEN_AUTH_NOT_SUPPORTED_FOR_LDAP -> context
|
||||
WrongUsernameOrPassword -> context.getString(R.string.api_subsonic_not_authenticated)
|
||||
TokenAuthNotSupportedForLDAP -> context
|
||||
.getString(R.string.api_subsonic_token_auth_not_supported_for_ldap)
|
||||
USER_NOT_AUTHORIZED_FOR_OPERATION -> context
|
||||
UserNotAuthorizedForOperation -> context
|
||||
.getString(R.string.api_subsonic_not_authorized)
|
||||
TRIAL_PERIOD_IS_OVER -> context.getString(R.string.api_subsonic_trial_period_is_over)
|
||||
REQUESTED_DATA_WAS_NOT_FOUND -> context
|
||||
TrialPeriodIsOver -> context.getString(R.string.api_subsonic_trial_period_is_over)
|
||||
RequestedDataWasNotFound -> context
|
||||
.getString(R.string.api_subsonic_requested_data_was_not_found)
|
||||
else -> context.getString(R.string.api_subsonic_unknown_api_error)
|
||||
}
|
||||
|
|
|
@ -430,7 +430,6 @@
|
|||
<string name="api.subsonic.param_missing">Falta el parámetro requerido.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">No se encontraron los datos solicitados.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">El período de prueba ha terminado.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Error de api desconocido.</string>
|
||||
<string name="api.subsonic.upgrade_client">Versiones incompatibles. Por favor actualiza la aplicación de Android UltraSonic.</string>
|
||||
<string name="api.subsonic.upgrade_server">Versiones incompatibles. Por favor actualiza el servidor de Subsonic.</string>
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@
|
|||
<string name="api.subsonic.param_missing">Param nécessaire manquant.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">Les données demandées n\'ont pas été trouvées.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">La période d\'essai est terminée.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Erreur d\'api inconnue.</string>
|
||||
<string name="api.subsonic.upgrade_client">Versions incompatible. Veuillez mette à jour l\'application Android UltraSonic.</string>
|
||||
<string name="api.subsonic.upgrade_server">Versions incompatible. Veuillez mette à jour le serveur Subsonic.</string>
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@
|
|||
<string name="api.subsonic.param_missing">A szükséges param hiányzik.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">A keresett adatokat nem találtuk.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">A próbaidő vége.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Ismeretlen api hiba.</string>
|
||||
<string name="api.subsonic.upgrade_client">Nem kompatibilis verzió. Kérjük, frissítse az UltraSonic Android alkalmazást!</string>
|
||||
<string name="api.subsonic.upgrade_server">Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót!</string>
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@
|
|||
<string name="api.subsonic.param_missing">O parâmetro requerido está faltando.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">Os dados solicitados não foram encontrados.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Erro de api desconhecido.</string>
|
||||
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
||||
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
||||
|
||||
|
|
|
@ -430,7 +430,6 @@
|
|||
<string name="api.subsonic.param_missing">O parâmetro requerido está faltando.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">Os dados solicitados não foram encontrados.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">O período de avaliação acabou.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Erro de api desconhecido.</string>
|
||||
<string name="api.subsonic.upgrade_client">Versões incompativeis. Atualize o aplicativo UltraSonic para Android.</string>
|
||||
<string name="api.subsonic.upgrade_server">Versões incompativeis. Atualize o servidor UltraSonic.</string>
|
||||
|
||||
|
|
|
@ -432,7 +432,6 @@
|
|||
<string name="api.subsonic.param_missing">Required param is missing.</string>
|
||||
<string name="api.subsonic.requested_data_was_not_found">Requested data was not found.</string>
|
||||
<string name="api.subsonic.trial_period_is_over">Trial period is over.</string>
|
||||
<string name="api.subsonic.unknown_api_error">Unknown api error.</string>
|
||||
<string name="api.subsonic.upgrade_client">Incompatible versions. Please upgrade UltraSonic Android app.</string>
|
||||
<string name="api.subsonic.upgrade_server">Incompatible versions. Please upgrade Subsonic server.</string>
|
||||
|
||||
|
|
Loading…
Reference in New Issue