build: change of package name

This commit is contained in:
antonio 2023-06-17 15:30:23 +02:00
parent 49afdbe4eb
commit b76a38cb30
274 changed files with 1981 additions and 2161 deletions

View file

@ -0,0 +1,59 @@
package com.cappielloantonio.tempo.subsonic
import com.cappielloantonio.tempo.App
import com.cappielloantonio.tempo.subsonic.utils.CacheUtil
import com.google.gson.GsonBuilder
import okhttp3.Cache
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
class RetrofitClient(subsonic: Subsonic) {
var retrofit: Retrofit
init {
retrofit = Retrofit.Builder()
.baseUrl(subsonic.url)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
.client(getOkHttpClient())
.build()
}
private fun getOkHttpClient(): OkHttpClient {
val cacheUtil = CacheUtil(60, 60 * 60 * 24 * 30)
// BrowsingClient 60
// MediaAnnotationClient 0
// MediaLibraryScanningClient 0
// MediaRetrievalClient 0
// PlaylistClient 0
// PodcastClient 60
// SearchClient 60
// SystemClient 60
// AlbumSongListClient 60
return OkHttpClient.Builder()
.callTimeout(2, TimeUnit.MINUTES)
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.addInterceptor(getHttpLoggingInterceptor())
.addInterceptor(cacheUtil.offlineInterceptor)
// .addNetworkInterceptor(cacheUtil.onlineInterceptor)
.cache(getCache())
.build()
}
private fun getHttpLoggingInterceptor(): HttpLoggingInterceptor {
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
return loggingInterceptor
}
private fun getCache(): Cache {
val cacheSize = 10 * 1024 * 1024
return Cache(App.getContext().cacheDir, cacheSize.toLong())
}
}

View file

@ -0,0 +1,144 @@
package com.cappielloantonio.tempo.subsonic;
import com.cappielloantonio.tempo.subsonic.api.albumsonglist.AlbumSongListClient;
import com.cappielloantonio.tempo.subsonic.api.bookmarks.BookmarksClient;
import com.cappielloantonio.tempo.subsonic.api.browsing.BrowsingClient;
import com.cappielloantonio.tempo.subsonic.api.internetradio.InternetRadioClient;
import com.cappielloantonio.tempo.subsonic.api.mediaannotation.MediaAnnotationClient;
import com.cappielloantonio.tempo.subsonic.api.medialibraryscanning.MediaLibraryScanningClient;
import com.cappielloantonio.tempo.subsonic.api.mediaretrieval.MediaRetrievalClient;
import com.cappielloantonio.tempo.subsonic.api.playlist.PlaylistClient;
import com.cappielloantonio.tempo.subsonic.api.podcast.PodcastClient;
import com.cappielloantonio.tempo.subsonic.api.searching.SearchingClient;
import com.cappielloantonio.tempo.subsonic.api.system.SystemClient;
import com.cappielloantonio.tempo.subsonic.base.Version;
import java.util.HashMap;
import java.util.Map;
public class Subsonic {
private static final Version API_MAX_VERSION = Version.of("1.15.0");
private final Version apiVersion = API_MAX_VERSION;
private final SubsonicPreferences preferences;
private SystemClient systemClient;
private BrowsingClient browsingClient;
private MediaRetrievalClient mediaRetrievalClient;
private PlaylistClient playlistClient;
private SearchingClient searchingClient;
private AlbumSongListClient albumSongListClient;
private MediaAnnotationClient mediaAnnotationClient;
private PodcastClient podcastClient;
private MediaLibraryScanningClient mediaLibraryScanningClient;
private BookmarksClient bookmarksClient;
private InternetRadioClient internetRadioClient;
public Subsonic(SubsonicPreferences preferences) {
this.preferences = preferences;
}
public Version getApiVersion() {
return apiVersion;
}
public SystemClient getSystemClient() {
if (systemClient == null) {
systemClient = new SystemClient(this);
}
return systemClient;
}
public BrowsingClient getBrowsingClient() {
if (browsingClient == null) {
browsingClient = new BrowsingClient(this);
}
return browsingClient;
}
public MediaRetrievalClient getMediaRetrievalClient() {
if (mediaRetrievalClient == null) {
mediaRetrievalClient = new MediaRetrievalClient(this);
}
return mediaRetrievalClient;
}
public PlaylistClient getPlaylistClient() {
if (playlistClient == null) {
playlistClient = new PlaylistClient(this);
}
return playlistClient;
}
public SearchingClient getSearchingClient() {
if (searchingClient == null) {
searchingClient = new SearchingClient(this);
}
return searchingClient;
}
public AlbumSongListClient getAlbumSongListClient() {
if (albumSongListClient == null) {
albumSongListClient = new AlbumSongListClient(this);
}
return albumSongListClient;
}
public MediaAnnotationClient getMediaAnnotationClient() {
if (mediaAnnotationClient == null) {
mediaAnnotationClient = new MediaAnnotationClient(this);
}
return mediaAnnotationClient;
}
public PodcastClient getPodcastClient() {
if (podcastClient == null) {
podcastClient = new PodcastClient(this);
}
return podcastClient;
}
public MediaLibraryScanningClient getMediaLibraryScanningClient() {
if (mediaLibraryScanningClient == null) {
mediaLibraryScanningClient = new MediaLibraryScanningClient(this);
}
return mediaLibraryScanningClient;
}
public BookmarksClient getBookmarksClient() {
if (bookmarksClient == null) {
bookmarksClient = new BookmarksClient(this);
}
return bookmarksClient;
}
public InternetRadioClient getInternetRadioClient() {
if (internetRadioClient == null) {
internetRadioClient = new InternetRadioClient(this);
}
return internetRadioClient;
}
public String getUrl() {
String url = preferences.getServerUrl() + "/rest/";
return url.replace("//rest", "/rest");
}
public Map<String, String> getParams() {
Map<String, String> params = new HashMap<>();
params.put("u", preferences.getUsername());
if (preferences.getAuthentication().getPassword() != null)
params.put("p", preferences.getAuthentication().getPassword());
if (preferences.getAuthentication().getSalt() != null)
params.put("s", preferences.getAuthentication().getSalt());
if (preferences.getAuthentication().getToken() != null)
params.put("t", preferences.getAuthentication().getToken());
params.put("v", getApiVersion().getVersionString());
params.put("c", preferences.getClientName());
params.put("f", "json");
return params;
}
}

View file

