diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/LinkChecker.kt b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/LinkChecker.kt index 78934a8..798e1ee 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/LinkChecker.kt +++ b/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/LinkChecker.kt @@ -4,6 +4,7 @@ import ir.amirab.downloader.connection.DownloaderClient import ir.amirab.downloader.connection.response.ResponseInfo import ir.amirab.downloader.downloaditem.DownloadCredentials import com.abdownloadmanager.utils.isValidUrl +import ir.amirab.util.UrlUtils import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update diff --git a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/OkHttpDownloaderClient.kt b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/OkHttpDownloaderClient.kt index 9917c68..70c7cd2 100644 --- a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/OkHttpDownloaderClient.kt +++ b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/OkHttpDownloaderClient.kt @@ -26,17 +26,17 @@ class OkHttpDownloaderClient( ?.filter { //OkHttp handles this header and if we override it, //makes redirected links to have this "Host" instead of their own!, and cause error - !it.key.equals("Host",true) + !it.key.equals("Host", true) } ?.forEach { (k, v) -> - header(k, v) - } + header(k, v) + } val username = downloadCredentials.username val password = downloadCredentials.password if (username?.isNotBlank() == true && password?.isNotBlank() == true) { header("Authorization", Credentials.basic(username, password)) } - downloadCredentials.userAgent?.let { userAgent-> + downloadCredentials.userAgent?.let { userAgent -> header("User-Agent", userAgent) } } @@ -65,6 +65,7 @@ class OkHttpDownloaderClient( return ResponseInfo( statusCode = response.code, message = response.message, + requestUrl = response.request.url.toString(), requestHeaders = response.request.headers.associate { (key, value) -> key.lowercase() to value }, @@ -88,7 +89,7 @@ class OkHttpDownloaderClient( } ).await() val body = runCatching { - requireNotNull(response.body){ + requireNotNull(response.body) { "body is null" } }.onFailure { diff --git a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt index 08373bd..f810989 100644 --- a/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt +++ b/downloader/core/src/main/kotlin/ir/amirab/downloader/connection/response/ResponseInfo.kt @@ -3,10 +3,13 @@ package ir.amirab.downloader.connection.response import ir.amirab.downloader.connection.response.headers.getContentRange import ir.amirab.downloader.connection.response.headers.extractFileNameFromContentDisposition import ir.amirab.downloader.exception.UnSuccessfulResponseException +import ir.amirab.downloader.utils.FileNameUtil +import ir.amirab.util.UrlUtils data class ResponseInfo( val statusCode: Int, val message: String, + val requestUrl: String, val requestHeaders: Map = linkedMapOf(), val responseHeaders: Map = linkedMapOf(), ) { @@ -37,9 +40,24 @@ data class ResponseInfo( statusCode == 206 } val fileName: String? by lazy { - responseHeaders["content-disposition"]?.let { - extractFileNameFromContentDisposition(it) + val foundName = run { + val nameFromHeader = responseHeaders["content-disposition"]?.let { + extractFileNameFromContentDisposition(it) + } + if (nameFromHeader!=null){ + return@lazy nameFromHeader + } + UrlUtils.extractNameFromLink(requestUrl).orEmpty() } + var valueToReturn = foundName + if (isWebPage()){ + valueToReturn = FileNameUtil.replaceExtension( + valueToReturn, + "html", + true + ) + } + valueToReturn } // It is good to use these properties to check file is valid @@ -52,6 +70,10 @@ data class ResponseInfo( } } +fun ResponseInfo.isWebPage(): Boolean { + return responseHeaders["content-type"].orEmpty().contains("text/html") +} + fun ResponseInfo.expectSuccess() = apply { if (!isSuccessFul) { throw UnSuccessfulResponseException(statusCode, message) diff --git a/downloader/core/src/main/kotlin/ir/amirab/downloader/utils/FileNameUtil.kt b/downloader/core/src/main/kotlin/ir/amirab/downloader/utils/FileNameUtil.kt index 92166aa..c1fc0c3 100644 --- a/downloader/core/src/main/kotlin/ir/amirab/downloader/utils/FileNameUtil.kt +++ b/downloader/core/src/main/kotlin/ir/amirab/downloader/utils/FileNameUtil.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.currentCoroutineContext import kotlinx.coroutines.flow.* import kotlinx.coroutines.isActive import java.io.File +import java.security.cert.Extension object FileNameUtil { private fun getExtensionOrNull(name: String): String? { @@ -33,4 +34,14 @@ object FileNameUtil { } } } + + fun replaceExtension(filename: String, newExtension: String, appendIfNotExists: Boolean=true): String { + val ext = getExtensionOrNull(filename) ?: if (appendIfNotExists) { + return "$filename.$newExtension" + } else { + return filename + } + val filenameWithoutExtension = filename.substring(0, filename.length - ext.length) + return "$filenameWithoutExtension$newExtension" + } } \ No newline at end of file diff --git a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/UrlUtils.kt b/shared/utils/src/main/kotlin/ir/amirab/util/UrlUtils.kt similarity index 93% rename from desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/UrlUtils.kt rename to shared/utils/src/main/kotlin/ir/amirab/util/UrlUtils.kt index de2218a..220b982 100644 --- a/desktop/app/src/main/kotlin/com/abdownloadmanager/desktop/utils/UrlUtils.kt +++ b/shared/utils/src/main/kotlin/ir/amirab/util/UrlUtils.kt @@ -1,4 +1,4 @@ -package com.abdownloadmanager.desktop.utils +package ir.amirab.util import java.net.URL import java.net.URLDecoder