1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-02-03 02:27:31 +01:00

Merge pull request #25 from ultrasonic/use-get-artists

Use getArtists new api implementation call
This commit is contained in:
Yahor Berdnikau 2017-08-16 07:42:51 +02:00 committed by GitHub
commit 6b8d953751
8 changed files with 159 additions and 189 deletions

View File

@ -164,17 +164,18 @@ class SubsonicAPIClientTest {
lastModified `should equal` 1491069027523 lastModified `should equal` 1491069027523
ignoredArticles `should equal` "The El La Los Las Le Les" ignoredArticles `should equal` "The El La Los Las Le Les"
shortcutList `should equal` listOf( shortcutList `should equal` listOf(
Artist(889L, "podcasts", null), Artist(id = 889L, name = "podcasts"),
Artist(890L, "audiobooks", null) Artist(id = 890L, name = "audiobooks")
) )
indexList `should equal` mutableListOf( indexList `should equal` mutableListOf(
Index("A", listOf( Index("A", listOf(
Artist(50L, "Ace Of Base", parseDate("2017-04-02T20:16:29.815Z")), Artist(id = 50L, name = "Ace Of Base",
Artist(379L, "A Perfect Circle", null) starred = parseDate("2017-04-02T20:16:29.815Z")),
Artist(id = 379L, name = "A Perfect Circle")
)), )),
Index("H", listOf( Index("H", listOf(
Artist(299, "Haddaway", null), Artist(id = 299, name = "Haddaway"),
Artist(297, "Halestorm", null) Artist(id = 297, name = "Halestorm")
)) ))
) )
} }
@ -271,6 +272,55 @@ class SubsonicAPIClientTest {
} }
} }
@Test
fun `Should parse get artists error response`() {
val response = checkErrorCallParsed { client.api.getArtists(null).execute() }
response.indexes `should not be` null
with(response.indexes) {
lastModified `should equal to` 0
ignoredArticles `should equal to` ""
indexList.size `should equal to` 0
shortcutList.size `should equal to` 0
}
}
@Test
fun `Should parse get artists ok reponse`() {
enqueueResponse("get_artists_ok.json")
val response = client.api.getArtists(null).execute()
assertResponseSuccessful(response)
with(response.body().indexes) {
lastModified `should equal to` 0L
ignoredArticles `should equal to` "The El La Los Las Le Les"
shortcutList `should equal` emptyList()
indexList.size `should equal to` 2
indexList `should equal` listOf(
Index(name = "A", artists = listOf(
Artist(id = 362L, name = "AC/DC", coverArt = "ar-362", albumCount = 2),
Artist(id = 254L, name = "Acceptance", coverArt = "ar-254", albumCount = 1)
)),
Index(name = "T", artists = listOf(
Artist(id = 516L, name = "Tangerine Dream", coverArt = "ar-516", albumCount = 1),
Artist(id = 242L, name = "Taproot", coverArt = "ar-242", albumCount = 2)
))
)
}
}
@Test
fun `Should pass param on query for get artists call`() {
enqueueResponse("get_artists_ok.json")
val musicFolderId = 101L
client.api.getArtists(musicFolderId).execute()
val request = mockWebServerRule.mockWebServer.takeRequest()
request.requestLine `should contain` "musicFolderId=$musicFolderId"
}
private fun enqueueResponse(resourceName: String) { private fun enqueueResponse(resourceName: String) {
mockWebServerRule.mockWebServer.enqueue(MockResponse() mockWebServerRule.mockWebServer.enqueue(MockResponse()
.setBody(loadJsonResponse(resourceName))) .setBody(loadJsonResponse(resourceName)))

View File

@ -0,0 +1,43 @@
{
"subsonic-response": {
"status": "ok",
"version": "1.15.0",
"artists": {
"ignoredArticles": "The El La Los Las Le Les",
"index": [
{
"name": "A",
"artist": [
{
"id": "362",
"name": "AC/DC",
"coverArt": "ar-362",
"albumCount": 2
},
{
"id": "254",
"name": "Acceptance",
"coverArt": "ar-254",
"albumCount": 1
}
]
}, {
"name": "T",
"artist": [
{
"id": "516",
"name": "Tangerine Dream",
"coverArt": "ar-516",
"albumCount": 1
},
{
"id": "242",
"name": "Taproot",
"coverArt": "ar-242",
"albumCount": 2
}
]
} ]
}
}
}

View File

@ -1,5 +1,6 @@
package org.moire.ultrasonic.api.subsonic package org.moire.ultrasonic.api.subsonic
import org.moire.ultrasonic.api.subsonic.response.GetArtistsResponse
import org.moire.ultrasonic.api.subsonic.response.GetIndexesResponse import org.moire.ultrasonic.api.subsonic.response.GetIndexesResponse
import org.moire.ultrasonic.api.subsonic.response.GetMusicDirectoryResponse import org.moire.ultrasonic.api.subsonic.response.GetMusicDirectoryResponse
import org.moire.ultrasonic.api.subsonic.response.LicenseResponse import org.moire.ultrasonic.api.subsonic.response.LicenseResponse
@ -30,4 +31,7 @@ interface SubsonicAPIDefinition {
@GET("getMusicDirectory.view") @GET("getMusicDirectory.view")
fun getMusicDirectory(@Query("id") id: Long): Call<GetMusicDirectoryResponse> fun getMusicDirectory(@Query("id") id: Long): Call<GetMusicDirectoryResponse>
@GET("getArtists.view")
fun getArtists(@Query("musicFolderId") musicFolderId: Long?): Call<GetArtistsResponse>
} }

View File

@ -4,4 +4,6 @@ import java.util.Calendar
data class Artist(val id: Long = -1, data class Artist(val id: Long = -1,
val name: String = "", val name: String = "",
val starred: Calendar?) val coverArt: String = "",
val albumCount: Int = 0,
val starred: Calendar? = null)

View File

@ -0,0 +1,12 @@
package org.moire.ultrasonic.api.subsonic.response
import com.fasterxml.jackson.annotation.JsonProperty
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import org.moire.ultrasonic.api.subsonic.SubsonicError
import org.moire.ultrasonic.api.subsonic.models.Indexes
class GetArtistsResponse(status: Status,
version: SubsonicAPIVersions,
error: SubsonicError?,
@JsonProperty("artists") val indexes: Indexes = Indexes()) :
SubsonicResponse(status, version, error)

View File

@ -56,6 +56,7 @@ import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.moire.ultrasonic.R; import org.moire.ultrasonic.R;
import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient; import org.moire.ultrasonic.api.subsonic.SubsonicAPIClient;
import org.moire.ultrasonic.api.subsonic.response.GetArtistsResponse;
import org.moire.ultrasonic.api.subsonic.response.GetIndexesResponse; import org.moire.ultrasonic.api.subsonic.response.GetIndexesResponse;
import org.moire.ultrasonic.api.subsonic.response.LicenseResponse; import org.moire.ultrasonic.api.subsonic.response.LicenseResponse;
import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse; import org.moire.ultrasonic.api.subsonic.response.MusicFoldersResponse;
@ -81,7 +82,6 @@ import org.moire.ultrasonic.service.parser.BookmarkParser;
import org.moire.ultrasonic.service.parser.ChatMessageParser; import org.moire.ultrasonic.service.parser.ChatMessageParser;
import org.moire.ultrasonic.service.parser.ErrorParser; import org.moire.ultrasonic.service.parser.ErrorParser;
import org.moire.ultrasonic.service.parser.GenreParser; import org.moire.ultrasonic.service.parser.GenreParser;
import org.moire.ultrasonic.service.parser.IndexesParser;
import org.moire.ultrasonic.service.parser.JukeboxStatusParser; import org.moire.ultrasonic.service.parser.JukeboxStatusParser;
import org.moire.ultrasonic.service.parser.LyricsParser; import org.moire.ultrasonic.service.parser.LyricsParser;
import org.moire.ultrasonic.service.parser.MusicDirectoryParser; import org.moire.ultrasonic.service.parser.MusicDirectoryParser;
@ -234,6 +234,21 @@ public class RESTMusicService implements MusicService
return musicFolders; return musicFolders;
} }
private static List<MusicFolder> readCachedMusicFolders(Context context) {
String filename = getCachedMusicFoldersFilename(context);
return FileUtil.deserialize(context, filename);
}
private static void writeCachedMusicFolders(Context context, List<MusicFolder> musicFolders) {
String filename = getCachedMusicFoldersFilename(context);
FileUtil.serialize(context, new ArrayList<>(musicFolders), filename);
}
private static String getCachedMusicFoldersFilename(Context context) {
String s = Util.getRestUrl(context, null);
return String.format(Locale.US, "musicFolders-%d.ser", Math.abs(s.hashCode()));
}
@Override @Override
public Indexes getIndexes(String musicFolderId, public Indexes getIndexes(String musicFolderId,
boolean refresh, boolean refresh,
@ -269,68 +284,38 @@ public class RESTMusicService implements MusicService
return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode())); return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode()));
} }
@Override @Override
public Indexes getArtists(boolean refresh, Context context, ProgressListener progressListener) throws Exception public Indexes getArtists(boolean refresh,
{ Context context,
checkServerVersion(context, "1.8", "Artists by ID3 tag not supported."); ProgressListener progressListener) throws Exception {
Indexes cachedArtists = readCachedArtists(context);
if (cachedArtists != null &&
!refresh) {
return cachedArtists;
}
Indexes cachedArtists = readCachedArtists(context); Response<GetArtistsResponse> response = subsonicAPIClient.getApi().getArtists(null).execute();
if (cachedArtists != null && !refresh) checkResponseSuccessful(response);
{
return cachedArtists;
}
Reader reader = getReader(context, progressListener, "getArtists", null); Indexes indexes = APIConverter.toDomainEntity(response.body().getIndexes());
try writeCachedArtists(context, indexes);
{ return indexes;
Indexes indexes = new IndexesParser(context).parse(reader, progressListener); }
if (indexes != null)
{
writeCachedArtists(context, indexes);
return indexes;
}
return cachedArtists != null ? cachedArtists : new Indexes(0, null, new ArrayList<org.moire.ultrasonic.domain.Artist>(), new ArrayList<org.moire.ultrasonic.domain.Artist>()); private static Indexes readCachedArtists(Context context) {
} String filename = getCachedArtistsFilename(context);
finally
{
Util.close(reader);
}
}
private static Indexes readCachedArtists(Context context)
{
String filename = getCachedArtistsFilename(context);
return FileUtil.deserialize(context, filename);
}
private static void writeCachedArtists(Context context, Indexes artists)
{
String filename = getCachedArtistsFilename(context);
FileUtil.serialize(context, artists, filename);
}
private static String getCachedArtistsFilename(Context context)
{
String s = Util.getRestUrl(context, null);
return String.format("indexes-%d.ser", Math.abs(s.hashCode()));
}
private static List<MusicFolder> readCachedMusicFolders(Context context) {
String filename = getCachedMusicFoldersFilename(context);
return FileUtil.deserialize(context, filename); return FileUtil.deserialize(context, filename);
} }
private static void writeCachedMusicFolders(Context context, List<MusicFolder> musicFolders) { private static void writeCachedArtists(Context context, Indexes artists) {
String filename = getCachedMusicFoldersFilename(context); String filename = getCachedArtistsFilename(context);
FileUtil.serialize(context, new ArrayList<>(musicFolders), filename); FileUtil.serialize(context, artists, filename);
} }
private static String getCachedMusicFoldersFilename(Context context) private static String getCachedArtistsFilename(Context context) {
{ String s = Util.getRestUrl(context, null);
String s = Util.getRestUrl(context, null); return String.format(Locale.US, "indexes-%d.ser", Math.abs(s.hashCode()));
return String.format("musicFolders-%d.ser", Math.abs(s.hashCode())); }
}
@Override @Override
public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception public void star(String id, String albumId, String artistId, Context context, ProgressListener progressListener) throws Exception

