1
0
mirror of https://github.com/ultrasonic/ultrasonic synced 2025-04-16 19:37:18 +02:00

Convert all Services to Kotlin

This commit is contained in:
tzugen 2021-05-26 23:17:52 +02:00
parent 3f2daaa7ec
commit 5ac36b749b
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
4 changed files with 1328 additions and 1518 deletions

View File

@ -16,524 +16,470 @@
Copyright 2009 (C) Sindre Mehus Copyright 2009 (C) Sindre Mehus
*/ */
package org.moire.ultrasonic.service; package org.moire.ultrasonic.service
import android.graphics.Bitmap; import android.graphics.Bitmap
import org.koin.java.KoinJavaComponent.inject
import org.moire.ultrasonic.data.ActiveServerProvider; import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.Bookmark; import org.moire.ultrasonic.domain.Bookmark
import org.moire.ultrasonic.domain.ChatMessage; import org.moire.ultrasonic.domain.ChatMessage
import org.moire.ultrasonic.domain.Genre; import org.moire.ultrasonic.domain.Genre
import org.moire.ultrasonic.domain.Indexes; import org.moire.ultrasonic.domain.Indexes
import org.moire.ultrasonic.domain.JukeboxStatus; import org.moire.ultrasonic.domain.JukeboxStatus
import org.moire.ultrasonic.domain.Lyrics; import org.moire.ultrasonic.domain.Lyrics
import org.moire.ultrasonic.domain.MusicDirectory; import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.MusicFolder; import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.domain.Playlist; import org.moire.ultrasonic.domain.Playlist
import org.moire.ultrasonic.domain.PodcastsChannel; import org.moire.ultrasonic.domain.PodcastsChannel
import org.moire.ultrasonic.domain.SearchCriteria; import org.moire.ultrasonic.domain.SearchCriteria
import org.moire.ultrasonic.domain.SearchResult; import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.domain.Share; import org.moire.ultrasonic.domain.Share
import org.moire.ultrasonic.domain.UserInfo; import org.moire.ultrasonic.domain.UserInfo
import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.LRUCache; import org.moire.ultrasonic.util.LRUCache
import org.moire.ultrasonic.util.TimeLimitedCache; import org.moire.ultrasonic.util.TimeLimitedCache
import org.moire.ultrasonic.util.Util; import org.moire.ultrasonic.util.Util
import java.io.InputStream
import java.io.InputStream; import java.util.concurrent.TimeUnit
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import kotlin.Lazy;
import kotlin.Pair;
import static org.koin.java.KoinJavaComponent.inject;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class CachedMusicService implements MusicService class CachedMusicService(private val musicService: MusicService) : MusicService {
{ private val activeServerProvider = inject(
private final Lazy<ActiveServerProvider> activeServerProvider = inject(ActiveServerProvider.class); ActiveServerProvider::class.java
)
private static final int MUSIC_DIR_CACHE_SIZE = 100; private val cachedMusicDirectories: LRUCache<String?, TimeLimitedCache<MusicDirectory?>>
private val cachedArtist: LRUCache<String?, TimeLimitedCache<MusicDirectory?>>
private final MusicService musicService; private val cachedAlbum: LRUCache<String?, TimeLimitedCache<MusicDirectory?>>
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedMusicDirectories; private val cachedUserInfo: LRUCache<String?, TimeLimitedCache<UserInfo?>>
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedArtist; private val cachedLicenseValid = TimeLimitedCache<Boolean>(120, TimeUnit.SECONDS)
private final LRUCache<String, TimeLimitedCache<MusicDirectory>> cachedAlbum; private val cachedIndexes = TimeLimitedCache<Indexes?>(60 * 60, TimeUnit.SECONDS)
private final LRUCache<String, TimeLimitedCache<UserInfo>> cachedUserInfo; private val cachedArtists = TimeLimitedCache<Indexes?>(60 * 60, TimeUnit.SECONDS)
private final TimeLimitedCache<Boolean> cachedLicenseValid = new TimeLimitedCache<>(120, TimeUnit.SECONDS); private val cachedPlaylists = TimeLimitedCache<List<Playlist>?>(3600, TimeUnit.SECONDS)
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS); private val cachedPodcastsChannels =
private final TimeLimitedCache<Indexes> cachedArtists = new TimeLimitedCache<>(60 * 60, TimeUnit.SECONDS); TimeLimitedCache<List<PodcastsChannel>>(3600, TimeUnit.SECONDS)
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<>(3600, TimeUnit.SECONDS); private val cachedMusicFolders =
private final TimeLimitedCache<List<PodcastsChannel>> cachedPodcastsChannels = new TimeLimitedCache<>(3600, TimeUnit.SECONDS); TimeLimitedCache<List<MusicFolder>?>(10 * 3600, TimeUnit.SECONDS)
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); private val cachedGenres = TimeLimitedCache<List<Genre>?>(10 * 3600, TimeUnit.SECONDS)
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); private var restUrl: String? = null
private var cachedMusicFolderId: String? = null
private String restUrl;
private String cachedMusicFolderId; @Throws(Exception::class)
override fun ping() {
public CachedMusicService(MusicService musicService) checkSettingsChanged()
{ musicService.ping()
this.musicService = musicService; }
cachedMusicDirectories = new LRUCache<>(MUSIC_DIR_CACHE_SIZE);
cachedArtist = new LRUCache<>(MUSIC_DIR_CACHE_SIZE); @Throws(Exception::class)
cachedAlbum = new LRUCache<>(MUSIC_DIR_CACHE_SIZE); override fun isLicenseValid(): Boolean {
cachedUserInfo = new LRUCache<>(MUSIC_DIR_CACHE_SIZE); checkSettingsChanged()
} var result = cachedLicenseValid.get()
if (result == null) {
@Override result = musicService.isLicenseValid()
public void ping() throws Exception cachedLicenseValid[result, if (result) 30L * 60L else 2L * 60L] = TimeUnit.SECONDS
{ }
checkSettingsChanged(); return result
musicService.ping(); }
}
@Throws(Exception::class)
@Override override fun getMusicFolders(refresh: Boolean): List<MusicFolder> {
public boolean isLicenseValid() throws Exception checkSettingsChanged()
{ if (refresh) {
checkSettingsChanged(); cachedMusicFolders.clear()
Boolean result = cachedLicenseValid.get(); }
if (result == null)
{ val cache = cachedMusicFolders.get()
result = musicService.isLicenseValid(); if (cache != null) return cache
cachedLicenseValid.set(result, result ? 30L * 60L : 2L * 60L, TimeUnit.SECONDS);
} val result = musicService.getMusicFolders(refresh)
return result; cachedMusicFolders.set(result)
}
return result
@Override }
public List<MusicFolder> getMusicFolders(boolean refresh) throws Exception
{ @Throws(Exception::class)
checkSettingsChanged(); override fun getIndexes(musicFolderId: String?, refresh: Boolean): Indexes {
if (refresh) checkSettingsChanged()
{ if (refresh) {
cachedMusicFolders.clear(); cachedIndexes.clear()
} cachedMusicFolders.clear()
List<MusicFolder> result = cachedMusicFolders.get(); cachedMusicDirectories.clear()
if (result == null) }
{ var result = cachedIndexes.get()
result = musicService.getMusicFolders(refresh); if (result == null) {
cachedMusicFolders.set(result); result = musicService.getIndexes(musicFolderId, refresh)
} cachedIndexes.set(result)
return result; }
} return result
}
@Override
public Indexes getIndexes(String musicFolderId, boolean refresh) throws Exception @Throws(Exception::class)
{ override fun getArtists(refresh: Boolean): Indexes {
checkSettingsChanged(); checkSettingsChanged()
if (refresh) if (refresh) {
{ cachedArtists.clear()
cachedIndexes.clear();
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
}
Indexes result = cachedIndexes.get();
if (result == null)
{
result = musicService.getIndexes(musicFolderId, refresh);
cachedIndexes.set(result);
}
return result;
}
@Override
public Indexes getArtists(boolean refresh) throws Exception
{
checkSettingsChanged();
if (refresh)
{
cachedArtists.clear();
}
Indexes result = cachedArtists.get();
if (result == null)
{
result = musicService.getArtists(refresh);
cachedArtists.set(result);
}
return result;
}
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh) throws Exception
{
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getMusicDirectory(id, name, refresh);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(id, cache);
} }
return dir; var result = cachedArtists.get()
if (result == null) {
result = musicService.getArtists(refresh)
cachedArtists.set(result)
} }
return result
@Override
public MusicDirectory getArtist(String id, String name, boolean refresh) throws Exception
{
checkSettingsChanged();
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedArtist.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null)
{
dir = musicService.getArtist(id, name, refresh);
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(), TimeUnit.SECONDS);
cache.set(dir);
cachedArtist.put(id, cache);
}
return dir;
} }
@Override @Throws(Exception::class)
public MusicDirectory getAlbum(String id, String name, boolean refresh) throws Exception override fun getMusicDirectory(id: String, name: String?, refresh: Boolean): MusicDirectory {
{ checkSettingsChanged()
checkSettingsChanged(); var cache = if (refresh) null else cachedMusicDirectories[id]
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedAlbum.get(id); var dir = cache?.get()
MusicDirectory dir = cache == null ? null : cache.get(); if (dir == null) {
if (dir == null) dir = musicService.getMusicDirectory(id, name, refresh)
{ cache = TimeLimitedCache(
dir = musicService.getAlbum(id, name, refresh); Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(), TimeUnit.SECONDS); )
cache.set(dir); cache.set(dir)
cachedAlbum.put(id, cache); cachedMusicDirectories.put(id, cache)
} }
return dir; return dir
} }
@Override @Throws(Exception::class)
public SearchResult search(SearchCriteria criteria) throws Exception override fun getArtist(id: String, name: String?, refresh: Boolean): MusicDirectory {
{ checkSettingsChanged()
return musicService.search(criteria); var cache = if (refresh) null else cachedArtist[id]
var dir = cache?.get()
if (dir == null) {
dir = musicService.getArtist(id, name, refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedArtist.put(id, cache)
} }
return dir
@Override
public MusicDirectory getPlaylist(String id, String name) throws Exception
{
return musicService.getPlaylist(id, name);
} }
@Override @Throws(Exception::class)
public List<PodcastsChannel> getPodcastsChannels(boolean refresh) throws Exception { override fun getAlbum(id: String, name: String?, refresh: Boolean): MusicDirectory {
checkSettingsChanged(); checkSettingsChanged()
List<PodcastsChannel> result = refresh ? null : cachedPodcastsChannels.get(); var cache = if (refresh) null else cachedAlbum[id]
if (result == null) var dir = cache?.get()
{ if (dir == null) {
result = musicService.getPodcastsChannels(refresh); dir = musicService.getAlbum(id, name, refresh)
cachedPodcastsChannels.set(result); cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedAlbum.put(id, cache)
} }
return result; return dir
} }
@Override @Throws(Exception::class)
public MusicDirectory getPodcastEpisodes(String podcastChannelId) throws Exception { override fun search(criteria: SearchCriteria): SearchResult? {
return musicService.getPodcastEpisodes(podcastChannelId); return musicService.search(criteria)
} }
@Throws(Exception::class)
override fun getPlaylist(id: String, name: String): MusicDirectory {
return musicService.getPlaylist(id, name)
}
@Override @Throws(Exception::class)
public List<Playlist> getPlaylists(boolean refresh) throws Exception override fun getPodcastsChannels(refresh: Boolean): List<PodcastsChannel> {
{ checkSettingsChanged()
checkSettingsChanged(); var result = if (refresh) null else cachedPodcastsChannels.get()
List<Playlist> result = refresh ? null : cachedPlaylists.get(); if (result == null) {
if (result == null) result = musicService.getPodcastsChannels(refresh)
{ cachedPodcastsChannels.set(result)
result = musicService.getPlaylists(refresh);
cachedPlaylists.set(result);
} }
return result; return result
} }
@Override @Throws(Exception::class)
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries) throws Exception override fun getPodcastEpisodes(podcastChannelId: String?): MusicDirectory? {
{ return musicService.getPodcastEpisodes(podcastChannelId)
cachedPlaylists.clear();
musicService.createPlaylist(id, name, entries);
} }
@Override @Throws(Exception::class)
public void deletePlaylist(String id) throws Exception override fun getPlaylists(refresh: Boolean): List<Playlist> {
{ checkSettingsChanged()
musicService.deletePlaylist(id); var result = if (refresh) null else cachedPlaylists.get()
if (result == null) {
result = musicService.getPlaylists(refresh)
cachedPlaylists.set(result)
} }
return result
@Override
public void updatePlaylist(String id, String name, String comment, boolean pub) throws Exception
{
musicService.updatePlaylist(id, name, comment, pub);
} }
@Override @Throws(Exception::class)
public Lyrics getLyrics(String artist, String title) throws Exception override fun createPlaylist(id: String, name: String, entries: List<MusicDirectory.Entry>) {
{ cachedPlaylists.clear()
return musicService.getLyrics(artist, title); musicService.createPlaylist(id, name, entries)
} }
@Override @Throws(Exception::class)
public void scrobble(String id, boolean submission) throws Exception override fun deletePlaylist(id: String) {
{ musicService.deletePlaylist(id)
musicService.scrobble(id, submission);
} }
@Override @Throws(Exception::class)
public MusicDirectory getAlbumList(String type, int size, int offset, String musicFolderId) throws Exception override fun updatePlaylist(id: String, name: String?, comment: String?, pub: Boolean) {
{ musicService.updatePlaylist(id, name, comment, pub)
return musicService.getAlbumList(type, size, offset, musicFolderId);
} }
@Override @Throws(Exception::class)
public MusicDirectory getAlbumList2(String type, int size, int offset, String musicFolderId) throws Exception override fun getLyrics(artist: String, title: String): Lyrics? {
{ return musicService.getLyrics(artist, title)
return musicService.getAlbumList2(type, size, offset, musicFolderId);
} }
@Override @Throws(Exception::class)
public MusicDirectory getRandomSongs(int size) throws Exception override fun scrobble(id: String, submission: Boolean) {
{ musicService.scrobble(id, submission)
return musicService.getRandomSongs(size);
} }
@Override @Throws(Exception::class)
public SearchResult getStarred() throws Exception override fun getAlbumList(
{ type: String,
return musicService.getStarred(); size: Int,
offset: Int,
musicFolderId: String?
): MusicDirectory {
return musicService.getAlbumList(type, size, offset, musicFolderId)
} }
@Override @Throws(Exception::class)
public SearchResult getStarred2() throws Exception override fun getAlbumList2(
{ type: String,
return musicService.getStarred2(); size: Int,
offset: Int,
musicFolderId: String?
): MusicDirectory {
return musicService.getAlbumList2(type, size, offset, musicFolderId)
} }
@Override @Throws(Exception::class)
public Bitmap getCoverArt(MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality) throws Exception override fun getRandomSongs(size: Int): MusicDirectory {
{ return musicService.getRandomSongs(size)
return musicService.getCoverArt(entry, size, saveToFile, highQuality);
} }
@Override @Throws(Exception::class)
public Pair<InputStream, Boolean> getDownloadInputStream(MusicDirectory.Entry song, long offset, int maxBitrate) throws Exception override fun getStarred(): SearchResult = musicService.getStarred()
{
return musicService.getDownloadInputStream(song, offset, maxBitrate);
}
@Override @Throws(Exception::class)
public String getVideoUrl(String id, boolean useFlash) throws Exception override fun getStarred2(): SearchResult = musicService.getStarred2()
{
return musicService.getVideoUrl(id, useFlash);
}
@Override @Throws(Exception::class)
public JukeboxStatus updateJukeboxPlaylist(List<String> ids) throws Exception override fun getCoverArt(
{ entry: MusicDirectory.Entry?,
return musicService.updateJukeboxPlaylist(ids); size: Int,
saveToFile: Boolean,
highQuality: Boolean
): Bitmap? {
return musicService.getCoverArt(entry, size, saveToFile, highQuality)
} }
@Override @Throws(Exception::class)
public JukeboxStatus skipJukebox(int index, int offsetSeconds) throws Exception override fun getDownloadInputStream(
{ song: MusicDirectory.Entry,
return musicService.skipJukebox(index, offsetSeconds); offset: Long,
maxBitrate: Int
): Pair<InputStream, Boolean> {
return musicService.getDownloadInputStream(song, offset, maxBitrate)
} }
@Override @Throws(Exception::class)
public JukeboxStatus stopJukebox() throws Exception override fun getVideoUrl(id: String, useFlash: Boolean): String? {
{ return musicService.getVideoUrl(id, useFlash)
return musicService.stopJukebox();
} }
@Override @Throws(Exception::class)
public JukeboxStatus startJukebox() throws Exception override fun updateJukeboxPlaylist(ids: List<String>?): JukeboxStatus {
{ return musicService.updateJukeboxPlaylist(ids)
return musicService.startJukebox();
} }
@Override @Throws(Exception::class)
public JukeboxStatus getJukeboxStatus() throws Exception override fun skipJukebox(index: Int, offsetSeconds: Int): JukeboxStatus {
{ return musicService.skipJukebox(index, offsetSeconds)
return musicService.getJukeboxStatus();
} }
@Override @Throws(Exception::class)
public JukeboxStatus setJukeboxGain(float gain) throws Exception override fun stopJukebox(): JukeboxStatus {
{ return musicService.stopJukebox()
return musicService.setJukeboxGain(gain);
} }
private void checkSettingsChanged() @Throws(Exception::class)
{ override fun startJukebox(): JukeboxStatus {
String newUrl = activeServerProvider.getValue().getRestUrl(null); return musicService.startJukebox()
String newFolderId = activeServerProvider.getValue().getActiveServer().getMusicFolderId();
if (!Util.equals(newUrl, restUrl) || !Util.equals(cachedMusicFolderId,newFolderId))
{
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
cachedLicenseValid.clear();
cachedIndexes.clear();
cachedPlaylists.clear();
cachedGenres.clear();
cachedAlbum.clear();
cachedArtist.clear();
cachedUserInfo.clear();
restUrl = newUrl;
cachedMusicFolderId = newFolderId;
}
} }
@Override @Throws(Exception::class)
public void star(String id, String albumId, String artistId) throws Exception override fun getJukeboxStatus(): JukeboxStatus = musicService.getJukeboxStatus()
{
musicService.star(id, albumId, artistId);
}
@Override @Throws(Exception::class)
public void unstar(String id, String albumId, String artistId) throws Exception override fun setJukeboxGain(gain: Float): JukeboxStatus {
{ return musicService.setJukeboxGain(gain)
musicService.unstar(id, albumId, artistId);
} }
@Override private fun checkSettingsChanged() {
public void setRating(String id, int rating) throws Exception val newUrl = activeServerProvider.value.getRestUrl(null)
{ val newFolderId = activeServerProvider.value.getActiveServer().musicFolderId
musicService.setRating(id, rating); if (!Util.equals(newUrl, restUrl) || !Util.equals(cachedMusicFolderId, newFolderId)) {
cachedMusicFolders.clear()
cachedMusicDirectories.clear()
cachedLicenseValid.clear()
cachedIndexes.clear()
cachedPlaylists.clear()
cachedGenres.clear()
cachedAlbum.clear()
cachedArtist.clear()
cachedUserInfo.clear()
restUrl = newUrl
cachedMusicFolderId = newFolderId
} }
@Override
public List<Genre> getGenres(boolean refresh) throws Exception
{
checkSettingsChanged();
if (refresh)
{
cachedGenres.clear();
} }
List<Genre> result = cachedGenres.get();
if (result == null) @Throws(Exception::class)
{ override fun star(id: String?, albumId: String?, artistId: String?) {
result = musicService.getGenres(refresh); musicService.star(id, albumId, artistId)
cachedGenres.set(result);
} }
Collections.sort(result, new Comparator<Genre>() @Throws(Exception::class)
{ override fun unstar(id: String?, albumId: String?, artistId: String?) {
@Override musicService.unstar(id, albumId, artistId)
public int compare(Genre genre, Genre genre2)
{
return genre.getName().compareToIgnoreCase(genre2.getName());
} }
});
return result; @Throws(Exception::class)
override fun setRating(id: String, rating: Int) {
musicService.setRating(id, rating)
} }
@Override @Throws(Exception::class)
public MusicDirectory getSongsByGenre(String genre, int count, int offset) throws Exception override fun getGenres(refresh: Boolean): List<Genre>? {
{ checkSettingsChanged()
return musicService.getSongsByGenre(genre, count, offset); if (refresh) {
cachedGenres.clear()
} }
var result = cachedGenres.get()
@Override if (result == null) {
public List<Share> getShares(boolean refresh) throws Exception result = musicService.getGenres(refresh)
{ cachedGenres.set(result)
return musicService.getShares(refresh);
} }
@Override val sorted = result?.toMutableList()
public List<ChatMessage> getChatMessages(Long since) throws Exception sorted?.sortWith { genre, genre2 ->
{ genre.name.compareTo(
return musicService.getChatMessages(since); genre2.name,
ignoreCase = true
)
} }
return sorted
@Override
public void addChatMessage(String message) throws Exception
{
musicService.addChatMessage(message);
} }
@Override @Throws(Exception::class)
public List<Bookmark> getBookmarks() throws Exception override fun getSongsByGenre(genre: String, count: Int, offset: Int): MusicDirectory {
{ return musicService.getSongsByGenre(genre, count, offset)
return musicService.getBookmarks();
} }
@Override @Throws(Exception::class)
public void deleteBookmark(String id) throws Exception override fun getShares(refresh: Boolean): List<Share> {
{ return musicService.getShares(refresh)
musicService.deleteBookmark(id);
} }
@Override @Throws(Exception::class)
public void createBookmark(String id, int position) throws Exception override fun getChatMessages(since: Long?): List<ChatMessage?>? {
{ return musicService.getChatMessages(since)
musicService.createBookmark(id, position);
} }
@Override @Throws(Exception::class)
public MusicDirectory getVideos(boolean refresh) throws Exception override fun addChatMessage(message: String) {
{ musicService.addChatMessage(message)
checkSettingsChanged(); }
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(Constants.INTENT_EXTRA_NAME_VIDEOS);
MusicDirectory dir = cache == null ? null : cache.get(); @Throws(Exception::class)
override fun getBookmarks(): List<Bookmark?>? = musicService.getBookmarks()
if (dir == null) @Throws(Exception::class)
{ override fun deleteBookmark(id: String) {
dir = musicService.getVideos(refresh); musicService.deleteBookmark(id)
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(), TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(Constants.INTENT_EXTRA_NAME_VIDEOS, cache);
} }
return dir; @Throws(Exception::class)
override fun createBookmark(id: String, position: Int) {
musicService.createBookmark(id, position)
} }
@Override @Throws(Exception::class)
public UserInfo getUser(String username) throws Exception override fun getVideos(refresh: Boolean): MusicDirectory? {
{ checkSettingsChanged()
checkSettingsChanged(); var cache =
if (refresh) null else cachedMusicDirectories[Constants.INTENT_EXTRA_NAME_VIDEOS]
TimeLimitedCache<UserInfo> cache = cachedUserInfo.get(username); var dir = cache?.get()
if (dir == null) {
dir = musicService.getVideos(refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedMusicDirectories.put(Constants.INTENT_EXTRA_NAME_VIDEOS, cache)
}
return dir
}
UserInfo userInfo = cache == null ? null : cache.get(); @Throws(Exception::class)
override fun getUser(username: String): UserInfo {
checkSettingsChanged()
var cache = cachedUserInfo[username]
var userInfo = cache?.get()
if (userInfo == null) {
userInfo = musicService.getUser(username)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
)
cache.set(userInfo)
cachedUserInfo.put(username, cache)
}
return userInfo
}
if (userInfo == null) @Throws(Exception::class)
{ override fun createShare(
userInfo = musicService.getUser(username); ids: List<String>,
cache = new TimeLimitedCache<>(Util.getDirectoryCacheTime(), TimeUnit.SECONDS); description: String?,
cache.set(userInfo); expires: Long?
cachedUserInfo.put(username, cache); ): List<Share> {
return musicService.createShare(ids, description, expires)
} }
return userInfo; @Throws(Exception::class)
override fun deleteShare(id: String) {
musicService.deleteShare(id)
} }
@Override @Throws(Exception::class)
public List<Share> createShare(List<String> ids, String description, Long expires) throws Exception override fun updateShare(id: String, description: String?, expires: Long?) {
{ musicService.updateShare(id, description, expires)
return musicService.createShare(ids, description, expires);
} }
@Override @Throws(Exception::class)
public void deleteShare(String id) throws Exception override fun getAvatar(
{ username: String?,
musicService.deleteShare(id); size: Int,
saveToFile: Boolean,
highQuality: Boolean
): Bitmap? {
return musicService.getAvatar(username, size, saveToFile, highQuality)
} }
@Override companion object {
public void updateShare(String id, String description, Long expires) throws Exception private const val MUSIC_DIR_CACHE_SIZE = 100
{
musicService.updateShare(id, description, expires);
} }
@Override init {
public Bitmap getAvatar(String username, int size, boolean saveToFile, boolean highQuality) throws Exception cachedMusicDirectories = LRUCache(MUSIC_DIR_CACHE_SIZE)
{ cachedArtist = LRUCache(MUSIC_DIR_CACHE_SIZE)
return musicService.getAvatar(username, size, saveToFile, highQuality); cachedAlbum = LRUCache(MUSIC_DIR_CACHE_SIZE)
cachedUserInfo = LRUCache(MUSIC_DIR_CACHE_SIZE)
} }
} }