@ -0,0 +1,86 @@
package com.cappielloantonio.tempo.subsonic;
import com.cappielloantonio.tempo.subsonic.utils.StringUtil;
import java.util.UUID;
public class SubsonicPreferences {
private String serverUrl;
private String username;
private String clientName = "Tempo";
private SubsonicAuthentication authentication;
public String getServerUrl() {
return serverUrl;
}
public String getUsername() {
return username;
}
public String getClientName() {
return clientName;
}
public SubsonicAuthentication getAuthentication() {
return authentication;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
public void setUsername(String username) {
this.username = username;
}
public void setClientName(String clientName) {
this.clientName = clientName;
}
public void setAuthentication(String password, String token, String salt, boolean isLowSecurity) {
if (password != null) {
this.authentication = new SubsonicAuthentication(password, isLowSecurity);
}
if (token != null && salt != null) {
this.authentication = new SubsonicAuthentication(token, salt);
}
}
public static class SubsonicAuthentication {
private String password;
private String salt;
private String token;
public SubsonicAuthentication(String password, boolean isLowSecurity) {
if (isLowSecurity) {
this.password = password;
} else {
update(password);
}
}
public SubsonicAuthentication(String token, String salt) {
this.token = token;
this.salt = salt;
}
public String getPassword() {
return password;
}
public String getSalt() {
return salt;
}
public String getToken() {
return token;
}
void update(String password) {
this.salt = UUID.randomUUID().toString();
this.token = StringUtil.tokenize(password + salt);
}
}
}

View file

@ -0,0 +1,56 @@
package com.cappielloantonio.tempo.subsonic.api.albumsonglist;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class AlbumSongListClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final AlbumSongListService albumSongListService;
public AlbumSongListClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.albumSongListService = new RetrofitClient(subsonic).getRetrofit().create(AlbumSongListService.class);
}
public Call<ApiResponse> getAlbumList(String type, int size, int offset) {
Log.d(TAG, "getAlbumList()");
return albumSongListService.getAlbumList(subsonic.getParams(), type, size, offset);
}
public Call<ApiResponse> getAlbumList2(String type, int size, int offset, Integer fromYear, Integer toYear) {
Log.d(TAG, "getAlbumList2()");
return albumSongListService.getAlbumList2(subsonic.getParams(), type, size, offset, fromYear, toYear);
}
public Call<ApiResponse> getRandomSongs(int size, Integer fromYear, Integer toYear) {
Log.d(TAG, "getRandomSongs()");
return albumSongListService.getRandomSongs(subsonic.getParams(), size, fromYear, toYear);
}
public Call<ApiResponse> getSongsByGenre(String genre, int count, int offset) {
Log.d(TAG, "getSongsByGenre()");
return albumSongListService.getSongsByGenre(subsonic.getParams(), genre, count, offset);
}
public Call<ApiResponse> getNowPlaying() {
Log.d(TAG, "getNowPlaying()");
return albumSongListService.getNowPlaying(subsonic.getParams());
}
public Call<ApiResponse> getStarred() {
Log.d(TAG, "getStarred()");
return albumSongListService.getStarred(subsonic.getParams());
}
public Call<ApiResponse> getStarred2() {
Log.d(TAG, "getStarred2()");
return albumSongListService.getStarred2(subsonic.getParams());
}
}

View file

@ -0,0 +1,33 @@
package com.cappielloantonio.tempo.subsonic.api.albumsonglist;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface AlbumSongListService {
@GET("getAlbumList")
Call<ApiResponse> getAlbumList(@QueryMap Map<String, String> params, @Query("type") String type, @Query("size") int size, @Query("offset") int offset);
@GET("getAlbumList2")
Call<ApiResponse> getAlbumList2(@QueryMap Map<String, String> params, @Query("type") String type, @Query("size") int size, @Query("offset") int offset, @Query("fromYear") Integer fromYear, @Query("toYear") Integer toYear);
@GET("getRandomSongs")
Call<ApiResponse> getRandomSongs(@QueryMap Map<String, String> params, @Query("size") int size, @Query("fromYear") Integer fromYear, @Query("toYear") Integer toYear);
@GET("getSongsByGenre")
Call<ApiResponse> getSongsByGenre(@QueryMap Map<String, String> params, @Query("genre") String genre, @Query("count") int count, @Query("offset") int offset);
@GET("getNowPlaying")
Call<ApiResponse> getNowPlaying(@QueryMap Map<String, String> params);
@GET("getStarred")
Call<ApiResponse> getStarred(@QueryMap Map<String, String> params);
@GET("getStarred2")
Call<ApiResponse> getStarred2(@QueryMap Map<String, String> params);
}

View file

@ -0,0 +1,33 @@
package com.cappielloantonio.tempo.subsonic.api.bookmarks;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.List;
import retrofit2.Call;
public class BookmarksClient {
private static final String TAG = "BookmarksClient";
private final Subsonic subsonic;
private final BookmarksService bookmarksService;
public BookmarksClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.bookmarksService = new RetrofitClient(subsonic).getRetrofit().create(BookmarksService.class);
}
public Call<ApiResponse> getPlayQueue() {
Log.d(TAG, "getPlayQueue()");
return bookmarksService.getPlayQueue(subsonic.getParams());
}
public Call<ApiResponse> savePlayQueue(List<String> ids, String current, long position) {
Log.d(TAG, "savePlayQueue()");
return bookmarksService.savePlayQueue(subsonic.getParams(), ids, current, position);
}
}

View file

@ -0,0 +1,19 @@
package com.cappielloantonio.tempo.subsonic.api.bookmarks;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.List;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface BookmarksService {
@GET("getPlayQueue")
Call<ApiResponse> getPlayQueue(@QueryMap Map<String, String> params);
@GET("savePlayQueue")
Call<ApiResponse> savePlayQueue(@QueryMap Map<String, String> params, @Query("id") List<String> ids, @Query("current") String current, @Query("position") long position);
}

View file

