mirror of
https://github.com/memen45/SubMusic.git
synced 2026-02-18 00:57:39 +01:00
fixed response checking (rare crash on some metadata)
improved error reporting added support for forerunner 945 LTE
This commit is contained in:
@@ -2,6 +2,11 @@ Version [] -
|
||||
- (future) added 'Manage...' option for more playlist options
|
||||
- (future) added alpha podcast implementation (feedback needed)
|
||||
|
||||
Version [0.1.10] - 2021-06-23
|
||||
- fixed response checking (rare crash on some metadata)
|
||||
- improved error reporting
|
||||
- added support for forerunner 945 LTE
|
||||
|
||||
Version [0.1.9] - 2021-06-02
|
||||
- fixed support for venu2s (Garmin bug with loading resource strings)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- This is a generated file. It is highly recommended that you DO NOT edit this file. --><iq:manifest xmlns:iq="http://www.garmin.com/xml/connectiq" version="3">
|
||||
<iq:application entry="SubMusicApp" id="62436b93f69e4823a8b41854b6684b4a" launcherIcon="@Drawables.LauncherIcon" name="@Strings.AppName" type="audio-content-provider-app" version="0.1.9">
|
||||
<iq:application entry="SubMusicApp" id="62436b93f69e4823a8b41854b6684b4a" launcherIcon="@Drawables.LauncherIcon" name="@Strings.AppName" type="audio-content-provider-app" version="0.1.10">
|
||||
<iq:products>
|
||||
<iq:product id="d2air"/>
|
||||
<iq:product id="d2delta"/>
|
||||
@@ -17,6 +17,7 @@
|
||||
<iq:product id="fr645m"/>
|
||||
<iq:product id="fr745"/>
|
||||
<iq:product id="fr945"/>
|
||||
<iq:product id="fr945lte"/>
|
||||
<iq:product id="legacyherocaptainmarvel"/>
|
||||
<iq:product id="legacyherofirstavenger"/>
|
||||
<iq:product id="legacysagadarthvader"/>
|
||||
|
||||
@@ -3,6 +3,7 @@ using Toybox.Cryptography;
|
||||
using Toybox.StringUtil;
|
||||
using Toybox.Communications;
|
||||
using Toybox.Lang;
|
||||
using Toybox.Media;
|
||||
|
||||
class AmpacheAPI extends Api {
|
||||
|
||||
@@ -66,7 +67,7 @@ class AmpacheAPI extends Api {
|
||||
System.println("AmpacheAPI::onHandshake with responseCode " + responseCode + " payload " + data);
|
||||
|
||||
// errors are filtered first
|
||||
var error = checkDictionaryResponse(responseCode, data);
|
||||
var error = Api.checkDictionaryResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
@@ -170,7 +171,7 @@ class AmpacheAPI extends Api {
|
||||
:mediaEncoding => encoding,
|
||||
:fileDownloadProgressCallback => method(:onProgress),
|
||||
};
|
||||
Communications.makeWebRequest(url(), params, options, self.method(:onStream));
|
||||
Communications.makeWebRequest(url(), params, options, self.method(:onContentResponse));
|
||||
}
|
||||
|
||||
function get_art(callback, params) {
|
||||
@@ -192,23 +193,23 @@ class AmpacheAPI extends Api {
|
||||
Communications.makeImageRequest(url(), params, options, self.method(:onGet_art));
|
||||
}
|
||||
|
||||
function onStream(responseCode, data) {
|
||||
System.println("AmpacheAPI::onStream with responseCode: " + responseCode);
|
||||
// function onStream(responseCode, data) {
|
||||
// System.println("AmpacheAPI::onStream with responseCode: " + responseCode);
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
}
|
||||
d_callback.invoke(data.getId());
|
||||
}
|
||||
// // check if request was successful and response is ok
|
||||
// var error = checkResponse(responseCode, data);
|
||||
// if (error) {
|
||||
// d_fallback.invoke(error);
|
||||
// return;
|
||||
// }
|
||||
// d_callback.invoke(data.getId());
|
||||
// }
|
||||
|
||||
function onGet_art(responseCode, data) {
|
||||
System.println("AmpacheAPI::onGet_art with responseCode: " + responseCode + " and " + data);
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkImageResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
@@ -236,7 +237,7 @@ class AmpacheAPI extends Api {
|
||||
System.println("AmpacheAPI::onArrayResponse with responseCode: " + responseCode + ", payload " + data);
|
||||
|
||||
// errors are filtered first
|
||||
var error = checkArrayResponse(responseCode, data);
|
||||
var error = Api.checkArrayResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
@@ -244,14 +245,14 @@ class AmpacheAPI extends Api {
|
||||
d_callback.invoke(data);
|
||||
}
|
||||
|
||||
function checkArrayResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
// function checkArrayResponse(responseCode, data) {
|
||||
// var error = checkResponse(responseCode, data);
|
||||
// if (error) { return error; }
|
||||
|
||||
// finally, expecting array
|
||||
if (!(data instanceof Lang.Array)) { return new AmpacheError(null); }
|
||||
return null;
|
||||
}
|
||||
// // finally, expecting array
|
||||
// if (!(data instanceof Lang.Array)) { return new AmpacheError(null); }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/*
|
||||
* onDictionaryResponse
|
||||
@@ -262,34 +263,60 @@ class AmpacheAPI extends Api {
|
||||
System.println("AmpacheAPI::onDictionaryResponse with responseCode " + responseCode + " payload " + data);
|
||||
|
||||
// errors are filtered first
|
||||
var error = checkDictionaryResponse(responseCode, data);
|
||||
var error = Api.checkDictionaryResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
}
|
||||
|
||||
d_callback.invoke(data);
|
||||
}
|
||||
|
||||
function checkDictionaryResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
// function checkDictionaryResponse(responseCode, data) {
|
||||
// var error = checkResponse(responseCode, data);
|
||||
// if (error) { return error; }
|
||||
|
||||
// finally, expecting Dictionary
|
||||
if (!(data instanceof Lang.Dictionary)) { return new AmpacheError(null); }
|
||||
return null;
|
||||
}
|
||||
// // finally, expecting Dictionary
|
||||
// if (!(data instanceof Lang.Dictionary)) { return new AmpacheError(null); }
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/*
|
||||
* checkResponse
|
||||
* onContentResponse
|
||||
*
|
||||
* returns response / api errors if found
|
||||
* Default handler for actions that return a ContentRef
|
||||
*/
|
||||
function checkResponse(responseCode, data) {
|
||||
var error = Api.checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
function onContentResponse(responseCode, data) {
|
||||
System.println("AmpacheAPI::onContentResponse with responseCode " + responseCode + " payload " + data);
|
||||
|
||||
// errors are filtered first
|
||||
var error = Api.checkContentResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
}
|
||||
d_callback.invoke(data);
|
||||
}
|
||||
|
||||
// /*
|
||||
// * checkResponse
|
||||
// *
|
||||
// * returns response / api errors if found
|
||||
// */
|
||||
// function checkResponse(responseCode, data) {
|
||||
// var error = Api.checkResponse(responseCode, data);
|
||||
// if (error) { return error; }
|
||||
// return AmpacheError.is(responseCode, data);
|
||||
// }
|
||||
|
||||
/*
|
||||
* @override Api.checkApiError
|
||||
*
|
||||
* returns ampache api error if found (used from base class Api)
|
||||
*/
|
||||
function checkApiError(responseCode, data) {
|
||||
return AmpacheError.is(responseCode, data);
|
||||
}
|
||||
|
||||
|
||||
// converts rfc3339 formatted timestamp to Time::Moment (null on error)
|
||||
function parseISODate(date) {
|
||||
@@ -406,6 +433,7 @@ class AmpacheAPI extends Api {
|
||||
}
|
||||
|
||||
function deleteSession() {
|
||||
System.println("AmpacheAPI::deleteSession()");
|
||||
// reset the session
|
||||
d_expire = new Time.Moment(0);
|
||||
Application.Storage.deleteValue("AMPACHE_API_SESSION");
|
||||
|
||||
@@ -13,7 +13,7 @@ class AmpacheError extends SubMusic.ApiError {
|
||||
// BAD_REQUEST = 4710,
|
||||
// FAILED_ACCESS = 4742,
|
||||
// }
|
||||
enum {
|
||||
static enum {
|
||||
ACCESS_CONTROL = 400,
|
||||
HANDSHAKE = 401,
|
||||
FEATURE_MISSING = 403,
|
||||
@@ -23,16 +23,16 @@ class AmpacheError extends SubMusic.ApiError {
|
||||
BAD_REQUEST = 410,
|
||||
FAILED_ACCESS = 442,
|
||||
}
|
||||
private var d_code = null;
|
||||
private var d_type = null;
|
||||
private var d_msg = "";
|
||||
|
||||
static private var s_name = "Ampache";
|
||||
static private var s_name = "AmpacheError";
|
||||
|
||||
function initialize(error_obj) {
|
||||
|
||||
// if null error_obj, response is malformed
|
||||
if (error_obj) {
|
||||
d_code = error_obj["code"];
|
||||
d_type = error_obj["code"].toNumber();
|
||||
d_msg = error_obj["message"];
|
||||
// TODO for Ampache 5:
|
||||
// d_code = error_obj["errorCode"]; // Ampache5
|
||||
@@ -40,32 +40,37 @@ class AmpacheError extends SubMusic.ApiError {
|
||||
}
|
||||
|
||||
// default is unknown
|
||||
var type = SubMusic.ApiError.UNKNOWN;
|
||||
if (d_code == HANDSHAKE) {
|
||||
type = SubMusic.ApiError.LOGIN;
|
||||
} else if (d_code == FAILED_ACCESS) {
|
||||
type = SubMusic.ApiError.ACCESS;
|
||||
} else if (d_code == NOT_FOUND) {
|
||||
type = SubMusic.ApiError.NOTFOUND;
|
||||
} else if ((d_code == ACCESS_CONTROL) || (d_code == FEATURE_MISSING) || (d_code == METHOD_MISSING) || (d_code == METHOD_DPRCTD)) {
|
||||
type = SubMusic.ApiError.SERVERCLIENT;
|
||||
} else if (d_code == BAD_REQUEST) {
|
||||
type = SubMusic.ApiError.BADREQUEST;
|
||||
var apitype = SubMusic.ApiError.UNKNOWN;
|
||||
if (d_type == HANDSHAKE) {
|
||||
apitype= SubMusic.ApiError.LOGIN;
|
||||
} else if (d_type == FAILED_ACCESS) {
|
||||
apitype= SubMusic.ApiError.ACCESS;
|
||||
} else if (d_type == NOT_FOUND) {
|
||||
apitype = SubMusic.ApiError.NOTFOUND;
|
||||
} else if ((d_type == ACCESS_CONTROL) || (d_type == FEATURE_MISSING) || (d_type == METHOD_MISSING) || (d_type == METHOD_DPRCTD)) {
|
||||
apitype = SubMusic.ApiError.SERVERCLIENT;
|
||||
} else if (d_type == BAD_REQUEST) {
|
||||
apitype = SubMusic.ApiError.BADREQUEST;
|
||||
}
|
||||
|
||||
SubMusic.ApiError.initialize(type);
|
||||
SubMusic.ApiError.initialize(apitype);
|
||||
|
||||
System.println(s_name + "::" + AmpacheError.typeToString(d_type));
|
||||
}
|
||||
|
||||
|
||||
function shortString() {
|
||||
return SubMusic.ApiError.shortString() + " " + d_code;
|
||||
return s_name + "::" + d_type;
|
||||
}
|
||||
|
||||
|
||||
function toString() {
|
||||
return d_msg;
|
||||
return SubMusic.ApiError.toString() +
|
||||
" --> " +
|
||||
s_name + "::" + AmpacheError.typeToString(d_type) +
|
||||
": " + d_msg;
|
||||
}
|
||||
|
||||
function code() {
|
||||
return d_code;
|
||||
function type() {
|
||||
return d_type;
|
||||
}
|
||||
|
||||
static function is(responseCode, data) {
|
||||
@@ -78,4 +83,25 @@ class AmpacheError extends SubMusic.ApiError {
|
||||
}
|
||||
return new AmpacheError(data["error"]);
|
||||
}
|
||||
|
||||
static function typeToString(type) {
|
||||
if (type == ACCESS_CONTROL) {
|
||||
return "ACCESS_CONTROL";
|
||||
} else if (type == HANDSHAKE) {
|
||||
return "HANDSHAKE";
|
||||
} else if (type == FEATURE_MISSING) {
|
||||
return "FEATURE_MISSING";
|
||||
} else if (type == NOT_FOUND) {
|
||||
return "NOT_FOUND";
|
||||
} else if (type == METHOD_MISSING) {
|
||||
return "METHOD_MISSING";
|
||||
} else if (type == METHOD_DPRCTD) {
|
||||
return "METHOD_DPRCTD";
|
||||
} else if (type == BAD_REQUEST) {
|
||||
return "BAD_REQUEST";
|
||||
} else if (type == FAILED_ACCESS) {
|
||||
return "FAILED_ACCESS";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
@@ -264,9 +264,9 @@ class AmpacheProvider {
|
||||
do_();
|
||||
}
|
||||
|
||||
function on_do_stream(refId) {
|
||||
function on_do_stream(contentRef) {
|
||||
d_action = null;
|
||||
d_callback.invoke(refId);
|
||||
d_callback.invoke(contentRef.getId());
|
||||
}
|
||||
|
||||
function on_do_get_art(artwork) {
|
||||
@@ -325,7 +325,7 @@ class AmpacheProvider {
|
||||
|
||||
// if handshake error on otherwise valid session, delete session and retry handshake
|
||||
if ((error instanceof AmpacheError)
|
||||
&& (error.code() == AmpacheError.HANDSHAKE)
|
||||
&& (error.type() == AmpacheError.HANDSHAKE)
|
||||
&& d_api.session(null)) {
|
||||
|
||||
d_api.deleteSession();
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
using Toybox.Lang;
|
||||
using Toybox.Media;
|
||||
using Toybox.System;
|
||||
using Toybox.WatchUi;
|
||||
using SubMusic;
|
||||
|
||||
class Api {
|
||||
|
||||
private var d_client; // the client name
|
||||
@@ -61,10 +67,53 @@ class Api {
|
||||
*
|
||||
* returns http/sdk errors if found
|
||||
*/
|
||||
static function checkResponse(responseCode, data) {
|
||||
function checkResponse(responseCode, data) {
|
||||
var error = SubMusic.HttpError.is(responseCode);
|
||||
if (error) { return error; }
|
||||
return SubMusic.GarminSdkError.is(responseCode);
|
||||
error = SubMusic.GarminSdkError.is(responseCode);
|
||||
if (error) { return error; }
|
||||
return self.checkApiError(responseCode, data);
|
||||
}
|
||||
|
||||
function checkApiError(responseCode, data) {
|
||||
System.println("WARNING: Api::checkApiError() was called, but should not be called");
|
||||
return null;
|
||||
}
|
||||
|
||||
function checkDictionaryResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
|
||||
// check type of received object
|
||||
if (data instanceof Lang.Dictionary) { return null; }
|
||||
return new SubMusic.ApiError(SubMusic.ApiError.BADRESPONSE);
|
||||
}
|
||||
|
||||
function checkArrayResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
|
||||
// check type of received object
|
||||
if (data instanceof Lang.Array) { return null; }
|
||||
return new SubMusic.ApiError(SubMusic.ApiError.BADRESPONSE);
|
||||
}
|
||||
|
||||
function checkContentResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
|
||||
// check type of received object
|
||||
if (data instanceof Media.ContentRef) { return null; }
|
||||
return new SubMusic.ApiError(SubMusic.ApiError.BADRESPONSE);
|
||||
}
|
||||
|
||||
function checkImageResponse(responseCode, data) {
|
||||
var error = checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
|
||||
// check type of received object
|
||||
if (data instanceof WatchUi.BitmapResource) { return null; }
|
||||
return new SubMusic.ApiError(SubMusic.ApiError.BADRESPONSE);
|
||||
}
|
||||
|
||||
function onProgress(totalBytesTransferred, fileSize) {
|
||||
|
||||
@@ -52,7 +52,7 @@ class SubsonicAPI extends Api {
|
||||
System.println("SubsonicAPI::onResponse( responseCode: " + responseCode + ", data: " + data + ")");
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkDictionaryResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error); // add function name and variables available ?
|
||||
return;
|
||||
@@ -78,7 +78,7 @@ class SubsonicAPI extends Api {
|
||||
System.println("SubsonicAPI::onGetPlaylists( responseCode: " + responseCode + ", data: " + data + ")");
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkDictionaryResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error); // add function name and variables available ?
|
||||
return;
|
||||
@@ -123,7 +123,7 @@ class SubsonicAPI extends Api {
|
||||
System.println("Subsonic::onGetPlaylist(responseCode: " + responseCode + ", data: " + data);
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkDictionaryResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error); // add function name and variables available ?
|
||||
return;
|
||||
@@ -163,12 +163,12 @@ class SubsonicAPI extends Api {
|
||||
System.println("SubsonicAPI::onStream with responseCode: " + responseCode);
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkContentResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
}
|
||||
d_callback.invoke(data.getId());
|
||||
d_callback.invoke(data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,17 +204,23 @@ class SubsonicAPI extends Api {
|
||||
System.println("SubsonicAPI::onGetCoverArt with responseCode: " + responseCode + " and " + data);
|
||||
|
||||
// check if request was successful and response is ok
|
||||
var error = checkResponse(responseCode, data);
|
||||
// var error = checkResponse(responseCode, data);
|
||||
var error = Api.checkImageResponse(responseCode, data);
|
||||
if (error) {
|
||||
d_fallback.invoke(error);
|
||||
d_fallback.invoke(error);
|
||||
return;
|
||||
}
|
||||
d_callback.invoke(data);
|
||||
}
|
||||
|
||||
function checkResponse(responseCode, data) {
|
||||
var error = Api.checkResponse(responseCode, data);
|
||||
if (error) { return error; }
|
||||
// function checkResponse(responseCode, data) {
|
||||
// var error = Api.checkResponse(responseCode, data);
|
||||
// if (error) { return error; }
|
||||
// return SubsonicError.is(responseCode, data);
|
||||
// }
|
||||
|
||||
// @override
|
||||
function checkApiError(responseCode, data) {
|
||||
return SubsonicError.is(responseCode, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using Toybox.Lang;
|
||||
|
||||
class SubsonicError extends SubMusic.ApiError {
|
||||
|
||||
enum {
|
||||
static enum {
|
||||
GENERIC = 0, // 0 A generic error.
|
||||
MISSING_PARAM = 10, // 10 Required parameter is missing.
|
||||
INCOMPAT_CLIENT = 20, // 20 Incompatible Subsonic REST protocol version. Client must upgrade.
|
||||
@@ -14,46 +14,51 @@ class SubsonicError extends SubMusic.ApiError {
|
||||
TRIAL_OVER = 60, // 60 The trial period for the Subsonic server is over. Please upgrade to Subsonic Premium. Visit subsonic.org for details.
|
||||
NOT_FOUND = 70, // 70 The requested data was not found.
|
||||
}
|
||||
private var d_code = null;
|
||||
private var d_type = null;
|
||||
private var d_msg = "";
|
||||
|
||||
static private var s_name = "Subsonic";
|
||||
static private var s_name = "SubsonicError";
|
||||
|
||||
function initialize(error_obj) {
|
||||
|
||||
// if null error_obj, response is malformed
|
||||
if (error_obj) {
|
||||
d_code = error_obj["code"];
|
||||
d_type = error_obj["code"];
|
||||
d_msg = error_obj["message"];
|
||||
}
|
||||
|
||||
// default is unknown
|
||||
var type = SubMusic.ApiError.UNKNOWN;
|
||||
if ((d_code == WRONG_CREDS) || (d_code == TOKEN_SUPPORT) || (d_code == TRIAL_OVER)) {
|
||||
type = SubMusic.ApiError.LOGIN;
|
||||
} else if (d_code == NOT_AUTHORIZED) {
|
||||
type = SubMusic.ApiError.ACCESS;
|
||||
} else if (d_code == NOT_FOUND) {
|
||||
type = SubMusic.ApiError.NOTFOUND;
|
||||
} else if ((d_code == INCOMPAT_CLIENT) || (d_code == INCOMPAT_SERVER)) {
|
||||
type = SubMusic.ApiError.SERVERCLIENT;
|
||||
} else if (d_code == MISSING_PARAM) {
|
||||
type = SubMusic.ApiError.BADREQUEST;
|
||||
var apitype = SubMusic.ApiError.UNKNOWN;
|
||||
if ((d_type == WRONG_CREDS) || (d_type == TOKEN_SUPPORT) || (d_type == TRIAL_OVER)) {
|
||||
apitype = SubMusic.ApiError.LOGIN;
|
||||
} else if (d_type == NOT_AUTHORIZED) {
|
||||
apitype = SubMusic.ApiError.ACCESS;
|
||||
} else if (d_type == NOT_FOUND) {
|
||||
apitype = SubMusic.ApiError.NOTFOUND;
|
||||
} else if ((d_type == INCOMPAT_CLIENT) || (d_type == INCOMPAT_SERVER)) {
|
||||
apitype = SubMusic.ApiError.SERVERCLIENT;
|
||||
} else if (d_type == MISSING_PARAM) {
|
||||
apitype = SubMusic.ApiError.BADREQUEST;
|
||||
}
|
||||
|
||||
SubMusic.ApiError.initialize(type);
|
||||
SubMusic.ApiError.initialize(apitype);
|
||||
|
||||
System.println(s_name + "::" + SubsonicError.typeToString(d_type));
|
||||
}
|
||||
|
||||
function shortString() {
|
||||
return SubMusic.ApiError.shortString() + " " + d_code;
|
||||
return s_name + "::" + d_type;
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return d_msg;
|
||||
return SubMusic.ApiError.toString() +
|
||||
" --> " +
|
||||
s_name + "::" + SubsonicError.typeToString(d_type) +
|
||||
": " + d_msg;
|
||||
}
|
||||
|
||||
function code() {
|
||||
return d_code;
|
||||
function type() {
|
||||
return d_type;
|
||||
}
|
||||
|
||||
static function is(responseCode, data) {
|
||||
@@ -70,4 +75,27 @@ class SubsonicError extends SubMusic.ApiError {
|
||||
}
|
||||
return new SubsonicError(data["subsonic-response"]["error"]);
|
||||
}
|
||||
|
||||
static function typeToString(type) {
|
||||
if (type == GENERIC) {
|
||||
return "GENERIC";
|
||||
} else if (type == MISSING_PARAM) {
|
||||
return "MISSING_PARAM";
|
||||
} else if (type == INCOMPAT_CLIENT) {
|
||||
return "INCOMPAT_CLIENT";
|
||||
} else if (type == INCOMPAT_SERVER) {
|
||||
return "INCOMPAT_SERVER";
|
||||
} else if (type == WRONG_CREDS) {
|
||||
return "WRONG_CREDS";
|
||||
} else if (type == TOKEN_SUPPORT) {
|
||||
return "TOKEN_SUPPORT";
|
||||
} else if (type == NOT_AUTHORIZED) {
|
||||
return "NOT_AUTHORIZED";
|
||||
} else if (type == TRIAL_OVER) {
|
||||
return "TRIAL_OVER";
|
||||
} else if (type == NOT_FOUND) {
|
||||
return "NOT_FOUND";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
@@ -209,8 +209,8 @@ class SubsonicProvider {
|
||||
d_callback.invoke(songs);
|
||||
}
|
||||
|
||||
function onStream(refId) {
|
||||
d_callback.invoke(refId);
|
||||
function onStream(contentRef) {
|
||||
d_callback.invoke(contentRef.getId());
|
||||
}
|
||||
|
||||
function onGetCoverArt(artwork) {
|
||||
|
||||
@@ -143,7 +143,7 @@ class PlaylistSync extends Deferrable {
|
||||
}
|
||||
|
||||
function onError(error) {
|
||||
System.println("PlaylistSync::onError(" + error.shortString() + ")");
|
||||
System.println("PlaylistSync::onError(" + error.shortString() + " : " + error.toString() + ")");
|
||||
|
||||
// indicate failed sync
|
||||
// d_playlist.setError(error); TODO
|
||||
@@ -165,15 +165,27 @@ class PlaylistSync extends Deferrable {
|
||||
d_playlist.setSynced(!d_failed);
|
||||
|
||||
// update playlist info if not found
|
||||
if ((error instanceof SubMusic.ApiError)
|
||||
&& (error.type() == SubMusic.ApiError.NOTFOUND)) {
|
||||
d_playlist.setRemote(false);
|
||||
Deferrable.complete();
|
||||
return;
|
||||
}
|
||||
|
||||
// other errors will break the sync by default
|
||||
Deferrable.cancel(error);
|
||||
return;
|
||||
// if ((error instanceof SubMusic.ApiError)
|
||||
// && (error.type() == SubMusic.ApiError.NOTFOUND)) {
|
||||
// d_playlist.setRemote(false);
|
||||
// Deferrable.complete();
|
||||
// return;
|
||||
// }
|
||||
if (!(error instanceof SubMusic.ApiError)) {
|
||||
|
||||
// other errors will break the sync by default
|
||||
Deferrable.cancel(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var apiError as SubMusic.ApiError = error;
|
||||
if (apiError.api_type() == SubMusic.ApiError.NOTFOUND) {
|
||||
d_playlist.setRemote(false);
|
||||
Deferrable.complete();
|
||||
return;
|
||||
}
|
||||
|
||||
Deferrable.cancel(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
using Toybox.Communications;
|
||||
|
||||
module SubMusic {
|
||||
|
||||
class Error {
|
||||
enum {
|
||||
static enum {
|
||||
HTTP,
|
||||
API,
|
||||
}
|
||||
static private var s_name = "Error";
|
||||
private var d_type;
|
||||
|
||||
function initialize(type) {
|
||||
System.println(s_name + "::" + Error.typeToString(type));
|
||||
d_type = type;
|
||||
}
|
||||
|
||||
@@ -16,17 +20,26 @@ module SubMusic {
|
||||
}
|
||||
|
||||
function shortString() {
|
||||
return "Error";
|
||||
return s_name + " " + Error.typeToString(d_type);
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return "";
|
||||
return s_name + " " + Error.typeToString(d_type);
|
||||
}
|
||||
|
||||
static function typeToString(type) {
|
||||
if (type == HTTP) {
|
||||
return "HTTP";
|
||||
} else if (type == API) {
|
||||
return "API";
|
||||
}
|
||||
return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
class ApiError extends Error {
|
||||
|
||||
enum {
|
||||
static enum {
|
||||
LOGIN,
|
||||
ACCESS,
|
||||
NOTFOUND,
|
||||
@@ -36,23 +49,35 @@ module SubMusic {
|
||||
UNKNOWN,
|
||||
}
|
||||
private var d_type;
|
||||
static private var s_name = "API";
|
||||
static private var s_name = "ApiError";
|
||||
|
||||
function initialize(type) {
|
||||
Error.initialize(Error.API);
|
||||
|
||||
System.println(s_name + "::" + ApiError.typeToString(type));
|
||||
|
||||
d_type = type;
|
||||
}
|
||||
|
||||
function shortString() {
|
||||
return "API::" + typeToString(d_type) + " " + Error.shortString();
|
||||
return s_name + "::" + ApiError.typeToString(d_type);
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return SubMusic.Error.toString() +
|
||||
" --> " +
|
||||
s_name + "::" + ApiError.typeToString(d_type);
|
||||
}
|
||||
|
||||
function type() {
|
||||
return d_type;
|
||||
}
|
||||
|
||||
function api_type() {
|
||||
return ApiError.type();
|
||||
}
|
||||
|
||||
function typeToString(type) {
|
||||
static function typeToString(type) {
|
||||
|
||||
if (type == LOGIN) {
|
||||
return "\"LOGIN\"";
|
||||
@@ -69,23 +94,24 @@ module SubMusic {
|
||||
} else if (type == UNKNOWN) {
|
||||
return "\"UNKNOWN\"";
|
||||
}
|
||||
return "Unknown";
|
||||
return "Unknown ApiError";
|
||||
}
|
||||
}
|
||||
|
||||
class HttpError extends Error {
|
||||
|
||||
enum {
|
||||
static enum {
|
||||
BAD_REQUEST = 400,
|
||||
NOT_FOUND = 404,
|
||||
}
|
||||
private var d_type;
|
||||
static private var s_name = "HTTP";
|
||||
static private var s_name = "HttpError";
|
||||
|
||||
function initialize(type) {
|
||||
Error.initialize(Error.HTTP);
|
||||
|
||||
d_type = type;
|
||||
|
||||
System.println(HttpError.toString());
|
||||
}
|
||||
|
||||
static function is(responseCode) {
|
||||
@@ -99,17 +125,23 @@ module SubMusic {
|
||||
}
|
||||
|
||||
function shortString() {
|
||||
return Error.shortString() + "::" + s_name + "::" + d_type.toString();
|
||||
return s_name + "::" + d_type.toString();
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return Error.toString() +
|
||||
" --> " +
|
||||
s_name + "::" + HttpError.typeToString(d_type);
|
||||
}
|
||||
|
||||
function toString() {
|
||||
static function typeToString(type) {
|
||||
|
||||
if (d_type == BAD_REQUEST) {
|
||||
if (type == BAD_REQUEST) {
|
||||
return "BAD_REQUEST";
|
||||
} else if (d_type == NOT_FOUND) {
|
||||
} else if (type == NOT_FOUND) {
|
||||
return "NOT_FOUND";
|
||||
}
|
||||
return "Unknown";
|
||||
return "Unknown HttpError";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,11 +149,13 @@ module SubMusic {
|
||||
|
||||
// enum for possible errors can be found in module Communications
|
||||
private var d_responseCode;
|
||||
static private var s_name = "GarminSdkError";
|
||||
|
||||
function initialize(responseCode) {
|
||||
Error.initialize(Error.HTTP);
|
||||
|
||||
d_responseCode = responseCode;
|
||||
|
||||
System.println(GarminSdkError.toString());
|
||||
}
|
||||
|
||||
static function is(responseCode) {
|
||||
@@ -139,15 +173,17 @@ module SubMusic {
|
||||
}
|
||||
|
||||
function shortString() {
|
||||
return d_responseCode.toString();
|
||||
return s_name + "::" + d_responseCode.toString();
|
||||
}
|
||||
|
||||
function toString() {
|
||||
return respCodeToString(d_responseCode);
|
||||
return Error.toString() +
|
||||
" --> " +
|
||||
s_name + "::" + GarminSdkError.respCodeToString(d_responseCode);
|
||||
}
|
||||
|
||||
// move to somewhere else later, but now this is one of the two places this is used
|
||||
function respCodeToString(responseCode) {
|
||||
static function respCodeToString(responseCode) {
|
||||
if (responseCode == Communications.UNKNOWN_ERROR) {
|
||||
return "\"UNKNOWN_ERROR\"";
|
||||
} else if (responseCode == Communications.BLE_ERROR) {
|
||||
@@ -188,8 +224,20 @@ module SubMusic {
|
||||
return "\"STORAGE_FULL\"";
|
||||
} else if (responseCode == Communications.SECURE_CONNECTION_REQUIRED) {
|
||||
return "\"SECURE_CONNECTION_REQUIRED\"";
|
||||
} else if (responseCode == Communications.UNSUPPORTED_CONTENT_TYPE_IN_RESPONSE) {
|
||||
return "\"UNSUPPORTED_CONTENT_TYPE_IN_RESPONSE\"";
|
||||
} else if (responseCode == Communications.REQUEST_CANCELLED) {
|
||||
return "\"REQUEST_CANCELLED\"";
|
||||
} else if (responseCode == Communications.REQUEST_CONNECTION_DROPPED) {
|
||||
return "\"REQUEST_CONNECTION_DROPPED\"";
|
||||
} else if (responseCode == Communications.UNABLE_TO_PROCESS_MEDIA) {
|
||||
return "\"UNABLE_TO_PROCESS_MEDIA\"";
|
||||
} else if (responseCode == Communications.UNABLE_TO_PROCESS_IMAGE) {
|
||||
return "\"UNABLE_TO_PROCESS_IMAGE\"";
|
||||
} else if (responseCode == Communications.UNABLE_TO_PROCESS_HLS) {
|
||||
return "\"UNABLE_TO_PROCESS_HLS\"";
|
||||
}
|
||||
return "Unknown";
|
||||
return "Unknown GarminSdkError";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ class SubMusicVersion {
|
||||
|
||||
private var d_major = 0;
|
||||
private var d_minor = 1;
|
||||
private var d_patch = 9;
|
||||
private var d_name = "juliett";
|
||||
private var d_patch = 10;
|
||||
private var d_name = "kilo";
|
||||
|
||||
function initialize(storage) {
|
||||
if (storage == null) {
|
||||
|
||||
Reference in New Issue
Block a user