music: make string hashing more resillient
Make string hashing a custom-made function that actually outputs to a long. This prevents overflows from causing a collision.
This commit is contained in:
parent
fe16ffb5bf
commit
f93d5f1a69
6 changed files with 25 additions and 53 deletions
|
@ -21,7 +21,6 @@ package org.oxycblt.auxio.music
|
|||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import org.oxycblt.auxio.BuildConfig
|
||||
|
@ -112,11 +111,9 @@ data class Song(
|
|||
) : Music() {
|
||||
override val id: Long
|
||||
get() {
|
||||
var result = rawName.lowercase().hashCode().toLong()
|
||||
result = 31 * result + album.rawName.lowercase().hashCode()
|
||||
result =
|
||||
31 * result +
|
||||
(album.artist.rawName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode()
|
||||
var result = rawName.toMusicId()
|
||||
result = 31 * result + album.rawName.toMusicId()
|
||||
result = 31 * result + album.artist.rawName.toMusicId()
|
||||
result = 31 * result + (track ?: 0)
|
||||
result = 31 * result + (disc ?: 0)
|
||||
result = 31 * result + durationMs
|
||||
|
@ -156,15 +153,14 @@ data class Song(
|
|||
/** Internal field. Do not use. */
|
||||
val _albumGroupingId: Long
|
||||
get() {
|
||||
var result =
|
||||
(_artistGroupingName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode().toLong()
|
||||
result = 31 * result + _albumName.lowercase().hashCode()
|
||||
var result = _artistGroupingName.toMusicId()
|
||||
result = 31 * result + _albumName.toMusicId()
|
||||
return result
|
||||
}
|
||||
|
||||
/** Internal field. Do not use. */
|
||||
val _genreGroupingId: Long
|
||||
get() = (_genreName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode().toLong()
|
||||
get() = _genreName.toMusicId()
|
||||
|
||||
/** Internal field. Do not use. */
|
||||
val _artistGroupingName: String?
|
||||
|
@ -228,9 +224,8 @@ data class Album(
|
|||
|
||||
override val id: Long
|
||||
get() {
|
||||
var result = rawName.lowercase().hashCode().toLong()
|
||||
result =
|
||||
31 * result + (artist.rawName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode()
|
||||
var result = rawName.toMusicId()
|
||||
result = 31 * result + artist.rawName.toMusicId()
|
||||
result = 31 * result + (date?.year ?: 0)
|
||||
return result
|
||||
}
|
||||
|
@ -244,7 +239,7 @@ data class Album(
|
|||
|
||||
/** Internal field. Do not use. */
|
||||
val _artistGroupingId: Long
|
||||
get() = (_artistGroupingName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode().toLong()
|
||||
get() = _artistGroupingName.toMusicId()
|
||||
|
||||
/** Internal field. Do not use. */
|
||||
val _isMissingArtist: Boolean
|
||||
|
@ -273,7 +268,7 @@ data class Artist(
|
|||
}
|
||||
|
||||
override val id: Long
|
||||
get() = (rawName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode().toLong()
|
||||
get() = rawName.toMusicId()
|
||||
|
||||
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_artist)
|
||||
|
||||
|
@ -294,11 +289,24 @@ data class Genre(override val rawName: String?, override val songs: List<Song>)
|
|||
get() = rawName
|
||||
|
||||
override val id: Long
|
||||
get() = (rawName?.lowercase() ?: MediaStore.UNKNOWN_STRING).hashCode().toLong()
|
||||
get() = rawName.toMusicId()
|
||||
|
||||
override fun resolveName(context: Context) = rawName ?: context.getString(R.string.def_genre)
|
||||
}
|
||||
|
||||
private fun String?.toMusicId(): Long {
|
||||
if (this == null) {
|
||||
// Pre-calculated hash of MediaStore.UNKNOWN_STRING
|
||||
return 54493231833456
|
||||
}
|
||||
|
||||
var result = 0L
|
||||
for (ch in lowercase()) {
|
||||
result = 31 * result + ch.code
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* An ISO-8601/RFC 3339 Date.
|
||||
*
|
||||
|
|
|
@ -538,7 +538,7 @@ class PlaybackStateManager private constructor() {
|
|||
/** Called when the queue has changed in a way that does not change the index or song. */
|
||||
fun onQueueChanged(queue: List<Song>) {}
|
||||
|
||||
/** Called when the queue and index has changed, but the song has not changed.. */
|
||||
/** Called when the queue and index has changed, but the song has not changed. */
|
||||
fun onQueueReworked(index: Int, queue: List<Song>) {}
|
||||
|
||||
/** Called when playback is changed completely, with a new index, queue, and parent. */
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
This is part of a stopgap animation used by QueueFragment until it's fully integrated
|
||||
into PlaybackLayout.
|
||||
-->
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromYDelta="100%"
|
||||
android:interpolator="@android:interpolator/decelerate_quint"
|
||||
android:toYDelta="0%" />
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
This is part of a stopgap animation used by QueueFragment until it's fully integrated
|
||||
into PlaybackLayout.
|
||||
-->
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromAlpha="1"
|
||||
android:interpolator="@android:interpolator/decelerate_quint"
|
||||
android:toAlpha="0" />
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
This is part of a stopgap animation used by QueueFragment until it's fully integrated
|
||||
into PlaybackLayout.
|
||||
-->
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromAlpha="0"
|
||||
android:interpolator="@android:interpolator/decelerate_quint"
|
||||
android:toAlpha="1" />
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
This is part of a stopgap animation used by QueueFragment until it's fully integrated
|
||||
into PlaybackLayout.
|
||||
-->
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="500"
|
||||
android:fromYDelta="0%"
|
||||
android:interpolator="@android:interpolator/decelerate_quint"
|
||||
android:toYDelta="100%" />
|
Loading…
Reference in a new issue