@ -0,0 +1,106 @@
package com.cappielloantonio.tempo.subsonic.api.browsing;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class BrowsingClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final BrowsingService browsingService;
public BrowsingClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.browsingService = new RetrofitClient(subsonic).getRetrofit().create(BrowsingService.class);
}
public Call<ApiResponse> getMusicFolders() {
Log.d(TAG, "getMusicFolders()");
return browsingService.getMusicFolders(subsonic.getParams());
}
public Call<ApiResponse> getIndexes(String musicFolderId, Long ifModifiedSince) {
Log.d(TAG, "getIndexes()");
return browsingService.getIndexes(subsonic.getParams(), musicFolderId, ifModifiedSince);
}
public Call<ApiResponse> getMusicDirectory(String id) {
Log.d(TAG, "getMusicDirectory()");
return browsingService.getMusicDirectory(subsonic.getParams(), id);
}
public Call<ApiResponse> getGenres() {
Log.d(TAG, "getGenres()");
return browsingService.getGenres(subsonic.getParams());
}
public Call<ApiResponse> getArtists() {
Log.d(TAG, "getArtists()");
return browsingService.getArtists(subsonic.getParams());
}
public Call<ApiResponse> getArtist(String id) {
Log.d(TAG, "getArtist()");
return browsingService.getArtist(subsonic.getParams(), id);
}
public Call<ApiResponse> getAlbum(String id) {
Log.d(TAG, "getAlbum()");
return browsingService.getAlbum(subsonic.getParams(), id);
}
public Call<ApiResponse> getSong(String id) {
Log.d(TAG, "getSong()");
return browsingService.getSong(subsonic.getParams(), id);
}
public Call<ApiResponse> getVideos() {
Log.d(TAG, "getVideos()");
return browsingService.getVideos(subsonic.getParams());
}
public Call<ApiResponse> getVideoInfo(String id) {
Log.d(TAG, "getVideoInfo()");
return browsingService.getVideoInfo(subsonic.getParams(), id);
}
public Call<ApiResponse> getArtistInfo(String id) {
Log.d(TAG, "getArtistInfo()");
return browsingService.getArtistInfo(subsonic.getParams(), id);
}
public Call<ApiResponse> getArtistInfo2(String id) {
Log.d(TAG, "getArtistInfo2()");
return browsingService.getArtistInfo2(subsonic.getParams(), id);
}
public Call<ApiResponse> getAlbumInfo(String id) {
Log.d(TAG, "getAlbumInfo()");
return browsingService.getAlbumInfo(subsonic.getParams(), id);
}
public Call<ApiResponse> getAlbumInfo2(String id) {
Log.d(TAG, "getAlbumInfo2()");
return browsingService.getAlbumInfo2(subsonic.getParams(), id);
}
public Call<ApiResponse> getSimilarSongs(String id, int count) {
Log.d(TAG, "getSimilarSongs()");
return browsingService.getSimilarSongs(subsonic.getParams(), id, count);
}
public Call<ApiResponse> getSimilarSongs2(String id, int limit) {
Log.d(TAG, "getSimilarSongs2()");
return browsingService.getSimilarSongs2(subsonic.getParams(), id, limit);
}
public Call<ApiResponse> getTopSongs(String artist, int count) {
Log.d(TAG, "getTopSongs()");
return browsingService.getTopSongs(subsonic.getParams(), artist, count);
}
}

View file

