Coverage Summary for Class: NewsArchiveParser (com.galarzaa.tibiakt.core.section.news.archive.parser)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| NewsArchiveParser |
100%
(1/1)
|
100%
(4/4)
|
62.5%
(35/56)
|
82.7%
(43/52)
|
71.6%
(307/429)
|
/*
* Copyright © 2025 Allan Galarza
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.galarzaa.tibiakt.core.section.news.archive.parser
import com.galarzaa.tibiakt.core.exceptions.ParsingException
import com.galarzaa.tibiakt.core.html.cells
import com.galarzaa.tibiakt.core.html.cleanText
import com.galarzaa.tibiakt.core.html.formData
import com.galarzaa.tibiakt.core.html.getLinkInformation
import com.galarzaa.tibiakt.core.html.parseTablesMap
import com.galarzaa.tibiakt.core.html.rows
import com.galarzaa.tibiakt.core.parser.Parser
import com.galarzaa.tibiakt.core.section.news.archive.builder.NewsArchiveBuilder
import com.galarzaa.tibiakt.core.section.news.archive.builder.newsArchive
import com.galarzaa.tibiakt.core.section.news.archive.model.NewsArchive
import com.galarzaa.tibiakt.core.section.news.shared.model.NewsCategory
import com.galarzaa.tibiakt.core.section.news.shared.model.NewsType
import com.galarzaa.tibiakt.core.time.parseTibiaDate
import kotlinx.datetime.LocalDate
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
/** Parses content from the news archive. */
public object NewsArchiveParser : Parser<NewsArchive> {
override fun fromContent(content: String): NewsArchive {
val document: Document = Jsoup.parse(content)
val boxContent =
document.selectFirst("div.BoxContent") ?: throw ParsingException("BoxContent container not found")
val tables = boxContent.parseTablesMap()
if (!tables.containsKey("News Archive Search")) throw ParsingException("news search not found in page")
return newsArchive {
boxContent.selectFirst("form")?.apply {
parseFilterTable(this)
}
tables["Search Results"]?.let { parseResultsTable(it) }
}
}
private fun NewsArchiveBuilder.parseResultsTable(table: Element) {
for (row in table.rows()) {
val rows = row.cells()
if (rows.size != 3)
continue
val (iconColumn, dateColumn, titleColumn) = rows
val iconUrl =
iconColumn.selectFirst("img")?.attr("src") ?: throw ParsingException("category icon not found")
val category =
NewsCategory.Companion.fromIcon(iconUrl)
?: throw ParsingException("unknown category icon found: $iconUrl")
val newsId = titleColumn.selectFirst("a")?.getLinkInformation()?.queryParams?.get("id")?.get(0)?.toInt()
?: throw ParsingException("Could not find link")
val typeLabel = dateColumn.selectFirst("small") ?: throw ParsingException("could not find type label")
val newsType = typeLabel.cleanText()
typeLabel.remove()
addEntry(
newsId,
titleColumn.cleanText(),
category,
parseTibiaDate(dateColumn.cleanText()),
NewsType.fromDisplayName(newsType)
?: throw ParsingException("unexpected news type found: $newsType")
)
}
}
private fun NewsArchiveBuilder.parseFilterTable(element: Element) {
val formData = element.formData()
val builder = NewsArchiveBuilder.NewsArchiveFiltersBuilder()
builder.startOn = LocalDate(
formData.values["filter_begin_year"]?.toInt()
?: throw ParsingException("could not find filter_begin_year in form"),
formData.values["filter_begin_month"]?.toInt()
?: throw ParsingException("could not find filter_begin_month in form"),
formData.values["filter_begin_day"]?.toInt()
?: throw ParsingException("could not find filter_begin_day in form"),
)
builder.endOn = LocalDate(
formData.values["filter_end_year"]?.toInt()
?: throw ParsingException("could not find filter_end_year in form"),
formData.values["filter_end_month"]?.toInt()
?: throw ParsingException("could not find filter_end_month in form"),
formData.values["filter_end_day"]?.toInt()
?: throw ParsingException("could not find filter_end_day in form"),
)
for (value in NewsCategory.entries) {
if (!formData.valuesMultiple[value.filterName].isNullOrEmpty()) builder.addCategory(value)
}
for (value in NewsType.entries) {
if (!formData.valuesMultiple[value.filterName].isNullOrEmpty()) builder.addType(value)
}
filters = builder.build()
}
}