Skip to content

Commit 2ce9698

Browse files
committed
refactor: improve memory footprint of zipline-parser code
I miss the ART GC already...
1 parent 42627d2 commit 2ce9698

4 files changed

Lines changed: 41 additions & 50 deletions

File tree

zipline-parser/src/commonMain/kotlin/dev/msfjarvis/claw/parser/internal/CommentParsers.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ private fun MutableList<Comment>.addSubtree(
3131
val comment = commentElement.toComment(parentComment)
3232
add(comment)
3333
val childContainer = if (subtree.`is`("div.comment")) subtree.parent() ?: subtree else subtree
34-
childContainer
35-
.children()
36-
.filter { it.`is`("ol.comments") }
37-
.flatMap { comments -> comments.children().filter { it.`is`("li.comments_subtree") } }
38-
.forEach { child -> addSubtree(child, parentComment = comment.shortId, seen) }
34+
for (childList in childContainer.children()) {
35+
if (!childList.`is`("ol.comments")) continue
36+
for (child in childList.children()) {
37+
if (!child.`is`("li.comments_subtree")) continue
38+
addSubtree(child, parentComment = comment.shortId, seen)
39+
}
40+
}
3941
}
4042

4143
private fun Element.toComment(parentComment: String?): Comment {

zipline-parser/src/commonMain/kotlin/dev/msfjarvis/claw/parser/internal/PostDetailsParsers.kt

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -10,40 +10,30 @@ import com.fleeksoft.ksoup.Ksoup
1010
import dev.msfjarvis.claw.model.LobstersPostDetails
1111

1212
private const val BASE_URL = "https://lobste.rs"
13+
private val commentCountRegex = "\\d+".toRegex()
14+
private const val STORY_SELECTOR = "ol.stories > li.story"
15+
private const val SUBMITTER_SELECTOR =
16+
"ol.stories > li.story div.byline > a[href^=/~]:not([tabindex]):not([aria-hidden=true])"
1317

1418
internal fun parsePostDetails(html: String): LobstersPostDetails {
1519
val document = Ksoup.parse(html, baseUri = BASE_URL)
20+
val storyElement = document.select(STORY_SELECTOR)
21+
val timestampElement = document.select("$STORY_SELECTOR div.byline > time")
22+
val titleElement = document.select("$STORY_SELECTOR span.link.h-cite > a")
23+
val commentsElement = document.select("$STORY_SELECTOR span.comments_label a")
24+
val submitterElement = document.select(SUBMITTER_SELECTOR)
25+
val tags = document.select("$STORY_SELECTOR span.tags > a").map { it.text() }
1626
return LobstersPostDetails(
17-
shortId = document.select("ol.stories > li.story").attr("data-shortid"),
18-
createdAt =
19-
normalizeCreatedAt(
20-
document.select("ol.stories > li.story div.byline > time").attr("data-at-unix")
21-
),
22-
title = document.select("ol.stories > li.story span.link.h-cite > a").text(),
23-
url = document.select("ol.stories > li.story span.link.h-cite > a").attr("abs:href"),
27+
shortId = storyElement.attr("data-shortid"),
28+
createdAt = normalizeCreatedAt(timestampElement.attr("data-at-unix")),
29+
title = titleElement.text(),
30+
url = titleElement.attr("abs:href"),
2431
description = document.select("div.story_content div.story_text").html(),
25-
commentCount =
26-
"\\d+"
27-
.toRegex()
28-
.find(document.select("ol.stories > li.story span.comments_label a").text())
29-
?.value
30-
?.toInt() ?: 0,
31-
commentsUrl = document.select("ol.stories > li.story span.comments_label a").attr("abs:href"),
32-
submitter =
33-
document
34-
.select(
35-
"ol.stories > li.story div.byline > a[href^=/~]:not([tabindex]):not([aria-hidden=true])"
36-
)
37-
.text(),
38-
tags = document.select("ol.stories > li.story span.tags > a").map { it.text() },
32+
commentCount = commentCountRegex.find(commentsElement.text())?.value?.toInt() ?: 0,
33+
commentsUrl = commentsElement.attr("abs:href"),
34+
submitter = submitterElement.text(),
35+
tags = tags,
3936
comments = parseComments(document),
40-
userIsAuthor =
41-
document
42-
.select(
43-
"ol.stories > li.story div.byline > a[href^=/~]:not([tabindex]):not([aria-hidden=true])"
44-
)
45-
.attr("class")
46-
.split(' ')
47-
.contains("user_is_author"),
37+
userIsAuthor = submitterElement.attr("class").split(' ').contains("user_is_author"),
4838
)
4939
}

zipline-parser/src/commonMain/kotlin/dev/msfjarvis/claw/parser/internal/PostParsers.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.fleeksoft.ksoup.nodes.Element
1111
import dev.msfjarvis.claw.model.LobstersPost
1212

1313
private const val BASE_URL = "https://lobste.rs"
14+
private val commentCountRegex = "\\d+".toRegex()
1415

1516
internal fun parsePostsPage(html: String): List<LobstersPost> {
1617
return Ksoup.parse(html, baseUri = BASE_URL).select("li.story").map(::parsePost)
@@ -24,19 +25,20 @@ private fun parsePost(element: Element): LobstersPost {
2425
"> div.story_liner div.byline > a[href^=/~]:not([tabindex]):not([aria-hidden=true])"
2526
)
2627

28+
val timestampElement = element.select("> div.story_liner div.byline > time")
29+
val descriptionElement = element.select("> div.story_liner a.description_present")
30+
val tags = element.select("> div.story_liner span.tags > a").map(Element::text)
31+
2732
return LobstersPost(
2833
shortId = element.attr("data-shortid"),
29-
createdAt =
30-
normalizeCreatedAt(
31-
element.select("> div.story_liner div.byline > time").attr("data-at-unix")
32-
),
34+
createdAt = normalizeCreatedAt(timestampElement.attr("data-at-unix")),
3335
title = titleElement.text(),
3436
url = titleElement.attr("abs:href"),
35-
description = element.select("> div.story_liner a.description_present").attr("title"),
36-
commentCount = "\\d+".toRegex().find(commentElement.text())?.value?.toInt() ?: 0,
37+
description = descriptionElement.attr("title"),
38+
commentCount = commentCountRegex.find(commentElement.text())?.value?.toInt() ?: 0,
3739
commentsUrl = commentElement.attr("abs:href"),
3840
submitter = submitterElement.text(),
3941
userIsAuthor = submitterElement.attr("class").split(' ').contains("user_is_author"),
40-
tags = element.select("> div.story_liner span.tags > a").map(Element::text),
42+
tags = tags,
4143
)
4244
}

zipline-parser/src/commonMain/kotlin/dev/msfjarvis/claw/parser/internal/TagParsers.kt

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,15 @@ internal fun parseTagsPage(html: String): List<Tag> {
1717
}
1818

1919
private fun parseTag(element: Element): Tag {
20+
val tagElement = element.select("> a.tag")
21+
val descriptionElement = element.select("> span:not(.byline)")
2022
return Tag(
21-
tag = element.select("> a.tag").text(),
22-
description = element.select("> span:not(.byline)").text(),
23+
tag = tagElement.text(),
24+
description = descriptionElement.text(),
2325
privileged = element.attr("data-privileged").toBoolean(),
24-
active =
25-
!element
26-
.select("> span:not(.byline)")
27-
.attr("class")
28-
.split(Regex("\\s+"))
29-
.contains("inactive_tag"),
26+
active = !descriptionElement.hasClass("inactive_tag"),
3027
category = element.attr("data-category"),
31-
isMedia = element.select("> a.tag").attr("class").split(Regex("\\s+")).contains("tag_is_media"),
28+
isMedia = tagElement.hasClass("tag_is_media"),
3229
hotnessMod = element.attr("data-hotness-mod").toDoubleOrNull() ?: 0.0,
3330
)
3431
}

0 commit comments

Comments
 (0)