refactor(android): move link metadata extraction to Unfurl

Crux is doing major changes for no good reason
This commit is contained in:
Harsh Shandilya 2023-07-17 14:58:30 +05:30
parent 37f42dc107
commit 0359860b82
7 changed files with 41 additions and 43 deletions

View file

@ -71,7 +71,6 @@ dependencies {
implementation(libs.androidx.work.runtime) implementation(libs.androidx.work.runtime)
implementation(libs.coil) implementation(libs.coil)
implementation(libs.copydown) implementation(libs.copydown)
implementation(libs.crux)
implementation(libs.dagger) implementation(libs.dagger)
implementation(libs.jsoup) implementation(libs.jsoup)
implementation(libs.kotlinx.collections.immutable) implementation(libs.kotlinx.collections.immutable)
@ -79,6 +78,7 @@ dependencies {
implementation(libs.napier) implementation(libs.napier)
implementation(libs.soloader) implementation(libs.soloader)
implementation(libs.sqldelight.extensions.coroutines) implementation(libs.sqldelight.extensions.coroutines)
implementation(libs.unfurl)
implementation(projects.api) implementation(projects.api)
implementation(projects.common) implementation(projects.common)
implementation(projects.core) implementation(projects.core)

View file

@ -1,25 +1,44 @@
/* /*
* Copyright © 2021-2022 Harsh Shandilya. * Copyright © 2021-2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style * Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT. * https://opensource.org/licenses/MIT.
*/ */
package dev.msfjarvis.claw.android.injection package dev.msfjarvis.claw.android.injection
import com.chimbori.crux.Crux
import com.deliveryhero.whetstone.app.ApplicationScope import com.deliveryhero.whetstone.app.ApplicationScope
import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.annotations.ContributesTo
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import io.github.aakira.napier.Napier
import me.saket.unfurl.UnfurlLogger
import me.saket.unfurl.Unfurler
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@Module @Module
@ContributesTo(ApplicationScope::class) @ContributesTo(ApplicationScope::class)
object MetadataExtractorModule { object MetadataExtractorModule {
@Provides @Provides
fun provideCrux( fun provideUnfurlLogger(): UnfurlLogger {
return object : UnfurlLogger {
override fun log(message: String) {
Napier.d { message }
}
override fun log(e: Throwable, message: String) {
Napier.e(e) { message }
}
}
}
@Provides
fun provideUnfurler(
okHttpClient: OkHttpClient, okHttpClient: OkHttpClient,
): Crux { logger: UnfurlLogger,
return Crux(okHttpClient = okHttpClient) ): Unfurler {
return Unfurler(
httpClient = okHttpClient,
logger = logger,
)
} }
} }

View file

@ -6,44 +6,21 @@
*/ */
package dev.msfjarvis.claw.android.viewmodel package dev.msfjarvis.claw.android.viewmodel
import com.chimbori.crux.Crux import dev.msfjarvis.claw.core.injection.IODispatcher
import com.chimbori.crux.api.Fields
import dev.msfjarvis.claw.model.LinkMetadata import dev.msfjarvis.claw.model.LinkMetadata
import javax.inject.Inject import javax.inject.Inject
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import kotlinx.coroutines.CoroutineDispatcher
import okhttp3.OkHttpClient import kotlinx.coroutines.withContext
import okhttp3.Request import me.saket.unfurl.Unfurler
import org.jsoup.Jsoup
class LinkMetadataRepository class LinkMetadataRepository
@Inject @Inject
constructor( constructor(
private val crux: Crux, private val unfurler: Unfurler,
private val okHttpClient: OkHttpClient, @IODispatcher private val dispatcher: CoroutineDispatcher,
) { ) {
suspend fun getLinkMetadata(url: String): LinkMetadata { suspend fun getLinkMetadata(url: String): LinkMetadata {
return run { val result = withContext(dispatcher) { unfurler.unfurl(url) }
val parsedUrl = url.toHttpUrlOrNull() ?: return@run null return LinkMetadata(url, result?.favicon?.toString())
if (!parsedUrl.isHttps) return@run null
val request = Request.Builder().url(parsedUrl).build()
val htmlContent =
okHttpClient.newCall(request).execute().use { response ->
val body = response.body ?: return@run null
body.string()
}
val extractedMetadata = crux.extractFrom(parsedUrl, Jsoup.parse(htmlContent, url))
val faviconUrl = extractedMetadata[Fields.FAVICON_URL].toString()
val readingTime = extractedMetadata[Fields.DURATION_MS].toString()
LinkMetadata(
url = url,
faviconUrl = faviconUrl,
readingTime = readingTime,
)
}
?: LinkMetadata(
url = url,
faviconUrl = null,
readingTime = null,
)
} }
} }

View file

@ -59,7 +59,7 @@ internal fun CommentsHeader(
val uriHandler = LocalUriHandler.current val uriHandler = LocalUriHandler.current
val linkMetadata by val linkMetadata by
produceState( produceState(
initialValue = LinkMetadata(postDetails.url, null, null), initialValue = LinkMetadata(postDetails.url, null),
) { ) {
runCatching { postActions.getLinkMetadata(postDetails.url) } runCatching { postActions.getLinkMetadata(postDetails.url) }
.onSuccess { metadata -> value = metadata } .onSuccess { metadata -> value = metadata }

View file

@ -289,7 +289,7 @@ fun LobstersCardPreview() {
} }
override suspend fun getLinkMetadata(url: String): LinkMetadata { override suspend fun getLinkMetadata(url: String): LinkMetadata {
return LinkMetadata("", "", "") return LinkMetadata("", "")
} }
}, },
) )