View File

@ -1,126 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus
*/
package org.moire.ultrasonic.service.parser;
import android.content.Context;
import android.util.Log;
import org.moire.ultrasonic.R;
import org.moire.ultrasonic.domain.Artist;
import org.moire.ultrasonic.domain.Indexes;
import org.moire.ultrasonic.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
/**
* @author Sindre Mehus
*/
public class IndexesParser extends AbstractParser
{
private static final String TAG = IndexesParser.class.getSimpleName();
private Context context;
public IndexesParser(Context context)
{
super(context);
this.context = context;
}
public Indexes parse(Reader reader, ProgressListener progressListener) throws Exception
{
long t0 = System.currentTimeMillis();
updateProgress(progressListener, R.string.parser_reading);
init(reader);
List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>();
Long lastModified = null;
String ignoredArticles = null;
int eventType;
String index = "#";
boolean changed = false;
do
{
eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG)
{
String name = getElementName();
if ("indexes".equals(name) || "artists".equals(name))
{
changed = true;
lastModified = getLong("lastModified");
ignoredArticles = get("ignoredArticles");
}
else if ("index".equals(name))
{
index = get("name");
}
else if ("artist".equals(name))
{
Artist artist = new Artist();
artist.setId(get("id"));
artist.setName(get("name"));
artist.setCoverArt(get("coverArt"));
artist.setAlbumCount(getLong("albumCount"));
artist.setIndex(index);
artists.add(artist);
if (artists.size() % 10 == 0)
{
String msg = this.context.getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
}
}
else if ("shortcut".equals(name))
{
Artist shortcut = new Artist();
shortcut.setId(get("id"));
shortcut.setName(get("name"));
shortcut.setIndex("*");
shortcuts.add(shortcut);
}
else if ("error".equals(name))
{
handleError();
}
}
} while (eventType != XmlPullParser.END_DOCUMENT);
validate();
if (!changed)
{
return null;
}
long t1 = System.currentTimeMillis();
Log.d(TAG, "Got " + artists.size() + " artist(s) in " + (t1 - t0) + "ms.");
String msg = this.context.getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
return new Indexes(lastModified == null ? 0L : lastModified, ignoredArticles, shortcuts, artists);
}
}

View File

@ -82,7 +82,7 @@ class APIConverterTest {
MusicFolder(id, name) MusicFolder(id, name)
private fun createArtist(id: Long = -1, name: String = "", starred: Calendar? = null): Artist private fun createArtist(id: Long = -1, name: String = "", starred: Calendar? = null): Artist
= Artist(id, name, starred) = Artist(id = id, name = name, starred = starred)
private fun createIndex(name: String = "", artistList: List<Artist> = emptyList()): Index private fun createIndex(name: String = "", artistList: List<Artist> = emptyList()): Index
= Index(name, artistList) = Index(name, artistList)