View File

@ -1,151 +1,192 @@
/* /*
This file is part of Subsonic. * MusicService.kt
* Copyright (C) 2009-2021 Ultrasonic developers
Subsonic is free software: you can redistribute it and/or modify *
it under the terms of the GNU General Public License as published by * Distributed under terms of the GNU GPLv3 license.
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; package org.moire.ultrasonic.service
import android.graphics.Bitmap; import android.graphics.Bitmap
import org.moire.ultrasonic.domain.Bookmark
import org.moire.ultrasonic.domain.ChatMessage
import org.moire.ultrasonic.domain.Genre
import org.moire.ultrasonic.domain.Indexes
import org.moire.ultrasonic.domain.JukeboxStatus
import org.moire.ultrasonic.domain.Lyrics
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.domain.Playlist
import org.moire.ultrasonic.domain.PodcastsChannel
import org.moire.ultrasonic.domain.SearchCriteria
import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.domain.Share
import org.moire.ultrasonic.domain.UserInfo
import java.io.InputStream
import org.moire.ultrasonic.domain.Bookmark; interface MusicService {
import org.moire.ultrasonic.domain.ChatMessage; @Throws(Exception::class)
import org.moire.ultrasonic.domain.Genre; fun ping()
import org.moire.ultrasonic.domain.Indexes;
import org.moire.ultrasonic.domain.JukeboxStatus;
import org.moire.ultrasonic.domain.Lyrics;
import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.domain.MusicFolder;
import org.moire.ultrasonic.domain.Playlist;
import org.moire.ultrasonic.domain.PodcastsChannel;
import org.moire.ultrasonic.domain.SearchCriteria;
import org.moire.ultrasonic.domain.SearchResult;
import org.moire.ultrasonic.domain.Share;
import org.moire.ultrasonic.domain.UserInfo;
import java.io.InputStream; @Throws(Exception::class)
import java.util.List; fun isLicenseValid(): Boolean
import kotlin.Pair; @Throws(Exception::class)
fun getGenres(refresh: Boolean): List<Genre>?
/** @Throws(Exception::class)
* @author Sindre Mehus fun star(id: String?, albumId: String?, artistId: String?)
*/
public interface MusicService
{
void ping() throws Exception; @Throws(Exception::class)
fun unstar(id: String?, albumId: String?, artistId: String?)
boolean isLicenseValid() throws Exception; @Throws(Exception::class)
fun setRating(id: String, rating: Int)
List<Genre> getGenres(boolean refresh) throws Exception; @Throws(Exception::class)
fun getMusicFolders(refresh: Boolean): List<MusicFolder>
void star(String id, String albumId, String artistId) throws Exception; @Throws(Exception::class)
fun getIndexes(musicFolderId: String?, refresh: Boolean): Indexes
void unstar(String id, String albumId, String artistId) throws Exception; @Throws(Exception::class)
fun getArtists(refresh: Boolean): Indexes
void setRating(String id, int rating) throws Exception; @Throws(Exception::class)
fun getMusicDirectory(id: String, name: String?, refresh: Boolean): MusicDirectory
List<MusicFolder> getMusicFolders(boolean refresh) throws Exception; @Throws(Exception::class)
fun getArtist(id: String, name: String?, refresh: Boolean): MusicDirectory
Indexes getIndexes(String musicFolderId, boolean refresh) throws Exception; @Throws(Exception::class)
fun getAlbum(id: String, name: String?, refresh: Boolean): MusicDirectory
Indexes getArtists(boolean refresh) throws Exception; @Throws(Exception::class)
fun search(criteria: SearchCriteria): SearchResult?
MusicDirectory getMusicDirectory(String id, String name, boolean refresh) throws Exception; @Throws(Exception::class)
fun getPlaylist(id: String, name: String): MusicDirectory
MusicDirectory getArtist(String id, String name, boolean refresh) throws Exception; @Throws(Exception::class)
fun getPodcastsChannels(refresh: Boolean): List<PodcastsChannel>
MusicDirectory getAlbum(String id, String name, boolean refresh) throws Exception; @Throws(Exception::class)
fun getPlaylists(refresh: Boolean): List<Playlist>
SearchResult search(SearchCriteria criteria) throws Exception; @Throws(Exception::class)
fun createPlaylist(id: String, name: String, entries: List<MusicDirectory.Entry>)
MusicDirectory getPlaylist(String id, String name) throws Exception; @Throws(Exception::class)
fun deletePlaylist(id: String)
List<PodcastsChannel> getPodcastsChannels(boolean refresh) throws Exception; @Throws(Exception::class)
fun updatePlaylist(id: String, name: String?, comment: String?, pub: Boolean)
List<Playlist> getPlaylists(boolean refresh) throws Exception; @Throws(Exception::class)
fun getLyrics(artist: String, title: String): Lyrics?
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries) throws Exception; @Throws(Exception::class)
fun scrobble(id: String, submission: Boolean)
void deletePlaylist(String id) throws Exception; @Throws(Exception::class)
fun getAlbumList(type: String, size: Int, offset: Int, musicFolderId: String?): MusicDirectory
void updatePlaylist(String id, String name, String comment, boolean pub) throws Exception; @Throws(Exception::class)
fun getAlbumList2(
type: String,
size: Int,
offset: Int,
musicFolderId: String?
): MusicDirectory
Lyrics getLyrics(String artist, String title) throws Exception; @Throws(Exception::class)
fun getRandomSongs(size: Int): MusicDirectory
void scrobble(String id, boolean submission) throws Exception; @Throws(Exception::class)
fun getSongsByGenre(genre: String, count: Int, offset: Int): MusicDirectory
MusicDirectory getAlbumList(String type, int size, int offset, String musicFolderId) throws Exception; @Throws(Exception::class)
fun getStarred(): SearchResult
MusicDirectory getAlbumList2(String type, int size, int offset, String musicFolderId) throws Exception; @Throws(Exception::class)
fun getStarred2(): SearchResult
MusicDirectory getRandomSongs(int size) throws Exception; @Throws(Exception::class)
fun getCoverArt(
entry: MusicDirectory.Entry?,
size: Int,
saveToFile: Boolean,
highQuality: Boolean
): Bitmap?
MusicDirectory getSongsByGenre(String genre, int count, int offset) throws Exception; @Throws(Exception::class)
fun getAvatar(username: String?, size: Int, saveToFile: Boolean, highQuality: Boolean): Bitmap?
SearchResult getStarred() throws Exception;
SearchResult getStarred2() throws Exception;
Bitmap getCoverArt(MusicDirectory.Entry entry, int size, boolean saveToFile, boolean highQuality) throws Exception;
Bitmap getAvatar(String username, int size, boolean saveToFile, boolean highQuality) throws Exception;
/** /**
* Return response {@link InputStream} and a {@link Boolean} that indicates if this response is * Return response [InputStream] and a [Boolean] that indicates if this response is
* partial. * partial.
*/ */
Pair<InputStream, Boolean> getDownloadInputStream(MusicDirectory.Entry song, long offset, int maxBitrate) throws Exception; @Throws(Exception::class)
fun getDownloadInputStream(
song: MusicDirectory.Entry,
offset: Long,
maxBitrate: Int
): Pair<InputStream, Boolean>
// TODO: Refactor and remove this call (see RestMusicService implementation) // TODO: Refactor and remove this call (see RestMusicService implementation)
String getVideoUrl(String id, boolean useFlash) throws Exception; @Throws(Exception::class)
fun getVideoUrl(id: String, useFlash: Boolean): String?
JukeboxStatus updateJukeboxPlaylist(List<String> ids) throws Exception; @Throws(Exception::class)
fun updateJukeboxPlaylist(ids: List<String>?): JukeboxStatus
JukeboxStatus skipJukebox(int index, int offsetSeconds) throws Exception; @Throws(Exception::class)
fun skipJukebox(index: Int, offsetSeconds: Int): JukeboxStatus
JukeboxStatus stopJukebox() throws Exception; @Throws(Exception::class)
fun stopJukebox(): JukeboxStatus
JukeboxStatus startJukebox() throws Exception; @Throws(Exception::class)
fun startJukebox(): JukeboxStatus
JukeboxStatus getJukeboxStatus() throws Exception; @Throws(Exception::class)
fun getJukeboxStatus(): JukeboxStatus
JukeboxStatus setJukeboxGain(float gain) throws Exception; @Throws(Exception::class)
fun setJukeboxGain(gain: Float): JukeboxStatus
List<Share> getShares(boolean refresh) throws Exception; @Throws(Exception::class)
fun getShares(refresh: Boolean): List<Share>
List<ChatMessage> getChatMessages(Long since) throws Exception; @Throws(Exception::class)
fun getChatMessages(since: Long?): List<ChatMessage?>?
void addChatMessage(String message) throws Exception; @Throws(Exception::class)
fun addChatMessage(message: String)
List<Bookmark> getBookmarks() throws Exception; @Throws(Exception::class)
fun getBookmarks(): List<Bookmark?>?
void deleteBookmark(String id) throws Exception; @Throws(Exception::class)
fun deleteBookmark(id: String)
void createBookmark(String id, int position) throws Exception; @Throws(Exception::class)
fun createBookmark(id: String, position: Int)
MusicDirectory getVideos(boolean refresh) throws Exception; @Throws(Exception::class)
fun getVideos(refresh: Boolean): MusicDirectory?
UserInfo getUser(String username) throws Exception; @Throws(Exception::class)
fun getUser(username: String): UserInfo
List<Share> createShare(List<String> ids, String description, Long expires) throws Exception; @Throws(Exception::class)
fun createShare(ids: List<String>, description: String?, expires: Long?): List<Share>
void deleteShare(String id) throws Exception; @Throws(Exception::class)
fun deleteShare(id: String)
void updateShare(String id, String description, Long expires) throws Exception; @Throws(Exception::class)
fun updateShare(id: String, description: String?, expires: Long?)
MusicDirectory getPodcastEpisodes(String podcastChannelId) throws Exception; @Throws(Exception::class)
fun getPodcastEpisodes(podcastChannelId: String?): MusicDirectory?
} }

View File

@ -1,35 +1,16 @@
/* /*
This file is part of Subsonic. * OfflineException.kt
* Copyright (C) 2009-2021 Ultrasonic developers
Subsonic is free software: you can redistribute it and/or modify *
it under the terms of the GNU General Public License as published by * Distributed under terms of the GNU GPLv3 license.
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; package org.moire.ultrasonic.service
/** /**
* Thrown by service methods that are not available in offline mode. * Thrown by service methods that are not available in offline mode.
*
* @author Sindre Mehus
* @version $Id$
*/ */
public class OfflineException extends Exception class OfflineException(message: String?) : Exception(message) {
{ companion object {
private static final long serialVersionUID = -4479642294747429444L; private const val serialVersionUID = -4479642294747429444L
public OfflineException(String message)
{
super(message);
} }
} }