Merge remote-tracking branch 'origin/master'

This commit is contained in:
kunfei
2023-03-15 22:53:26 +08:00
2 changed files with 47 additions and 13 deletions
@@ -22,6 +22,7 @@ import io.legado.app.help.AppWebDav
import io.legado.app.help.book.* import io.legado.app.help.book.*
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.lib.webdav.ObjectNotFoundException import io.legado.app.lib.webdav.ObjectNotFoundException
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.model.BookCover import io.legado.app.model.BookCover
import io.legado.app.model.ReadBook import io.legado.app.model.ReadBook
import io.legado.app.model.localBook.LocalBook import io.legado.app.model.localBook.LocalBook
@@ -242,7 +243,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
webFiles.clear() webFiles.clear()
val fileName = "${book.name} 作者:${book.author}" val fileName = "${book.name} 作者:${book.author}"
book.downloadUrls!!.map { book.downloadUrls!!.map {
val mFileName = UrlUtil.getFileName(it) ?: fileName val mFileName = UrlUtil.getFileName(AnalyzeUrl(it, source = bookSource)) ?: fileName
WebFile(it, mFileName) WebFile(it, mFileName)
} }
}.onError { }.onError {
@@ -456,7 +457,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
} }
// 后缀 // 后缀
val suffix: String = name.substringAfterLast(".") val suffix: String = UrlUtil.getSuffix(name)
// txt epub umd pdf等文件 // txt epub umd pdf等文件
val isSupported: Boolean = AppPattern.bookFileRegex.matches(name) val isSupported: Boolean = AppPattern.bookFileRegex.matches(name)
@@ -1,5 +1,7 @@
package io.legado.app.utils package io.legado.app.utils
import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.constant.AppLog
import java.net.HttpURLConnection import java.net.HttpURLConnection
import java.net.URL import java.net.URL
import java.net.URLDecoder import java.net.URLDecoder
@@ -29,19 +31,33 @@ object UrlUtil {
.replace("|", "%7C") .replace("|", "%7C")
} }
/* 阅读定义的url,{urlOption} */
fun getFileName(analyzeUrl: AnalyzeUrl): String? {
return getFileName(analyzeUrl.url, analyzeUrl.headerMap)
}
/** /**
* 根据网络url获取文件名 * 根据网络url获取文件信息 文件
*/ */
fun getFileName(fileUrl: String): String? { fun getFileName(fileUrl: String, headerMap: Map<String, String>? = null): String? {
// 如果获取到后缀可直接截取链接
if (getSuffix(fileUrl, "") != "") return fileUrl.substringAfterLast("/")
return kotlin.runCatching { return kotlin.runCatching {
var fileName: String var fileName: String = ""
val url = URL(fileUrl) val url = URL(fileUrl)
val conn: HttpURLConnection = url.openConnection() as HttpURLConnection val conn: HttpURLConnection = url.openConnection() as HttpURLConnection
// head方式 // HEAD方式获取返回头信息
conn.requestMethod = "HEAD" conn.requestMethod = "HEAD"
// 下载链接可能还需要书源header才能成功访问
headerMap?.forEach { key, value ->
conn.setRequestProperty(key, value)
}
conn.connect() conn.connect()
// 方法一 // val contentLength = conn.getContentLengthLong()
// Content-Disposition
// 解析文件名 filename= filename*=
val raw: String? = conn.getHeaderField("Content-Disposition") val raw: String? = conn.getHeaderField("Content-Disposition")
if (raw != null && raw.indexOf("=") > 0) { if (raw != null && raw.indexOf("=") > 0) {
fileName = raw.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1] fileName = raw.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[1]
@@ -50,22 +66,39 @@ object UrlUtil {
fileName.toByteArray(StandardCharsets.ISO_8859_1), fileName.toByteArray(StandardCharsets.ISO_8859_1),
StandardCharsets.UTF_8 //? StandardCharsets.UTF_8 //?
) )
} else { } else if (conn.getHeaderField("Location") != null) {
// 方法二 截取 // Location跳转到实际的下载链接
var newUrl: String = conn.url.path ?: return null var newUrl: String = conn.url.path ?: return null
newUrl = URLDecoder.decode(newUrl, "UTF-8") newUrl = URLDecoder.decode(newUrl, "UTF-8")
fileName = newUrl.substringAfterLast("/") if (getSuffix(newUrl, "") != "") {
fileName = newUrl.substringAfterLast("/")
}
} else {
// 其余情况 返回响应头
val headers = conn.getHeaderFields()
val headersString = buildString {
headers.forEach { key, value ->
value.forEach {
append(key)
append(": ")
append(it)
append("\n")
}
}
}
AppLog.putDebug("Cannot obtain URL file name:\n$headersString")
} }
fileName fileName
}.getOrNull() }.getOrNull()
} }
fun getSuffix(url: String, default: String): String { /* 获取合法的文件后缀 */
val suffix = url.substringAfterLast(".").substringBeforeLast(",") fun getSuffix(str: String, default: String? = null): String {
val suffix = str.substringAfterLast(".").substringBeforeLast(",")
//检查截取的后缀字符是否合法 [a-zA-Z0-9] //检查截取的后缀字符是否合法 [a-zA-Z0-9]
val fileSuffixRegex = Regex("^[a-z\\d]+$", RegexOption.IGNORE_CASE) val fileSuffixRegex = Regex("^[a-z\\d]+$", RegexOption.IGNORE_CASE)
return if (suffix.length > 5 || !suffix.matches(fileSuffixRegex)) { return if (suffix.length > 5 || !suffix.matches(fileSuffixRegex)) {
default default ?: throw IllegalArgumentException("Cannot find illegal suffix:\n target: $str\nsuffix: $suffix")
} else { } else {
suffix suffix
} }