diff --git a/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/fetcher/FeedFetcher.kt b/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/fetcher/FeedFetcher.kt index 8e9caf19c..594184cba 100644 --- a/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/fetcher/FeedFetcher.kt +++ b/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/fetcher/FeedFetcher.kt @@ -16,6 +16,8 @@ package dev.sasikanth.rss.reader.core.network.fetcher import com.fleeksoft.ksoup.Ksoup +import com.fleeksoft.ksoup.io.SourceReader +import com.fleeksoft.ksoup.io.from import dev.sasikanth.rss.reader.core.network.parser.FeedParser import dev.sasikanth.rss.reader.core.network.parser.FeedParser.Companion.ATOM_MEDIA_TYPE import dev.sasikanth.rss.reader.core.network.parser.FeedParser.Companion.ATTR_HREF @@ -26,13 +28,13 @@ import io.ktor.client.HttpClient import io.ktor.client.request.get import io.ktor.client.statement.HttpResponse import io.ktor.client.statement.bodyAsChannel -import io.ktor.client.statement.bodyAsText import io.ktor.http.ContentType import io.ktor.http.HttpStatusCode import io.ktor.http.URLBuilder import io.ktor.http.URLProtocol import io.ktor.http.Url import io.ktor.http.contentType +import io.ktor.utils.io.ByteReadChannel import korlibs.io.lang.Charset import korlibs.io.lang.Charsets import me.tatarka.inject.annotations.Inject @@ -99,7 +101,8 @@ class FeedFetcher(private val httpClient: HttpClient, private val feedParser: Fe return FeedFetchResult.Success(feedPayload) } - val feedUrl = fetchFeedLinkFromHtmlIfExists(response.bodyAsText(), url) + val feedUrl = + fetchFeedLinkFromHtmlIfExists(response = response.bodyAsChannel(), originalUrl = url) if (feedUrl != url && !feedUrl.isNullOrBlank()) { return fetch(url = feedUrl, transformUrl = false, redirectCount = redirectCount + 1) @@ -141,10 +144,16 @@ class FeedFetcher(private val httpClient: HttpClient, private val feedParser: Fe } } - private fun fetchFeedLinkFromHtmlIfExists(htmlContent: String, originalUrl: String): String? { + private fun fetchFeedLinkFromHtmlIfExists( + response: ByteReadChannel, + originalUrl: String + ): String? { val document = try { - Ksoup.parse(htmlContent) + Ksoup.parse( + sourceReader = SourceReader.from(response), + baseUri = originalUrl, + ) } catch (t: Throwable) { return null } diff --git a/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/FeedParser.kt b/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/FeedParser.kt index 1a4e1e1a1..c5cb32a68 100644 --- a/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/FeedParser.kt +++ b/core/network/src/commonMain/kotlin/dev/sasikanth/rss/reader/core/network/parser/FeedParser.kt @@ -23,12 +23,13 @@ import io.ktor.http.URLBuilder import io.ktor.http.URLProtocol import io.ktor.http.set import io.ktor.utils.io.ByteReadChannel -import io.ktor.utils.io.core.readBytes +import io.ktor.utils.io.readRemaining import korlibs.io.lang.Charset import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext +import kotlinx.io.readByteArray import me.tatarka.inject.annotations.Inject import org.kobjects.ktxml.api.XmlPullParserException import org.kobjects.ktxml.mini.MiniXmlPullParser @@ -154,9 +155,9 @@ private fun ByteReadChannel.toCharIterator( if (this@toCharIterator.isClosedForRead) return false val packet = runBlocking(context) { this@toCharIterator.readRemaining(DEFAULT_BUFFER_SIZE) } - currentBuffer = buildString { charset.decode(this, packet.readBytes()) } + currentBuffer = buildString { charset.decode(this, packet.readByteArray()) } - packet.release() + packet.close() currentIndex = 0 return currentBuffer.isNotEmpty() } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6fe58ceba..66dc9b4f6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,7 +31,7 @@ ktfmt = "0.44" kotlininject = "0.7.2" ksp = "2.0.20-1.0.25" material_color_utilities = "1.0.0-alpha01" -ksoup = "0.1.2" +ksoup = "0.1.9" sqliteAndroid = "3.45.0" windowSizeClass = "0.5.0" desugarJdk = "2.1.2" @@ -101,6 +101,7 @@ kotlininject-compiler = { module = 'me.tatarka.inject:kotlin-inject-compiler-ksp kotlininject-runtime = { module = 'me.tatarka.inject:kotlin-inject-runtime', version.ref = 'kotlininject' } material_color_utilities = { module = "dev.sasikanth:material-color-utilities", version.ref = "material_color_utilities" } ksoup = { module = "com.fleeksoft.ksoup:ksoup", version.ref = "ksoup" } +ksoup-okio = { module = "com.fleeksoft.ksoup:ksoup-okio", version.ref = "ksoup" } sqliteAndroid = { module = "com.github.requery:sqlite-android", version.ref = "sqliteAndroid" } windowSizeClass = { module = "dev.chrisbanes.material3:material3-window-size-class-multiplatform", version.ref = "windowSizeClass" } desugarJdk = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugarJdk" } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index b1f9eebca..2b69b01b7 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -93,6 +93,7 @@ kotlin { implementation(libs.androidx.collection) implementation(libs.material.color.utilities) implementation(libs.ksoup) + implementation(libs.ksoup.okio) implementation(libs.windowSizeClass) api(libs.androidx.datastore.okio) api(libs.androidx.datastore.preferences) diff --git a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/favicons/FavIconFetcher.kt b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/favicons/FavIconFetcher.kt index af4a33a27..41fc490c7 100644 --- a/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/favicons/FavIconFetcher.kt +++ b/shared/src/commonMain/kotlin/dev/sasikanth/rss/reader/favicons/FavIconFetcher.kt @@ -43,8 +43,9 @@ import coil3.network.httpHeaders import coil3.request.Options import coil3.util.MimeTypeMap import com.fleeksoft.ksoup.Ksoup +import com.fleeksoft.ksoup.io.SourceReader +import com.fleeksoft.ksoup.io.from import com.fleeksoft.ksoup.nodes.Document -import com.fleeksoft.ksoup.ported.BufferReader import okio.Buffer import okio.FileSystem import okio.IOException @@ -94,7 +95,7 @@ class FavIconFetcher( val document = Ksoup.parse( - bufferReader = BufferReader(responseBodyBuffer), + sourceReader = SourceReader.from(responseBodyBuffer), baseUri = url, charsetName = null )