musikr: document cache api
This commit is contained in:
parent
f213c21225
commit
a9707cbb33
2 changed files with 98 additions and 0 deletions
|
@ -22,28 +22,100 @@ import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.Properties
|
import org.oxycblt.musikr.metadata.Properties
|
||||||
import org.oxycblt.musikr.tag.parse.ParsedTags
|
import org.oxycblt.musikr.tag.parse.ParsedTags
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An immutable repository for cached song metadata.
|
||||||
|
*
|
||||||
|
* Since file opening and metadata extraction sends to be quite slow on Android, a cache allows
|
||||||
|
* up-to-date metadata to be read from a local database, which tends to be far faster.
|
||||||
|
*
|
||||||
|
* This is a read-only interface for reading cached metadata and isn't expected by Musikr's public
|
||||||
|
* API, however there might be some use in external cache diagnostics by the client. For writing,
|
||||||
|
* see [MutableCache].
|
||||||
|
*/
|
||||||
interface Cache {
|
interface Cache {
|
||||||
|
/**
|
||||||
|
* Read a [CachedSong] corresponding to the given [file] from the cache. This can result in
|
||||||
|
* several outcomes represented by [CacheResult].
|
||||||
|
*
|
||||||
|
* @param file the [DeviceFile] to read from the cache
|
||||||
|
* @return a [CacheResult] representing the result of the operation.
|
||||||
|
*/
|
||||||
suspend fun read(file: DeviceFile): CacheResult
|
suspend fun read(file: DeviceFile): CacheResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mutable repository for cached song metadata.
|
||||||
|
*
|
||||||
|
* Since file opening and metadata extraction sends to be quite slow on Android, a cache allows
|
||||||
|
* up-to-date metadata to be saved to a local database, which tends to be far faster.
|
||||||
|
*
|
||||||
|
* This is required by Musikr's public API for proper function.
|
||||||
|
*/
|
||||||
interface MutableCache : Cache {
|
interface MutableCache : Cache {
|
||||||
|
/**
|
||||||
|
* Write a [CachedSong] to the cache.
|
||||||
|
*
|
||||||
|
* This should commit the metadata to the repository in such a way that it can be retrieved
|
||||||
|
* later by [read] using only the [DeviceFile].
|
||||||
|
*
|
||||||
|
* @param cachedSong the [CachedSong] to write to the cache
|
||||||
|
*/
|
||||||
suspend fun write(cachedSong: CachedSong)
|
suspend fun write(cachedSong: CachedSong)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup the cache by removing all [CachedSong]s that are not in the provided [excluding]
|
||||||
|
* list.
|
||||||
|
*
|
||||||
|
* This is paramount for any long-term persistence to maintain correct Date added metadata and
|
||||||
|
* to avoid having space taken up by useless data.
|
||||||
|
*
|
||||||
|
* @param excluding a list of [CachedSong]s to exclude from cleanup, analogous to the library
|
||||||
|
* created by the loader this cache is used with.
|
||||||
|
*/
|
||||||
suspend fun cleanup(excluding: List<CachedSong>)
|
suspend fun cleanup(excluding: List<CachedSong>)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A cached song entry containing the data needed by the rest of the loader. */
|
||||||
data class CachedSong(
|
data class CachedSong(
|
||||||
|
/** The file this song corresponds to. */
|
||||||
val file: DeviceFile,
|
val file: DeviceFile,
|
||||||
|
/** The properties of the song. */
|
||||||
val properties: Properties,
|
val properties: Properties,
|
||||||
|
/** The parsed tags of the song. */
|
||||||
val tags: ParsedTags,
|
val tags: ParsedTags,
|
||||||
|
/**
|
||||||
|
* The cover ID of the song. Should be understandable by the [org.oxycblt.musikr.covers.Covers]
|
||||||
|
* implementation used.
|
||||||
|
*/
|
||||||
val coverId: String?,
|
val coverId: String?,
|
||||||
|
/**
|
||||||
|
* The time the song was added to the cache. Used for date added values. Should not be used for
|
||||||
|
* cleanup since it is unlikely to be monotonic.
|
||||||
|
*/
|
||||||
val addedMs: Long
|
val addedMs: Long
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/** A result of a cache lookup. */
|
||||||
sealed interface CacheResult {
|
sealed interface CacheResult {
|
||||||
|
/**
|
||||||
|
* A cache entry was found.
|
||||||
|
*
|
||||||
|
* @param song the [CachedSong] that was found.
|
||||||
|
*/
|
||||||
data class Hit(val song: CachedSong) : CacheResult
|
data class Hit(val song: CachedSong) : CacheResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache entry was not found.
|
||||||
|
*
|
||||||
|
* @param file the [DeviceFile] that could not be found in the cache.
|
||||||
|
*/
|
||||||
data class Miss(val file: DeviceFile) : CacheResult
|
data class Miss(val file: DeviceFile) : CacheResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cache entry was found, but it's out of date compared to the [file] given.
|
||||||
|
*
|
||||||
|
* @param file the [DeviceFile] that was found in the cache.
|
||||||
|
* @param addedMs the time the song was added to the cache.
|
||||||
|
*/
|
||||||
data class Stale(val file: DeviceFile, val addedMs: Long) : CacheResult
|
data class Stale(val file: DeviceFile, val addedMs: Long) : CacheResult
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,11 @@ import org.oxycblt.musikr.fs.device.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.Properties
|
import org.oxycblt.musikr.metadata.Properties
|
||||||
import org.oxycblt.musikr.tag.parse.ParsedTags
|
import org.oxycblt.musikr.tag.parse.ParsedTags
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An immutable [Cache] backed by an internal Room database.
|
||||||
|
*
|
||||||
|
* Create an instance with [from].
|
||||||
|
*/
|
||||||
class DBCache private constructor(private val readDao: CacheReadDao) : Cache {
|
class DBCache private constructor(private val readDao: CacheReadDao) : Cache {
|
||||||
override suspend fun read(file: DeviceFile): CacheResult {
|
override suspend fun read(file: DeviceFile): CacheResult {
|
||||||
val dbSong = readDao.selectSong(file.uri.toString()) ?: return CacheResult.Miss(file)
|
val dbSong = readDao.selectSong(file.uri.toString()) ?: return CacheResult.Miss(file)
|
||||||
|
@ -66,12 +71,25 @@ class DBCache private constructor(private val readDao: CacheReadDao) : Cache {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
/**
|
||||||
|
* Create a new instance of [DBCache] from the given [context]. This instance should be a
|
||||||
|
* singleton, since it implicitly holds a Room database. As a result, you should only create
|
||||||
|
* EITHER a [DBCache] or a [MutableDBCache].
|
||||||
|
*
|
||||||
|
* @param context The context to use to create the Room database.
|
||||||
|
* @return A new instance of [DBCache].
|
||||||
|
*/
|
||||||
fun from(context: Context) = from(CacheDatabase.from(context))
|
fun from(context: Context) = from(CacheDatabase.from(context))
|
||||||
|
|
||||||
internal fun from(db: CacheDatabase) = DBCache(db.readDao())
|
internal fun from(db: CacheDatabase) = DBCache(db.readDao())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A mutable [Cache] backed by an internal Room database.
|
||||||
|
*
|
||||||
|
* Create an instance with [from].
|
||||||
|
*/
|
||||||
class MutableDBCache
|
class MutableDBCache
|
||||||
private constructor(private val inner: DBCache, private val writeDao: CacheWriteDao) :
|
private constructor(private val inner: DBCache, private val writeDao: CacheWriteDao) :
|
||||||
MutableCache {
|
MutableCache {
|
||||||
|
@ -116,6 +134,14 @@ private constructor(private val inner: DBCache, private val writeDao: CacheWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
/**
|
||||||
|
* Create a new instance of [MutableDBCache] from the given [context]. This instance should
|
||||||
|
* be a singleton, since it implicitly holds a Room database. As a result, you should only
|
||||||
|
* create EITHER a [DBCache] or a [MutableDBCache].
|
||||||
|
*
|
||||||
|
* @param context The context to use to create the Room database.
|
||||||
|
* @return A new instance of [MutableDBCache].
|
||||||
|
*/
|
||||||
fun from(context: Context): MutableDBCache {
|
fun from(context: Context): MutableDBCache {
|
||||||
val db = CacheDatabase.from(context)
|
val db = CacheDatabase.from(context)
|
||||||
return MutableDBCache(DBCache.from(db), db.writeDao())
|
return MutableDBCache(DBCache.from(db), db.writeDao())
|
||||||
|
|
Loading…
Reference in a new issue