package link.roadio.riff.player.storage import link.roadio.riff.indexer.core.media.MediaId import link.roadio.riff.userstate.model.MediaKeyModel import link.roadio.riff.userstate.model.ObjectKeyModel // Catalog rows use unsigned hexadecimal; decimal parsing silently changes numeric-only IDs // and rejects ordinary XXH3 values. Preserve the same key at queue/bookmark and reaction edges. internal fun titleIdFromKey(key: String): Long? = key .takeIf { it.startsWith("album:") } ?.substringAfter(':') ?.toULongOrNull(16) ?.toLong() internal fun albumKey(id: Long): String = "album:${id.toULong().toString(16)}" internal fun objectKey(text: String): ObjectKeyModel { val type = text.substringBefore(':') val value = text.substringAfter(':') return if (type == "track" ) { ObjectKeyModel(mediaId = parseMedia(value).key()) } else { ObjectKeyModel( kind = listOf("track", "album", "artist", "genre", "folder").indexOf(type).also { require(it in 1..4) }, objectId = value.toULong(16).toLong(), ) } } internal fun textKey(key: ObjectKeyModel) = if (key.kind == 0 ) { "track:${checkNotNull(key.mediaId).media().hex()}" } else { "${listOf("track", "album", "artist", "genre", "folder")[key.kind]}:${checkNotNull(key.objectId).toULong().toString(16)}" } internal fun parseMedia(text: String): MediaId { require(text.length == 16 || text.length == 32) return MediaId( text.take(16).toULong(16).toLong(), if (text.length == 32 ) { text.takeLast(16).toULong(16).toLong() } else { 0 }, text.length == 32, ) } internal fun MediaId.key() = MediaKeyModel(high, if (lowPresent) low else 0, lowPresent) internal fun MediaKeyModel.media() = MediaId(hi, lo, loPresent)