fix(download): stop crashing native finalization on Android regex

Android's regex engine rejects Pattern.UNICODE_CHARACTER_CLASS, so NativeFinalizationPolicy failed to initialize and every native download crashed while writing metadata. List Unicode spaces explicitly and cover the separator with a device test.
This commit is contained in:
zarzet committed 2026-10-02 01:24:26 +07:00
1 parent ceb98eb766
commit fbf479c102
3 files changed
+43 -7

No files matched your search

@@ -0,0 +1,30 @@
package com.zarz.spotiflac
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
/**
* Runs on Android's own regex engine: the JVM accepts regex flags that the
* device rejects when NativeFinalizationPolicy initializes during finalization.
*/
@RunWith(AndroidJUnit4::class)
class NativeFinalizationPolicyDeviceTest {
@Test
fun primaryArtistSeparatorCompilesAndSplitsOnDevice() {
for ((input, expected) in listOf(
"Calle 24, Chino Pacas" to "Calle 24",
"Artist A feat. Artist B" to "Artist A",
"Artist A\u00A0feat.\u00A0Artist B" to "Artist A",
"Artist A\u3000x\u3000Artist B" to "Artist A",
"Malcolm X" to "Malcolm X",
)) {
assertEquals(input, expected, NativeFinalizationPolicy.artistTagValue(input, "primary"))
}
assertEquals(
"Artist A, Artist B",
NativeFinalizationPolicy.artistTagValue("Artist A, Artist B", "joined"),
)
}
}
@@ -1,7 +1,6 @@
package com.zarz.spotiflac
import java.util.Locale
import java.util.regex.Pattern
import kotlin.math.roundToInt
/**
@@ -374,12 +373,17 @@ internal object NativeFinalizationPolicy {
?: ""
}
// Same separator set as the Rust writer and Dart's primaryArtistTagValue;
// Unicode classes keep \s aligned with their whitespace handling.
private val primaryArtistSeparator = Pattern.compile(
"\\s*[,;&]\\s*|\\s+x\\s+|\\s+(?:feat(?:uring)?|ft|with)\\.?(?:\\s+|$)",
Pattern.CASE_INSENSITIVE or Pattern.UNICODE_CHARACTER_CLASS,
).toRegex()
// Same separator set as the Rust writer and Dart's primaryArtistTagValue.
// Android's regex engine rejects Pattern.UNICODE_CHARACTER_CLASS when this
// object initializes, so Unicode spaces are listed explicitly instead.
private const val PRIMARY_ARTIST_SPACE = "[\\s\\p{Z}]"
private val primaryArtistSeparator = Regex(
"$PRIMARY_ARTIST_SPACE*[,;&]$PRIMARY_ARTIST_SPACE*" +
"|$PRIMARY_ARTIST_SPACE+x$PRIMARY_ARTIST_SPACE+" +
"|$PRIMARY_ARTIST_SPACE+(?:feat(?:uring)?|ft|with)\\.?" +
"(?:$PRIMARY_ARTIST_SPACE+|$)",
RegexOption.IGNORE_CASE,
)
/**
* Artist tag value for [mode]. Only "primary" changes the value: the first
@@ -21,6 +21,8 @@ class NativeFinalizationPolicyTest {
"Artist A with Artist B" to "Artist A",
"Artist A x Artist B" to "Artist A",
"Artist A X Artist B" to "Artist A",
"Artist A\u00A0feat.\u00A0Artist B" to "Artist A",
"Artist A\u3000x\u3000Artist B" to "Artist A",
" , Artist A, Artist B" to "Artist A",
"Malcolm X" to "Malcolm X",
"Artist Without Fear" to "Artist Without Fear",