- added instructions on how to use the "Spotify for lyrics" feature in
  the README
- added ABI splits in preparation for the f-droid relase
- removed the skrape.it dependency
- fixed bug where the "This song is an instrumental" screen always shows
  after the first time of fetching lyrics from spotify
- properly position title and rotate navigation button icon on topbar for RTL
  languages
- show errors on the lyrics screen
- version 1.0.0
This commit is contained in:
2024-01-19 20:47:36 +02:00
committed by Illusion
parent 92c610a761
commit f5afb3b25c
14 changed files with 151 additions and 104 deletions
@@ -2,14 +2,10 @@ package com.illusionman1212.lyricsgrabbr.data
import android.content.Context
import android.net.Uri
import android.util.Log
import com.illusionman1212.lyricsgrabbr.R
import com.illusionman1212.lyricsgrabbr.data.network.GET
import com.illusionman1212.lyricsgrabbr.data.network.NetworkHelper
import com.illusionman1212.lyricsgrabbr.utils.await
import it.skrape.core.htmlDocument
import it.skrape.selects.ElementNotFoundException
import it.skrape.selects.html5.div
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.jsoup.Jsoup
@@ -56,8 +52,10 @@ class LyricsRepository(private val context: Context) {
GET(url.toString())
).await()
val body = res.body?.string()
if (res.isSuccessful) {
return Pair(json.decodeFromString(SuccessResponse.serializer(), res.body!!.string())
return Pair(json.decodeFromString(SuccessResponse.serializer(), body!!)
.lyrics
.lines.joinToString(separator = "\n") { it.words }, true)
} else {
@@ -70,61 +68,41 @@ class LyricsRepository(private val context: Context) {
}
fun fetchLyricsFromGenius(url: Uri): String {
// TODO: write a custom fetcher for skrape.it to use our OkHttp client
// and get rid of jsoup. Or better yet, maybe skrape.it will be fixed in the future
// and we can just use its built in BrowserFetcher
val doc = Jsoup.connect(url.toString()).userAgent(USER_AGENT).get()
val divs = doc.select("div[data-lyrics-container]")
try {
val lyrics = htmlDocument(doc.toString()) {
// set relaxed for instrumental songs
relaxed = true
val lyrics = StringUtil.borrowBuilder()
findFirst {
div {
withAttributeKey = "data-lyrics-container"
findAll {
this
}.joinToString(separator = "\n") {
val accum = StringUtil.borrowBuilder()
it.element.text()
it.element.traverse(object : NodeVisitor {
override fun head(node: Node, depth: Int) {
if (node is TextNode) {
accum.append(node.text().trim())
// append space here to get proper spacing when there's a <i> tag or other inline text tags
accum.append(" ")
} else if (node is Element) {
if (accum.isNotEmpty() && node.normalName() == "br") {
accum.append("\n")
}
}
}
override fun tail(node: Node, depth: Int) {
// since we append a space after every text node, we only append a newline if
// the last char isn't a space
val lastCharIsWhitespace = accum.isNotEmpty() && accum[accum.length - 1] == ' '
if (node is Element) {
if (node.isBlock && node.nextSibling() is TextNode && !lastCharIsWhitespace) {
accum.append("\n")
}
}
}
})
accum
divs.forEach {
it.traverse(object : NodeVisitor {
override fun head(node: Node, depth: Int) {
if (node is TextNode) {
lyrics.append(node.text().trim())
// append space here to get proper spacing when there's a <i> tag or other inline text tags
lyrics.append(" ")
} else if (node is Element) {
if (lyrics.isNotEmpty() && node.normalName() == "br") {
lyrics.append("\n")
}
}
}.replace("\n\n\n", "\n\n")
}
}
return lyrics
} catch (e: ElementNotFoundException) {
// TODO: relaxed is broken in skrape.it, so we have to catch this exception
return ""
override fun tail(node: Node, depth: Int) {
// since we append a space after every text node, we only append a newline if
// the last char isn't a space
val lastCharIsWhitespace = lyrics.isNotEmpty() && lyrics[lyrics.length - 1] == ' '
if (node is Element) {
if (node.isBlock && node.nextSibling() is TextNode && !lastCharIsWhitespace) {
lyrics.append("\n")
}
}
}
})
lyrics.append("\n")
}
return lyrics.toString().replace("\n\n\n", "\n\n")
}
companion object {