@ -0,0 +1,63 @@
package com.cappielloantonio.tempo.subsonic.api.browsing;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface BrowsingService {
@GET("getMusicFolders")
Call<ApiResponse> getMusicFolders(@QueryMap Map<String, String> params);
@GET("getIndexes")
Call<ApiResponse> getIndexes(@QueryMap Map<String, String> params, @Query("musicFolderId") String musicFolderId, @Query("ifModifiedSince") Long ifModifiedSince);
@GET("getMusicDirectory")
Call<ApiResponse> getMusicDirectory(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getGenres")
Call<ApiResponse> getGenres(@QueryMap Map<String, String> params);
@GET("getArtists")
Call<ApiResponse> getArtists(@QueryMap Map<String, String> params);
@GET("getArtist")
Call<ApiResponse> getArtist(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getAlbum")
Call<ApiResponse> getAlbum(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getSong")
Call<ApiResponse> getSong(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getVideos")
Call<ApiResponse> getVideos(@QueryMap Map<String, String> params);
@GET("getVideoInfo")
Call<ApiResponse> getVideoInfo(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getArtistInfo")
Call<ApiResponse> getArtistInfo(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getArtistInfo2")
Call<ApiResponse> getArtistInfo2(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getAlbumInfo")
Call<ApiResponse> getAlbumInfo(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getAlbumInfo2")
Call<ApiResponse> getAlbumInfo2(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getSimilarSongs")
Call<ApiResponse> getSimilarSongs(@QueryMap Map<String, String> params, @Query("id") String id, @Query("count") int count);
@GET("getSimilarSongs2")
Call<ApiResponse> getSimilarSongs2(@QueryMap Map<String, String> params, @Query("id") String id, @Query("count") int count);
@GET("getTopSongs")
Call<ApiResponse> getTopSongs(@QueryMap Map<String, String> params, @Query("artist") String artist, @Query("count") int count);
}

View file

@ -0,0 +1,41 @@
package com.cappielloantonio.tempo.subsonic.api.internetradio;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class InternetRadioClient {
private static final String TAG = "InternetRadioClient";
private final Subsonic subsonic;
private final InternetRadioService internetRadioService;
public InternetRadioClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.internetRadioService = new RetrofitClient(subsonic).getRetrofit().create(InternetRadioService.class);
}
public Call<ApiResponse> getInternetRadioStations() {
Log.d(TAG, "getInternetRadioStations()");
return internetRadioService.getInternetRadioStations(subsonic.getParams());
}
public Call<ApiResponse> createInternetRadioStation(String streamUrl, String name, String homepageUrl) {
Log.d(TAG, "createInternetRadioStation()");
return internetRadioService.createInternetRadioStation(subsonic.getParams(), streamUrl, name, homepageUrl);
}
public Call<ApiResponse> updateInternetRadioStation(String id, String streamUrl, String name, String homepageUrl) {
Log.d(TAG, "updateInternetRadioStation()");
return internetRadioService.updateInternetRadioStation(subsonic.getParams(), id, streamUrl, name, homepageUrl);
}
public Call<ApiResponse> deleteInternetRadioStation(String id) {
Log.d(TAG, "deleteInternetRadioStation()");
return internetRadioService.deleteInternetRadioStation(subsonic.getParams(), id);
}
}

View file

@ -0,0 +1,24 @@
package com.cappielloantonio.tempo.subsonic.api.internetradio;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface InternetRadioService {
@GET("getInternetRadioStations")
Call<ApiResponse> getInternetRadioStations(@QueryMap Map<String, String> params);
@GET("createInternetRadioStation")
Call<ApiResponse> createInternetRadioStation(@QueryMap Map<String, String> params, @Query("streamUrl") String streamUrl, @Query("name") String name, @Query("homepageUrl") String homepageUrl);
@GET("updateInternetRadioStation")
Call<ApiResponse> updateInternetRadioStation(@QueryMap Map<String, String> params, @Query("id") String id, @Query("streamUrl") String streamUrl, @Query("name") String name, @Query("homepageUrl") String homepageUrl);
@GET("deleteInternetRadioStation")
Call<ApiResponse> deleteInternetRadioStation(@QueryMap Map<String, String> params, @Query("id") String id);
}

View file

@ -0,0 +1,41 @@
package com.cappielloantonio.tempo.subsonic.api.mediaannotation;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class MediaAnnotationClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final MediaAnnotationService mediaAnnotationService;
public MediaAnnotationClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.mediaAnnotationService = new RetrofitClient(subsonic).getRetrofit().create(MediaAnnotationService.class);
}
public Call<ApiResponse> star(String id, String albumId, String artistId) {
Log.d(TAG, "star()");
return mediaAnnotationService.star(subsonic.getParams(), id, albumId, artistId);
}
public Call<ApiResponse> unstar(String id, String albumId, String artistId) {
Log.d(TAG, "unstar()");
return mediaAnnotationService.unstar(subsonic.getParams(), id, albumId, artistId);
}
public Call<ApiResponse> setRating(String id, int rating) {
Log.d(TAG, "setRating()");
return mediaAnnotationService.setRating(subsonic.getParams(), id, rating);
}
public Call<ApiResponse> scrobble(String id) {
Log.d(TAG, "scrobble()");
return mediaAnnotationService.scrobble(subsonic.getParams(), id);
}
}

View file

@ -0,0 +1,24 @@
package com.cappielloantonio.tempo.subsonic.api.mediaannotation;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface MediaAnnotationService {
@GET("star")
Call<ApiResponse> star(@QueryMap Map<String, String> params, @Query("id") String id, @Query("albumId") String albumId, @Query("artistId") String artistId);
@GET("unstar")
Call<ApiResponse> unstar(@QueryMap Map<String, String> params, @Query("id") String id, @Query("albumId") String albumId, @Query("artistId") String artistId);
@GET("setRating")
Call<ApiResponse> setRating(@QueryMap Map<String, String> params, @Query("id") String id, @Query("rating") int rating);
@GET("scrobble")
Call<ApiResponse> scrobble(@QueryMap Map<String, String> params, @Query("id") String id);
}

View file

@ -0,0 +1,31 @@
package com.cappielloantonio.tempo.subsonic.api.medialibraryscanning;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class MediaLibraryScanningClient {
private static final String TAG = "SystemClient";
private final Subsonic subsonic;
private final MediaLibraryScanningService mediaLibraryScanningService;
public MediaLibraryScanningClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.mediaLibraryScanningService = new RetrofitClient(subsonic).getRetrofit().create(MediaLibraryScanningService.class);
}
public Call<ApiResponse> startScan() {
Log.d(TAG, "startScan()");
return mediaLibraryScanningService.startScan(subsonic.getParams());
}
public Call<ApiResponse> getScanStatus() {
Log.d(TAG, "getScanStatus()");
return mediaLibraryScanningService.getScanStatus(subsonic.getParams());
}
}

View file

@ -0,0 +1,17 @@
package com.cappielloantonio.tempo.subsonic.api.medialibraryscanning;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;
public interface MediaLibraryScanningService {
@GET("startScan")
Call<ApiResponse> startScan(@QueryMap Map<String, String> params);
@GET("getScanStatus")
Call<ApiResponse> getScanStatus(@QueryMap Map<String, String> params);
}

View file

@ -0,0 +1,36 @@
package com.cappielloantonio.tempo.subsonic.api.mediaretrieval;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class MediaRetrievalClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final MediaRetrievalService mediaRetrievalService;
public MediaRetrievalClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.mediaRetrievalService = new RetrofitClient(subsonic).getRetrofit().create(MediaRetrievalService.class);
}
public Call<ApiResponse> stream(String id, Integer maxBitRate, String format) {
Log.d(TAG, "stream()");
return mediaRetrievalService.stream(subsonic.getParams(), id, maxBitRate, format);
}
public Call<ApiResponse> download(String id) {
Log.d(TAG, "download()");
return mediaRetrievalService.download(subsonic.getParams(), id);
}
public Call<ApiResponse> getLyrics(String artist, String title) {
Log.d(TAG, "getLyrics()");
return mediaRetrievalService.getLyrics(subsonic.getParams(), artist, title);
}
}

View file

@ -0,0 +1,21 @@
package com.cappielloantonio.tempo.subsonic.api.mediaretrieval;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface MediaRetrievalService {
@GET("stream")
Call<ApiResponse> stream(@QueryMap Map<String, String> params, @Query("id") String id, @Query("maxBitRate") Integer maxBitRate, @Query("format") String format);
@GET("download")
Call<ApiResponse> download(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("getLyrics")
Call<ApiResponse> getLyrics(@QueryMap Map<String, String> params, @Query("artist") String artist, @Query("title") String title);
}

View file

@ -0,0 +1,48 @@
package com.cappielloantonio.tempo.subsonic.api.playlist;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.ArrayList;
import retrofit2.Call;
public class PlaylistClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final PlaylistService playlistService;
public PlaylistClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.playlistService = new RetrofitClient(subsonic).getRetrofit().create(PlaylistService.class);
}
public Call<ApiResponse> getPlaylists() {
Log.d(TAG, "getPlaylists()");
return playlistService.getPlaylists(subsonic.getParams());
}
public Call<ApiResponse> getPlaylist(String id) {
Log.d(TAG, "getPlaylist()");
return playlistService.getPlaylist(subsonic.getParams(), id);
}
public Call<ApiResponse> createPlaylist(String playlistId, String name, ArrayList<String> songsId) {
Log.d(TAG, "createPlaylist()");
return playlistService.createPlaylist(subsonic.getParams(), playlistId, name, songsId);
}
public Call<ApiResponse> updatePlaylist(String playlistId, String name, boolean isPublic, ArrayList<String> songIdToAdd, ArrayList<Integer> songIndexToRemove) {
Log.d(TAG, "updatePlaylist()");
return playlistService.updatePlaylist(subsonic.getParams(), playlistId, name, isPublic, songIdToAdd, songIndexToRemove);
}
public Call<ApiResponse> deletePlaylist(String id) {
Log.d(TAG, "deletePlaylist()");
return playlistService.deletePlaylist(subsonic.getParams(), id);
}
}

View file

@ -0,0 +1,28 @@
package com.cappielloantonio.tempo.subsonic.api.playlist;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.ArrayList;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface PlaylistService {
@GET("getPlaylists")
Call<ApiResponse> getPlaylists(@QueryMap Map<String, String> params);
@GET("getPlaylist")
Call<ApiResponse> getPlaylist(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("createPlaylist")
Call<ApiResponse> createPlaylist(@QueryMap Map<String, String> params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("songId") ArrayList<String> songsId);
@GET("updatePlaylist")
Call<ApiResponse> updatePlaylist(@QueryMap Map<String, String> params, @Query("playlistId") String playlistId, @Query("name") String name, @Query("public") boolean isPublic, @Query("songIdToAdd") ArrayList<String> songIdToAdd, @Query("songIndexToRemove") ArrayList<Integer> songIndexToRemove);
@GET("deletePlaylist")
Call<ApiResponse> deletePlaylist(@QueryMap Map<String, String> params, @Query("id") String id);
}

View file

@ -0,0 +1,51 @@
package com.cappielloantonio.tempo.subsonic.api.podcast;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class PodcastClient {
private static final String TAG = "SystemClient";
private final Subsonic subsonic;
private final PodcastService podcastService;
public PodcastClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.podcastService = new RetrofitClient(subsonic).getRetrofit().create(PodcastService.class);
}
public Call<ApiResponse> getPodcasts(boolean includeEpisodes, String channelId) {
Log.d(TAG, "getPodcasts()");
return podcastService.getPodcasts(subsonic.getParams(), includeEpisodes, channelId);
}
public Call<ApiResponse> getNewestPodcasts(int count) {
Log.d(TAG, "getNewestPodcasts()");
return podcastService.getNewestPodcasts(subsonic.getParams(), count);
}
public Call<ApiResponse> refreshPodcasts() {
Log.d(TAG, "refreshPodcasts()");
return podcastService.refreshPodcasts(subsonic.getParams());
}
public Call<ApiResponse> createPodcastChannel(String url) {
Log.d(TAG, "createPodcastChannel()");
return podcastService.createPodcastChannel(subsonic.getParams(), url);
}
public Call<ApiResponse> deletePodcastChannel(String channelId) {
Log.d(TAG, "deletePodcastChannel()");
return podcastService.deletePodcastChannel(subsonic.getParams(), channelId);
}
public Call<ApiResponse> deletePodcastEpisode(String episodeId) {
Log.d(TAG, "deletePodcastEpisode()");
return podcastService.deletePodcastEpisode(subsonic.getParams(), episodeId);
}
}

View file

@ -0,0 +1,30 @@
package com.cappielloantonio.tempo.subsonic.api.podcast;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface PodcastService {
@GET("getPodcasts")
Call<ApiResponse> getPodcasts(@QueryMap Map<String, String> params, @Query("includeEpisodes") boolean includeEpisodes, @Query("id") String id);
@GET("getNewestPodcasts")
Call<ApiResponse> getNewestPodcasts(@QueryMap Map<String, String> params, @Query("count") int count);
@GET("refreshPodcasts")
Call<ApiResponse> refreshPodcasts(@QueryMap Map<String, String> params);
@GET("createPodcastChannel")
Call<ApiResponse> createPodcastChannel(@QueryMap Map<String, String> params, @Query("url") String url);
@GET("deletePodcastChannel")
Call<ApiResponse> deletePodcastChannel(@QueryMap Map<String, String> params, @Query("id") String id);
@GET("deletePodcastEpisode")
Call<ApiResponse> deletePodcastEpisode(@QueryMap Map<String, String> params, @Query("id") String id);
}

View file

@ -0,0 +1,31 @@
package com.cappielloantonio.tempo.subsonic.api.searching;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class SearchingClient {
private static final String TAG = "BrowsingClient";
private final Subsonic subsonic;
private final SearchingService searchingService;
public SearchingClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.searchingService = new RetrofitClient(subsonic).getRetrofit().create(SearchingService.class);
}
public Call<ApiResponse> search2(String query, int songCount, int albumCount, int artistCount) {
Log.d(TAG, "search2()");
return searchingService.search2(subsonic.getParams(), query, songCount, albumCount, artistCount);
}
public Call<ApiResponse> search3(String query, int songCount, int albumCount, int artistCount) {
Log.d(TAG, "search3()");
return searchingService.search3(subsonic.getParams(), query, songCount, albumCount, artistCount);
}
}

View file

@ -0,0 +1,18 @@
package com.cappielloantonio.tempo.subsonic.api.searching;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
public interface SearchingService {
@GET("search2")
Call<ApiResponse> search2(@QueryMap Map<String, String> params, @Query("query") String query, @Query("songCount") int songCount, @Query("albumCount") int albumCount, @Query("artistCount") int artistCount);
@GET("search3")
Call<ApiResponse> search3(@QueryMap Map<String, String> params, @Query("query") String query, @Query("songCount") int songCount, @Query("albumCount") int albumCount, @Query("artistCount") int artistCount);
}

View file

@ -0,0 +1,31 @@
package com.cappielloantonio.tempo.subsonic.api.system;
import android.util.Log;
import com.cappielloantonio.tempo.subsonic.RetrofitClient;
import com.cappielloantonio.tempo.subsonic.Subsonic;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import retrofit2.Call;
public class SystemClient {
private static final String TAG = "SystemClient";
private final Subsonic subsonic;
private final SystemService systemService;
public SystemClient(Subsonic subsonic) {
this.subsonic = subsonic;
this.systemService = new RetrofitClient(subsonic).getRetrofit().create(SystemService.class);
}
public Call<ApiResponse> ping() {
Log.d(TAG, "ping()");
return systemService.ping(subsonic.getParams());
}
public Call<ApiResponse> getLicense() {
Log.d(TAG, "getLicense()");
return systemService.getLicense(subsonic.getParams());
}
}

View file

@ -0,0 +1,17 @@
package com.cappielloantonio.tempo.subsonic.api.system;
import com.cappielloantonio.tempo.subsonic.base.ApiResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.QueryMap;
public interface SystemService {
@GET("ping")
Call<ApiResponse> ping(@QueryMap Map<String, String> params);
@GET("getLicense")
Call<ApiResponse> getLicense(@QueryMap Map<String, String> params);
}

View file

@ -0,0 +1,9 @@
package com.cappielloantonio.tempo.subsonic.base
import com.cappielloantonio.tempo.subsonic.models.SubsonicResponse
import com.google.gson.annotations.SerializedName
class ApiResponse {
@SerializedName("subsonic-response")
var subsonicResponse: SubsonicResponse? = null
}

View file

@ -0,0 +1,59 @@
package com.cappielloantonio.tempo.subsonic.base;
import androidx.annotation.NonNull;
public class Version implements Comparable<Version> {
private static final String VERSION_PATTERN = "\\d+(\\.\\d+)*";
private final String versionString;
public static Version of(String versionString) {
return new Version(versionString);
}
private Version(String versionString) {
if (versionString == null || !versionString.matches(VERSION_PATTERN)) {
throw new IllegalArgumentException("Invalid version format");
}
this.versionString = versionString;
}
public String getVersionString() {
return versionString;
}
public boolean isLowerThan(Version version) {
return compareTo(version) < 0;
}
@Override
public int compareTo(Version that) {
if (that == null) {
return 1;
}
String[] thisParts = this.getVersionString().split("\\.");
String[] thatParts = that.getVersionString().split("\\.");
int length = Math.max(thisParts.length, thatParts.length);
for (int i = 0; i < length; i++) {
int thisPart = i < thisParts.length ? Integer.parseInt(thisParts[i]) : 0;
int thatPart = i < thatParts.length ? Integer.parseInt(thatParts[i]) : 0;
if (thisPart < thatPart) {
return -1;
}
if (thisPart > thatPart) {
return 1;
}
}
return 0;
}
@NonNull
@Override
public String toString() {
return versionString;
}
}

View file

@ -0,0 +1,25 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
open class AlbumID3 : Parcelable {
var id: String? = null
var name: String? = null
var artist: String? = null
var artistId: String? = null
@SerializedName("coverArt")
var coverArtId: String? = null
var songCount: Int? = 0
var duration: Int? = 0
var playCount: Long? = null
var created: Date? = null
var starred: Date? = null
var year: Int = 0
var genre: String? = null
}

View file

@ -0,0 +1,11 @@
package com.cappielloantonio.tempo.subsonic.models
class AlbumInfo {
var notes: String? = null
var musicBrainzId: String? = null
var lastFmUrl: String? = null
var smallImageUrl: String? = null
var mediumImageUrl: String? = null
var largeImageUrl: String? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class AlbumList {
var albums: List<Child>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class AlbumList2 {
@SerializedName("album")
var albums: List<AlbumID3>? = null
}

View file

@ -0,0 +1,11 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class AlbumWithSongsID3 : AlbumID3(), Parcelable {
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.util.Date
@Parcelize
class Artist : Parcelable {
var id: String? = null
var name: String? = null
var starred: Date? = null
var userRating: Int? = null
var averageRating: Double? = null
}

View file

@ -0,0 +1,17 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
open class ArtistID3 : Parcelable {
var id: String? = null
var name: String? = null
@SerializedName("coverArt")
var coverArtId: String? = null
var albumCount = 0
var starred: Date? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class ArtistInfo : ArtistInfoBase() {
var similarArtists: List<Artist>? = null
}

View file

@ -0,0 +1,9 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
import java.util.*
class ArtistInfo2 : ArtistInfoBase() {
@SerializedName("similarArtist")
var similarArtists: List<SimilarArtistID3>? = emptyList()
}

View file

@ -0,0 +1,10 @@
package com.cappielloantonio.tempo.subsonic.models
open class ArtistInfoBase {
var biography: String? = null
var musicBrainzId: String? = null
var lastFmUrl: String? = null
var smallImageUrl: String? = null
var mediumImageUrl: String? = null
var largeImageUrl: String? = null
}

View file

@ -0,0 +1,11 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class ArtistWithAlbumsID3 : ArtistID3(), Parcelable {
@SerializedName("album")
var albums: List<AlbumID3>? = null
}

View file

@ -0,0 +1,9 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class ArtistsID3 {
@SerializedName("index")
var indices: List<IndexID3>? = null
var ignoredArticles: String? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class AudioTrack {
var id: String? = null
var name: String? = null
var languageCode: String? = null
}

View file

@ -0,0 +1,12 @@
package com.cappielloantonio.tempo.subsonic.models
import java.util.*
class Bookmark {
var entry: Child? = null
var position: Long = 0
var username: String? = null
var comment: String? = null
var created: Date? = null
var changed: Date? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class Bookmarks {
var bookmarks: List<Bookmark>? = null
}

View file

@ -0,0 +1,6 @@
package com.cappielloantonio.tempo.subsonic.models
class Captions {
var id: String? = null
var name: String? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class ChatMessage {
var username: String? = null
var time: Long = 0
var message: String? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class ChatMessages {
var chatMessages: List<ChatMessage>? = null
}

View file

@ -0,0 +1,110 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
open class Child(
@PrimaryKey
@ColumnInfo(name = "id")
open val id: String,
@ColumnInfo(name = "parent_id")
@SerializedName("parent")
var parentId: String? = null,
@ColumnInfo(name = "is_dir")
var isDir: Boolean = false,
@ColumnInfo
var title: String? = null,
@ColumnInfo
var album: String? = null,
@ColumnInfo
var artist: String? = null,
@ColumnInfo
var track: Int? = null,
@ColumnInfo
var year: Int? = null,
@ColumnInfo
@SerializedName("genre")
var genre: String? = null,
@ColumnInfo(name = "cover_art_id")
@SerializedName("coverArt")
var coverArtId: String? = null,
@ColumnInfo
var size: Long? = null,
@ColumnInfo(name = "content_type")
var contentType: String? = null,
@ColumnInfo
var suffix: String? = null,
@ColumnInfo("transcoding_content_type")
var transcodedContentType: String? = null,
@ColumnInfo(name = "transcoded_suffix")
var transcodedSuffix: String? = null,
@ColumnInfo
var duration: Int? = null,
@ColumnInfo("bitrate")
@SerializedName("bitRate")
var bitrate: Int? = null,
@ColumnInfo
var path: String? = null,
@ColumnInfo(name = "is_video")
@SerializedName("isVideo")
var isVideo: Boolean = false,
@ColumnInfo(name = "user_rating")
var userRating: Int? = null,
@ColumnInfo(name = "average_rating")
var averageRating: Double? = null,
@ColumnInfo(name = "play_count")
var playCount: Long? = null,
@ColumnInfo(name = "disc_number")
var discNumber: Int? = null,
@ColumnInfo
var created: Date? = null,
@ColumnInfo
var starred: Date? = null,
@ColumnInfo(name = "album_id")
var albumId: String? = null,
@ColumnInfo(name = "artist_id")
var artistId: String? = null,
@ColumnInfo
var type: String? = null,
@ColumnInfo(name = "bookmark_position")
var bookmarkPosition: Long? = null,
@ColumnInfo(name = "original_width")
var originalWidth: Int? = null,
@ColumnInfo(name = "original_height")
var originalHeight: Int? = null
) : Parcelable

View file

@ -0,0 +1,20 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.Date
@Parcelize
class Directory : Parcelable {
@SerializedName("child")
var children: List<Child>? = null
var id: String? = null
@SerializedName("parent")
var parentId: String? = null
var name: String? = null
var starred: Date? = null
var userRating: Int? = null
var averageRating: Double? = null
var playCount: Long? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class Error {
var code: ErrorCode? = null
var message: String? = null
}

View file

@ -0,0 +1,16 @@
package com.cappielloantonio.tempo.subsonic.models
class ErrorCode(val value: Int) {
companion object {
var GENERIC_ERROR = 0
var REQUIRED_PARAMETER_MISSING = 10
var INCOMPATIBLE_VERSION_CLIENT = 20
var INCOMPATIBLE_VERSION_SERVER = 30
var WRONG_USERNAME_OR_PASSWORD = 40
var TOKEN_AUTHENTICATION_NOT_SUPPORTED = 41
var USER_NOT_AUTHORIZED = 50
var TRIAL_PERIOD_OVER = 60
var DATA_NOT_FOUND = 70
}
}

View file

@ -0,0 +1,13 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class Genre : Parcelable {
@SerializedName("value")
var genre: String? = null
var songCount = 0
var albumCount = 0
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Genres {
@SerializedName("genre")
var genres: List<Genre>? = null
}

View file

@ -0,0 +1,9 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Index {
@SerializedName("artist")
var artists: List<Artist>? = null
var name: String? = null
}

View file

@ -0,0 +1,9 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class IndexID3 {
@SerializedName("artist")
var artists: List<ArtistID3>? = null
var name: String? = null
}

View file

@ -0,0 +1,12 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Indexes {
var shortcuts: List<Artist>? = null
@SerializedName("index")
var indices: List<Index>? = null
var children: List<Child>? = null
var lastModified: Long = 0
var ignoredArticles: String? = null
}

View file

@ -0,0 +1,12 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class InternetRadioStation : Parcelable {
var id: String? = null
var name: String? = null
var streamUrl: String? = null
var homePageUrl: String? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class InternetRadioStations {
@SerializedName("internetRadioStation")
var internetRadioStations: List<InternetRadioStation>? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class JukeboxPlaylist : JukeboxStatus() {
var entries: List<Child>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
open class JukeboxStatus {
var currentIndex = 0
var isPlaying = false
var gain = 0f
var position: Int? = null
}

View file

@ -0,0 +1,10 @@
package com.cappielloantonio.tempo.subsonic.models
import java.util.*
class License {
var isValid = false
var email: String? = null
var licenseExpires: Date? = null
var trialExpires: Date? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class Lyrics {
var value: String? = null
var artist: String? = null
var title: String? = null
}

View file

@ -0,0 +1,12 @@
package com.cappielloantonio.tempo.subsonic.models
class MediaType {
var value: String? = null
companion object {
var MUSIC = "music"
var PODCAST = "podcast"
var AUDIOBOOK = "audiobook"
var VIDEO = "video"
}
}

View file

@ -0,0 +1,10 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class MusicFolder : Parcelable {
var id: String? = null
var name: String? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class MusicFolders {
@SerializedName("musicFolder")
var musicFolders: List<MusicFolder>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class NewestPodcasts {
@SerializedName("episode")
var episodes: List<PodcastEpisode>? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class NowPlaying {
var entries: List<NowPlayingEntry>? = null
}

View file

@ -0,0 +1,15 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class NowPlayingEntry(
@SerializedName("_id")
override val id: String
) : Child(id) {
var username: String? = null
var minutesAgo = 0
var playerId = 0
var playerName: String? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
import java.util.*
class PlayQueue {
@SerializedName("entry")
var entries: List<Child>? = null
var current: String? = null
var position: Long? = null
var username: String? = null
var changed: Date? = null
var changedBy: String? = null
}

View file

@ -0,0 +1,49 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
@Entity(tableName = "playlist")
open class Playlist(
@PrimaryKey
@ColumnInfo(name = "id")
open var id: String
) : Parcelable {
@ColumnInfo(name = "name")
var name: String? = null
@Ignore
var comment: String? = null
@Ignore
var owner: String? = null
@Ignore
@SerializedName("public")
var isUniversal: Boolean? = null
@Ignore
var songCount: Int = 0
@ColumnInfo(name = "duration")
var duration: Long = 0
@Ignore
var created: Date? = null
@Ignore
var changed: Date? = null
@ColumnInfo(name = "coverArt")
var coverArtId: String? = null
@Ignore
var allowedUsers: List<String>? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class PlaylistWithSongs(
@SerializedName("_id")
override var id: String
) : Playlist(id), Parcelable {
@SerializedName("entry")
var entries: List<Child>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Playlists(
@SerializedName("playlist")
var playlists: List<Playlist>? = null
)

View file

@ -0,0 +1,19 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
@Parcelize
class PodcastChannel : Parcelable {
@SerializedName("episode")
var episodes: List<PodcastEpisode>? = null
var id: String? = null
var url: String? = null
var title: String? = null
var description: String? = null
var coverArtId: String? = null
var originalImageUrl: String? = null
var status: String? = null
var errorMessage: String? = null
}

View file

@ -0,0 +1,58 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import androidx.room.ColumnInfo
import com.google.gson.annotations.SerializedName
import kotlinx.parcelize.Parcelize
import java.util.*
@Parcelize
class PodcastEpisode : Parcelable {
var id: String? = null
@SerializedName("parent")
var parentId: String? = null
@SerializedName("isDir")
var isDir = false
var title: String? = null
var album: String? = null
var artist: String? = null
var track: Int? = null
var year: Int? = null
var genre: String? = null
@SerializedName("coverArt")
var coverArtId: String? = null
var size: Long? = null
var contentType: String? = null
var suffix: String? = null
var transcodedContentType: String? = null
var transcodedSuffix: String? = null
var duration: Int? = null
@ColumnInfo("bitrate")
@SerializedName("bitRate")
var bitrate: Int? = null
var path: String? = null
@ColumnInfo(name = "is_video")
@SerializedName("isVideo")
var isVideo: Boolean = false
var userRating: Int? = null
var averageRating: Double? = null
var playCount: Long? = null
var discNumber: Int? = null
var created: Date? = null
var starred: Date? = null
var albumId: String? = null
var artistId: String? = null
var type: String? = null
var bookmarkPosition: Long? = null
var originalWidth: Int? = null
var originalHeight: Int? = null
var streamId: String? = null
var channelId: String? = null
var description: String? = null
var status: String? = null
var publishDate: Date? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
class PodcastStatus {
var value: String? = null
companion object {
var NEW = "new"
var DOWNLOADING = "downloading"
var COMPLETED = "completed"
var ERROR = "error"
var DELETED = "deleted"
var SKIPPED = "skipped"
}
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Podcasts {
@SerializedName("channel")
var channels: List<PodcastChannel>? = null
}

View file

@ -0,0 +1,12 @@
package com.cappielloantonio.tempo.subsonic.models
class ResponseStatus(val value: String) {
companion object {
@JvmField
var OK = "ok"
@JvmField
var FAILED = "failed"
}
}

View file

@ -0,0 +1,6 @@
package com.cappielloantonio.tempo.subsonic.models
class ScanStatus {
var isScanning = false
var count: Long? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class SearchResult {
var matches: List<Child>? = null
var offset = 0
var totalHits = 0
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class SearchResult2 {
@SerializedName("artist")
var artists: List<Artist>? = null
@SerializedName("album")
var albums: List<Child>? = null
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class SearchResult3 {
@SerializedName("artist")
var artists: List<ArtistID3>? = null
@SerializedName("album")
var albums: List<AlbumID3>? = null
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,15 @@
package com.cappielloantonio.tempo.subsonic.models
import java.util.*
class Share {
var entries: List<Child>? = null
var id: String? = null
var url: String? = null
var description: String? = null
var username: String? = null
var created: Date? = null
var expires: Date? = null
var lastVisited: Date? = null
var visitCount = 0
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class Shares {
var shares: List<Share>? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
@Parcelize
class SimilarArtistID3 : ArtistID3(), Parcelable

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class SimilarSongs {
var songs: List<Child>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class SimilarSongs2 {
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Songs {
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class Starred {
var artists: List<Artist>? = null
var albums: List<Child>? = null
var songs: List<Child>? = null
}

View file

@ -0,0 +1,14 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class Starred2 {
@SerializedName("artist")
var artists: List<ArtistID3>? = null
@SerializedName("album")
var albums: List<AlbumID3>? = null
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,51 @@
package com.cappielloantonio.tempo.subsonic.models
class SubsonicResponse {
var error: Error? = null
var scanStatus: ScanStatus? = null
var topSongs: TopSongs? = null
var similarSongs2: SimilarSongs2? = null
var similarSongs: SimilarSongs? = null
var artistInfo2: ArtistInfo2? = null
var artistInfo: ArtistInfo? = null
var albumInfo: AlbumInfo? = null
var starred2: Starred2? = null
var starred: Starred? = null
var shares: Shares? = null
var playQueue: PlayQueue? = null
var bookmarks: Bookmarks? = null
var internetRadioStations: InternetRadioStations? = null
var newestPodcasts: NewestPodcasts? = null
var podcasts: Podcasts? = null
var lyrics: Lyrics? = null
var songsByGenre: Songs? = null
var randomSongs: Songs? = null
var albumList2: AlbumList2? = null
var albumList: AlbumList? = null
var chatMessages: ChatMessages? = null
var user: User? = null
var users: Users? = null
var license: License? = null
var jukeboxPlaylist: JukeboxPlaylist? = null
var jukeboxStatus: JukeboxStatus? = null
var playlist: PlaylistWithSongs? = null
var playlists: Playlists? = null
var searchResult3: SearchResult3? = null
var searchResult2: SearchResult2? = null
var searchResult: SearchResult? = null
var nowPlaying: NowPlaying? = null
var videoInfo: VideoInfo? = null
var videos: Videos? = null
var song: Child? = null
var album: AlbumWithSongsID3? = null
var artist: ArtistWithAlbumsID3? = null
var artists: ArtistsID3? = null
var genres: Genres? = null
var directory: Directory? = null
var indexes: Indexes? = null
var musicFolders: MusicFolders? = null
var status: String? = null
var version: String? = null
var type: String? = null
var serverVersion: String? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
import com.google.gson.annotations.SerializedName
class TopSongs {
@SerializedName("song")
var songs: List<Child>? = null
}

View file

@ -0,0 +1,24 @@
package com.cappielloantonio.tempo.subsonic.models
import java.util.*
class User {
var folders: List<Int>? = null
var username: String? = null
var email: String? = null
var isScrobblingEnabled = false
var maxBitRate: Int? = null
var isAdminRole = false
var isSettingsRole = false
var isDownloadRole = false
var isUploadRole = false
var isPlaylistRole = false
var isCoverArtRole = false
var isCommentRole = false
var isPodcastRole = false
var isStreamRole = false
var isJukeboxRole = false
var isShareRole = false
var isVideoConversionRole = false
var avatarLastChanged: Date? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class Users {
var users: List<User>? = null
}

View file

@ -0,0 +1,7 @@
package com.cappielloantonio.tempo.subsonic.models
class VideoConversion {
var id: String? = null
var bitRate: Int? = null
var audioTrackId: Int? = null
}

View file

@ -0,0 +1,8 @@
package com.cappielloantonio.tempo.subsonic.models
class VideoInfo {
var captions: List<Captions>? = null
var audioTracks: List<AudioTrack>? = null
var conversions: List<VideoConversion>? = null
var id: String? = null
}

View file

@ -0,0 +1,5 @@
package com.cappielloantonio.tempo.subsonic.models
class Videos {
var videos: List<Child>? = null
}

View file

@ -0,0 +1,45 @@
package com.cappielloantonio.tempo.subsonic.utils;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.cappielloantonio.tempo.App;
import okhttp3.Interceptor;
import okhttp3.Request;
public class CacheUtil {
private int maxAge; // 60 seconds
private int maxStale; // 60 * 60 * 24 * 30 = 30 days (60 seconds * 60 minutes * 24 hours * 30 days)
public CacheUtil(int maxAge, int maxStale) {
this.maxAge = maxAge;
this.maxStale = maxStale;
}
public Interceptor onlineInterceptor = chain -> {
okhttp3.Response response = chain.proceed(chain.request());
return response.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.removeHeader("Pragma")
.build();
};
public Interceptor offlineInterceptor = chain -> {
Request request = chain.request();
if (!isConnected()) {
request = request.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.removeHeader("Pragma")
.build();
}
return chain.proceed(request);
};
private boolean isConnected() {
ConnectivityManager connectivityManager = (ConnectivityManager) App.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
return (netInfo != null && netInfo.isConnected());
}
}

View file

@ -0,0 +1,28 @@
package com.cappielloantonio.tempo.subsonic.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class StringUtil {
public static String tokenize(String s) {
final String MD5 = "MD5";
try {
MessageDigest digest = java.security.MessageDigest.getInstance(MD5);
digest.update(s.getBytes());
byte[] messageDigest = digest.digest();
StringBuilder hexString = new StringBuilder();
for (byte aMessageDigest : messageDigest) {
StringBuilder h = new StringBuilder(Integer.toHexString(0xFF & aMessageDigest));
while (h.length() < 2) {
h.insert(0, "0");
}
hexString.append(h);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
}