View file

@ -61,7 +61,6 @@ compose-richtext-markdown = { module = "com.halilibo.compose-richtext:richtext-c
compose-richtext-material3 = { module = "com.halilibo.compose-richtext:richtext-ui-material3", version.ref = "richtext" } compose-richtext-material3 = { module = "com.halilibo.compose-richtext:richtext-ui-material3", version.ref = "richtext" }
compose-richtext-ui = { module = "com.halilibo.compose-richtext:richtext-ui", version.ref = "richtext" } compose-richtext-ui = { module = "com.halilibo.compose-richtext:richtext-ui", version.ref = "richtext" }
copydown = "io.github.furstenheim:copy_down:1.1" copydown = "io.github.furstenheim:copy_down:1.1"
crux = "com.chimbori.crux:crux:5.0"
dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" }
dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" } dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" }
eithernet = "com.slack.eithernet:eithernet:1.4.1" eithernet = "com.slack.eithernet:eithernet:1.4.1"
@ -93,6 +92,7 @@ sqldelight-primitiveAdapters = { module = "app.cash.sqldelight:primitive-adapter
sqlite-android = "com.github.requery:sqlite-android:3.42.0" sqlite-android = "com.github.requery:sqlite-android:3.42.0"
testparameterinjector = "com.google.testparameterinjector:test-parameter-injector:1.12" testparameterinjector = "com.google.testparameterinjector:test-parameter-injector:1.12"
truth = "com.google.truth:truth:1.1.5" truth = "com.google.truth:truth:1.1.5"
unfurl = "me.saket.unfurl:unfurl:1.7.0"
whetstone = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "whetstone" } whetstone = { module = "com.deliveryhero.whetstone:whetstone", version.ref = "whetstone" }
[plugins] [plugins]

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2022 Harsh Shandilya. * Copyright © 2022-2023 Harsh Shandilya.
* Use of this source code is governed by an MIT-style * Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at * license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT. * https://opensource.org/licenses/MIT.
@ -8,8 +8,10 @@
package dev.msfjarvis.claw.model package dev.msfjarvis.claw.model
data class LinkMetadata( import dev.drewhamilton.poko.Poko
@Poko
class LinkMetadata(
val url: String, val url: String,
val faviconUrl: String?, val faviconUrl: String?,
val readingTime: String?,
) )