compose-lobsters/api/src/main/kotlin/dev/msfjarvis/claw/api/converters/SearchConverter.kt

66 lines
2.2 KiB
Kotlin

/*
* Copyright © 2023-2024 Harsh Shandilya.
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/
package dev.msfjarvis.claw.api.converters
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.model.LobstersPost
import java.lang.reflect.Type
import okhttp3.ResponseBody
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import retrofit2.Converter
import retrofit2.Retrofit
object SearchConverter : Converter<ResponseBody, List<LobstersPost>> {
override fun convert(value: ResponseBody): List<LobstersPost> {
val elements =
Jsoup.parse(value.string(), LobstersApi.BASE_URL).select("div.story_liner.h-entry")
return elements.map(::parsePost)
}
private fun parsePost(elem: Element): LobstersPost {
val parent = elem.parent() ?: error("$elem must have a parent")
val shortId = parent.attr("data-shortid")
val titleElement = elem.select("span.link.h-cite > a")
val title = titleElement.text()
val url = titleElement.attr("href")
val tags = elem.select("span.tags > a").map(Element::text)
val (commentCount, commentsUrl) = getCommentsData(elem.select("span.comments_label"))
val submitter = elem.select("div.byline > a.u-author").text()
return LobstersPost(
shortId = shortId,
title = title,
url = url,
commentCount = commentCount,
commentsUrl = commentsUrl,
tags = tags,
submitter = submitter,
// The value of these fields is irrelevant for our use case
createdAt = "",
description = "",
)
}
private fun getCommentsData(elem: Elements): Pair<Int, String> {
val linkElement = elem.select("a")
val countString = linkElement.text().trimStart().substringBefore(" ")
val commentsUrl = LobstersApi.BASE_URL + linkElement.attr("href")
return (countString.toIntOrNull() ?: 0) to commentsUrl
}
object Factory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit,
): Converter<ResponseBody, List<LobstersPost>> {
return SearchConverter
}
}
}