pull/1296/head^2
gedoor 3 years ago
parent fd8932e85b
commit 3c5ab64f2c
  1. 4
      app/src/main/java/io/legado/app/help/JsExtensions.kt
  2. 108
      app/src/main/java/io/legado/app/model/CacheBook.kt
  3. 2
      app/src/main/java/io/legado/app/model/ReadBook.kt
  4. 44
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  5. 5
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  6. 5
      app/src/main/java/io/legado/app/ui/main/MainViewModel.kt
  7. 2
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssActivity.kt
  8. 1
      app/src/main/java/io/legado/app/ui/rss/read/ReadRssViewModel.kt

@ -82,7 +82,7 @@ interface JsExtensions {
}.onFailure {
it.printStackTrace()
}.getOrElse {
StrResponse(analyzeUrl.url, it.localizedMessage)
StrResponse(analyzeUrl.getDirectUrl(), it.localizedMessage)
}
}
}
@ -96,7 +96,7 @@ interface JsExtensions {
}.onFailure {
it.printStackTrace()
}.getOrElse {
StrResponse(analyzeUrl.url, it.localizedMessage)
StrResponse(analyzeUrl.getDirectUrl(), it.localizedMessage)
}
}
}

@ -3,6 +3,7 @@ package io.legado.app.model
import android.content.Context
import io.legado.app.R
import io.legado.app.constant.IntentAction
import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource
@ -12,67 +13,91 @@ import io.legado.app.utils.msg
import io.legado.app.utils.startService
import kotlinx.coroutines.CoroutineScope
import splitties.init.appCtx
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet
object CacheBook {
val logs = arrayListOf<String>()
private val downloadMap = ConcurrentHashMap<String, CopyOnWriteArraySet<Int>>()
class CacheBook(val bookSource: BookSource, val book: Book) {
fun addLog(log: String?) {
log ?: return
synchronized(this) {
if (logs.size > 1000) {
logs.removeAt(0)
companion object {
val logs = arrayListOf<String>()
private val cacheBookMap = hashMapOf<String, CacheBook>()
fun get(bookUrl: String): CacheBook? {
var cacheBook = cacheBookMap[bookUrl]
if (cacheBook != null) {
return cacheBook
}
logs.add(log)
val book = appDb.bookDao.getBook(bookUrl) ?: return null
val bookSource = appDb.bookSourceDao.getBookSource(book.origin) ?: return null
cacheBook = CacheBook(bookSource, book)
cacheBookMap[bookUrl] = cacheBook
return cacheBook
}
}
fun start(context: Context, bookUrl: String, start: Int, end: Int) {
context.startService<CacheBookService> {
action = IntentAction.start
putExtra("bookUrl", bookUrl)
putExtra("start", start)
putExtra("end", end)
fun get(bookSource: BookSource, book: Book): CacheBook {
var cacheBook = cacheBookMap[book.bookUrl]
if (cacheBook != null) {
return cacheBook
}
cacheBook = CacheBook(bookSource, book)
cacheBookMap[book.bookUrl] = cacheBook
return cacheBook
}
}
fun remove(context: Context, bookUrl: String) {
context.startService<CacheBookService> {
action = IntentAction.remove
putExtra("bookUrl", bookUrl)
fun addLog(log: String?) {
log ?: return
synchronized(this) {
if (logs.size > 1000) {
logs.removeAt(0)
}
logs.add(log)
}
}
}
fun stop(context: Context) {
context.startService<CacheBookService> {
action = IntentAction.stop
fun start(context: Context, bookUrl: String, start: Int, end: Int) {
context.startService<CacheBookService> {
action = IntentAction.start
putExtra("bookUrl", bookUrl)
putExtra("start", start)
putExtra("end", end)
}
}
}
fun downloadCount(): Int {
var count = 0
downloadMap.forEach {
count += it.value.size
fun remove(context: Context, bookUrl: String) {
context.startService<CacheBookService> {
action = IntentAction.remove
putExtra("bookUrl", bookUrl)
}
}
return count
fun stop(context: Context) {
context.startService<CacheBookService> {
action = IntentAction.stop
}
}
val downloadCount: Int
get() {
var count = 0
cacheBookMap.forEach {
count += it.value.downloadSet.size
}
return count
}
}
val downloadSet = CopyOnWriteArraySet<Int>()
fun download(
scope: CoroutineScope,
bookSource: BookSource,
book: Book,
chapter: BookChapter,
resetPageOffset: Boolean = false
) {
if (downloadMap[book.bookUrl]?.contains(chapter.index) == true) {
if (downloadSet.contains(chapter.index)) {
return
}
if (downloadMap[book.bookUrl] == null) {
downloadMap[book.bookUrl] = CopyOnWriteArraySet()
}
downloadMap[book.bookUrl]?.add(chapter.index)
downloadSet.add(chapter.index)
WebBook.getContent(scope, bookSource, book, chapter)
.onSuccess { content ->
if (ReadBook.book?.bookUrl == book.bookUrl) {
@ -93,10 +118,7 @@ object CacheBook {
)
}
}.onFinally {
downloadMap[book.bookUrl]?.remove(chapter.index)
if (downloadMap[book.bookUrl].isNullOrEmpty()) {
downloadMap.remove(book.bookUrl)
}
downloadSet.remove(chapter.index)
ReadBook.removeLoading(chapter.index)
}
}

@ -295,7 +295,7 @@ object ReadBook : CoroutineScope by MainScope() {
val book = book
val bookSource = bookSource
if (book != null && bookSource != null) {
CacheBook.download(scope, bookSource, book, chapter)
CacheBook.get(bookSource, book).download(scope, chapter)
} else if (book != null) {
contentLoadFinish(
book, chapter, "没有书源", resetPageOffset = resetPageOffset

@ -35,7 +35,6 @@ class AnalyzeUrl(
val speakText: String? = null,
val speakSpeed: Int? = null,
var baseUrl: String = "",
var useWebView: Boolean = false,
val book: BaseBook? = null,
val chapter: BookChapter? = null,
private val ruleData: RuleDataInterface? = null,
@ -48,17 +47,18 @@ class AnalyzeUrl(
private val accessTime = hashMapOf<String, FetchRecord>()
}
var url: String = ""
val headerMap = HashMap<String, String>()
var body: String? = null
var type: String? = null
private lateinit var urlHasQuery: String
private var url: String = ""
private var queryStr: String? = null
private val fieldMap = LinkedHashMap<String, String>()
private var charset: String? = null
private var method = RequestMethod.GET
private var proxy: String? = null
private var retry: Int = 0
private var useWebView: Boolean = false
private var webJs: String? = null
init {
val urlMatcher = paramPattern.matcher(baseUrl)
@ -141,12 +141,13 @@ class AnalyzeUrl(
*/
private fun initUrl() { //replaceKeyPageJs已经替换掉额外内容,此处url是基础形式,可以直接切首个‘,’之前字符串。
val urlMatcher = paramPattern.matcher(ruleUrl)
urlHasQuery = if (urlMatcher.find()) ruleUrl.substring(0, urlMatcher.start()) else ruleUrl
url = NetworkUtils.getAbsoluteURL(baseUrl, urlHasQuery)
val urlNoOption =
if (urlMatcher.find()) ruleUrl.substring(0, urlMatcher.start()) else ruleUrl
url = NetworkUtils.getAbsoluteURL(baseUrl, urlNoOption)
NetworkUtils.getBaseUrl(url)?.let {
baseUrl = it
}
if (urlHasQuery.length != ruleUrl.length) {
if (urlNoOption.length != ruleUrl.length) {
GSON.fromJsonObject<UrlOption>(ruleUrl.substring(urlMatcher.end()))?.let { option ->
option.method?.let {
if (it.equals("POST", true)) method = RequestMethod.POST
@ -171,6 +172,7 @@ class AnalyzeUrl(
useWebView = true
}
}
webJs = option.webJs
option.js?.let {
evalJS(it)
}
@ -183,21 +185,21 @@ class AnalyzeUrl(
}
when (method) {
RequestMethod.GET -> {
if (!useWebView) {
val pos = url.indexOf('?')
if (pos != -1) {
analyzeFields(url.substring(pos + 1))
url = url.substring(0, pos)
}
}
}
RequestMethod.POST -> {
body?.let {
val pos = url.indexOf('?')
if (pos != -1) {
analyzeFields(url.substring(pos + 1))
url = url.substring(0, pos)
} else body?.let {
if (!it.isJson()) {
analyzeFields(it)
}
}
}
RequestMethod.POST -> body?.let {
if (!it.isJson()) {
analyzeFields(it)
}
}
}
}
@ -416,7 +418,14 @@ class AnalyzeUrl(
headerMap.forEach { (key, value) ->
headers.addHeader(key, value)
}
return GlideUrl(urlHasQuery, headers.build())
return GlideUrl(getDirectUrl(), headers.build())
}
fun getDirectUrl(): String {
val qs = fieldMap.map {
"${it.key}=${it.value}"
}
return "$url?${qs.joinToString("&")}"
}
fun getUserAgent(): String {
@ -431,6 +440,7 @@ class AnalyzeUrl(
val method: String?,
val charset: String?,
val webView: Any?,
val webJs: String?,
val headers: Any?,
val body: Any?,
val type: String?,

@ -131,10 +131,9 @@ class AudioPlayService : BaseService(),
AnalyzeUrl(
url,
headerMapF = AudioPlay.headers(),
source = AudioPlay.bookSource,
useWebView = true
source = AudioPlay.bookSource
)
val uri = Uri.parse(analyzeUrl.url)
val uri = Uri.parse(analyzeUrl.getDirectUrl())
val dataSourceFactory = OkHttpDataSource.Factory(okHttpClient)
.setDefaultRequestProperties(analyzeUrl.headerMap)
val mediaSource = ExoPlayerHelper

@ -118,8 +118,9 @@ class MainViewModel(application: Application) : BaseViewModel(application) {
if (!BookHelp.hasContent(book, chapter)) {
var addToCache = false
while (!addToCache) {
if (CacheBook.downloadCount() < 10) {
CacheBook.download(this, bookSource, book, chapter)
val cacheBook = CacheBook.get(bookSource, book)
if (CacheBook.downloadCount < 10) {
cacheBook.download(this, chapter)
addToCache = true
} else {
delay(100)

@ -193,7 +193,7 @@ class ReadRssActivity : VMBaseActivity<ActivityRssReadBinding, ReadRssViewModel>
}
viewModel.urlLiveData.observe(this) {
upJavaScriptEnable()
binding.webView.loadUrl(it.url, it.headerMap)
binding.webView.loadUrl(it.getDirectUrl(), it.headerMap)
}
}

@ -84,7 +84,6 @@ class ReadRssViewModel(application: Application) : BaseViewModel(application),
val analyzeUrl = AnalyzeUrl(
ruleUrl = url,
baseUrl = baseUrl,
useWebView = true,
headerMapF = rssSource?.getHeaderMap()
)
urlLiveData.postValue(analyzeUrl)

Loading…
Cancel
Save