Skip to content

Commit b0d2a54

Browse files
committed
feat(Willhaben): support /iad/object redirects
1 parent 5827d36 commit b0d2a54

File tree

2 files changed

+36
-14
lines changed

2 files changed

+36
-14
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version = "3.1.0"
1+
version = "3.2.0"

integration/willhaben/src/main/kotlin/me/snoty/integration/contrib/willhaben/api/WillhabenAPI.kt

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging
44
import io.ktor.client.*
55
import io.ktor.client.plugins.*
66
import io.ktor.client.request.*
7+
import io.ktor.client.statement.HttpResponse
78
import io.ktor.http.*
89
import kotlinx.serialization.json.Json
910
import kotlinx.serialization.json.jsonArray
@@ -27,22 +28,43 @@ class WillhabenAPIImpl(private val httpClient: HttpClient) : WillhabenAPI, KoinC
2728
val logger = KotlinLogging.logger {}
2829

2930
override suspend fun fetchListing(url: String): WillhabenListing? {
30-
val mappedUrl = parseWillhabenUrl(url)
31-
if (mappedUrl.segments.firstOrNull() != "iad" || !mappedUrl.segments.contains("d")) throw IllegalArgumentException("Not a listing URL: $url")
31+
var mappedUrl = parseWillhabenUrl(url)
32+
if (
33+
mappedUrl.segments.firstOrNull() != "iad"
34+
|| (
35+
!mappedUrl.segments.contains("d")
36+
&& mappedUrl.segments.last() != "object"
37+
)
38+
) throw IllegalArgumentException("Not a listing URL: $url")
3239

33-
val response = try {
34-
noRedirectClient.get(mappedUrl)
35-
} catch (redirect: RedirectResponseException) {
36-
val location = redirect.response.headers[HttpHeaders.Location] ?: throw redirect
40+
lateinit var response: HttpResponse
3741

38-
if (location.contains("?fromExpiredAdId=")) {
39-
logger.warn { "Listing $url is expired" }
40-
return null
41-
}
42-
if (!location.contains("/d/")) throw IllegalArgumentException("Invalid redirect location: $location")
42+
for (attempt in 0..3) {
43+
try {
44+
logger.debug { "Attempting to fetch $mappedUrl - attempt $attempt" }
45+
response = noRedirectClient.get(mappedUrl)
46+
break
47+
} catch (redirect: RedirectResponseException) {
48+
val location = redirect.response.headers[HttpHeaders.Location] ?: throw redirect
49+
50+
if (location.contains("?fromExpiredAdId=")) {
51+
logger.warn { "Listing $url is expired" }
52+
return null
53+
}
54+
if (!location.contains("/d/")) throw IllegalArgumentException("Invalid redirect location: $location")
4355

44-
// redirect may be valid (http -> https?) - try the new URL
45-
noRedirectClient.get(location)
56+
// redirect may be valid (/iad/object?adId=... -> /iad/.../d/...) - try the new URL
57+
val newUrlBuilder = URLBuilder()
58+
newUrlBuilder.protocol = URLProtocol.HTTPS
59+
// since we manually follow the redirect, use WILLHABEN_HOST as the default
60+
newUrlBuilder.host = WILLHABEN_HOST
61+
// and override the path with the relative path gotten from the original request
62+
newUrlBuilder.path(location)
63+
val newUrl = newUrlBuilder.build()
64+
65+
logger.debug { "Redirected to $newUrl" }
66+
mappedUrl = newUrl
67+
}
4668
}
4769

4870
val props = response.parsePageProps(json)

0 commit comments

Comments
 (0)