添加多页目录并发访问限制

pull/2481/head
kunfei 2 years ago
parent 20c2daeadb
commit 118be1d2e4
  1. 31
      app/src/main/java/io/legado/app/model/analyzeRule/AnalyzeUrl.kt
  2. 39
      app/src/main/java/io/legado/app/model/webBook/BookChapterList.kt

@ -3,9 +3,9 @@ package io.legado.app.model.analyzeRule
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Base64 import android.util.Base64
import androidx.annotation.Keep import androidx.annotation.Keep
import cn.hutool.core.util.HexUtil
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.script.SimpleBindings import com.script.SimpleBindings
import cn.hutool.core.util.HexUtil
import io.legado.app.constant.AppConst.SCRIPT_ENGINE import io.legado.app.constant.AppConst.SCRIPT_ENGINE
import io.legado.app.constant.AppConst.UA_NAME import io.legado.app.constant.AppConst.UA_NAME
import io.legado.app.constant.AppPattern.JS_PATTERN import io.legado.app.constant.AppPattern.JS_PATTERN
@ -279,6 +279,7 @@ class AnalyzeUrl(
/** /**
* 开始访问,并发判断 * 开始访问,并发判断
*/ */
@Throws(ConcurrentException::class)
private fun fetchStart(): ConcurrentRecord? { private fun fetchStart(): ConcurrentRecord? {
source ?: return null source ?: return null
val concurrentRate = source.concurrentRate val concurrentRate = source.concurrentRate
@ -294,10 +295,13 @@ class AnalyzeUrl(
} }
val waitTime: Int = synchronized(fetchRecord) { val waitTime: Int = synchronized(fetchRecord) {
try { try {
if (rateIndex == -1) { if (!fetchRecord.isConcurrent) {
//并发控制非 次数/毫秒
if (fetchRecord.frequency > 0) { if (fetchRecord.frequency > 0) {
//已经有访问线程,直接等待
return@synchronized concurrentRate.toInt() return@synchronized concurrentRate.toInt()
} }
//没有线程访问,判断还剩多少时间可以访问
val nextTime = fetchRecord.time + concurrentRate.toInt() val nextTime = fetchRecord.time + concurrentRate.toInt()
if (System.currentTimeMillis() >= nextTime) { if (System.currentTimeMillis() >= nextTime) {
fetchRecord.time = System.currentTimeMillis() fetchRecord.time = System.currentTimeMillis()
@ -306,9 +310,11 @@ class AnalyzeUrl(
} }
return@synchronized (nextTime - System.currentTimeMillis()).toInt() return@synchronized (nextTime - System.currentTimeMillis()).toInt()
} else { } else {
//并发控制为 次数/毫秒
val sj = concurrentRate.substring(rateIndex + 1) val sj = concurrentRate.substring(rateIndex + 1)
val nextTime = fetchRecord.time + sj.toInt() val nextTime = fetchRecord.time + sj.toInt()
if (System.currentTimeMillis() >= nextTime) { if (System.currentTimeMillis() >= nextTime) {
//已经过了限制时间,重置开始时间
fetchRecord.time = System.currentTimeMillis() fetchRecord.time = System.currentTimeMillis()
fetchRecord.frequency = 1 fetchRecord.frequency = 1
return@synchronized 0 return@synchronized 0
@ -335,7 +341,7 @@ class AnalyzeUrl(
* 访问结束 * 访问结束
*/ */
private fun fetchEnd(concurrentRecord: ConcurrentRecord?) { private fun fetchEnd(concurrentRecord: ConcurrentRecord?) {
if (concurrentRecord != null && !concurrentRecord.concurrent) { if (concurrentRecord != null && !concurrentRecord.isConcurrent) {
synchronized(concurrentRecord) { synchronized(concurrentRecord) {
concurrentRecord.frequency = concurrentRecord.frequency - 1 concurrentRecord.frequency = concurrentRecord.frequency - 1
} }
@ -345,6 +351,7 @@ class AnalyzeUrl(
/** /**
* 访问网站,返回StrResponse * 访问网站,返回StrResponse
*/ */
@Throws(ConcurrentException::class)
suspend fun getStrResponseAwait( suspend fun getStrResponseAwait(
jsStr: String? = null, jsStr: String? = null,
sourceRegex: String? = null, sourceRegex: String? = null,
@ -414,6 +421,7 @@ class AnalyzeUrl(
} }
@JvmOverloads @JvmOverloads
@Throws(ConcurrentException::class)
fun getStrResponse( fun getStrResponse(
jsStr: String? = null, jsStr: String? = null,
sourceRegex: String? = null, sourceRegex: String? = null,
@ -427,6 +435,7 @@ class AnalyzeUrl(
/** /**
* 访问网站,返回Response * 访问网站,返回Response
*/ */
@Throws(ConcurrentException::class)
suspend fun getResponseAwait(): Response { suspend fun getResponseAwait(): Response {
val concurrentRecord = fetchStart() val concurrentRecord = fetchStart()
try { try {
@ -457,6 +466,7 @@ class AnalyzeUrl(
} }
} }
@Throws(ConcurrentException::class)
fun getResponse(): Response { fun getResponse(): Response {
return runBlocking { return runBlocking {
getResponseAwait() getResponseAwait()
@ -464,6 +474,7 @@ class AnalyzeUrl(
} }
@Suppress("UnnecessaryVariable") @Suppress("UnnecessaryVariable")
@Throws(ConcurrentException::class)
private fun getByteArrayIfDataUri(): ByteArray? { private fun getByteArrayIfDataUri(): ByteArray? {
@Suppress("RegExpRedundantEscape") @Suppress("RegExpRedundantEscape")
val dataUriFindResult = dataUriRegex.find(urlNoQuery) val dataUriFindResult = dataUriRegex.find(urlNoQuery)
@ -480,6 +491,7 @@ class AnalyzeUrl(
* 访问网站,返回ByteArray * 访问网站,返回ByteArray
*/ */
@Suppress("UnnecessaryVariable", "LiftReturnOrAssignment") @Suppress("UnnecessaryVariable", "LiftReturnOrAssignment")
@Throws(ConcurrentException::class)
suspend fun getByteArrayAwait(): ByteArray { suspend fun getByteArrayAwait(): ByteArray {
getByteArrayIfDataUri()?.let { getByteArrayIfDataUri()?.let {
return it return it
@ -497,6 +509,7 @@ class AnalyzeUrl(
* 访问网站,返回InputStream * 访问网站,返回InputStream
*/ */
@Suppress("LiftReturnOrAssignment") @Suppress("LiftReturnOrAssignment")
@Throws(ConcurrentException::class)
suspend fun getInputStreamAwait(): InputStream { suspend fun getInputStreamAwait(): InputStream {
getByteArrayIfDataUri()?.let { getByteArrayIfDataUri()?.let {
return ByteArrayInputStream(it) return ByteArrayInputStream(it)
@ -504,6 +517,7 @@ class AnalyzeUrl(
return getResponseAwait().body!!.byteStream() return getResponseAwait().body!!.byteStream()
} }
@Throws(ConcurrentException::class)
fun getInputStream(): InputStream { fun getInputStream(): InputStream {
return runBlocking { return runBlocking {
getInputStreamAwait() getInputStreamAwait()
@ -679,8 +693,17 @@ class AnalyzeUrl(
} }
data class ConcurrentRecord( data class ConcurrentRecord(
val concurrent: Boolean, /**
* 是否按频率
*/
val isConcurrent: Boolean,
/**
* 开始访问时间
*/
var time: Long, var time: Long,
/**
* 正在访问的个数
*/
var frequency: Int var frequency: Int
) )

@ -6,15 +6,18 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.rule.TocRule import io.legado.app.data.entities.rule.TocRule
import io.legado.app.exception.ConcurrentException
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.exception.TocEmptyException import io.legado.app.exception.TocEmptyException
import io.legado.app.help.book.ContentProcessor import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.http.StrResponse
import io.legado.app.model.Debug import io.legado.app.model.Debug
import io.legado.app.model.analyzeRule.AnalyzeRule import io.legado.app.model.analyzeRule.AnalyzeRule
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.utils.isTrue import io.legado.app.utils.isTrue
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import splitties.init.appCtx import splitties.init.appCtx
@ -61,12 +64,26 @@ object BookChapterList {
var nextUrl = chapterData.second[0] var nextUrl = chapterData.second[0]
while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) { while (nextUrl.isNotEmpty() && !nextUrlList.contains(nextUrl)) {
nextUrlList.add(nextUrl) nextUrlList.add(nextUrl)
AnalyzeUrl( val analyzeUrl = AnalyzeUrl(
mUrl = nextUrl, mUrl = nextUrl,
source = bookSource, source = bookSource,
ruleData = book, ruleData = book,
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
).getStrResponseAwait().body?.let { nextBody -> )
var res: StrResponse? = null
var isConcurrent: Boolean
do {
//控制并发访问
isConcurrent = false
try {
res = analyzeUrl.getStrResponseAwait()
} catch (e: ConcurrentException) {
isConcurrent = true
//如果是并发限制等待再次访问
delay(e.waitTime.toLong())
}
} while (!isConcurrent)
res!!.body?.let { nextBody ->
chapterData = analyzeChapterList( chapterData = analyzeChapterList(
book, nextUrl, nextUrl, book, nextUrl, nextUrl,
nextBody, tocRule, listRule, bookSource nextBody, tocRule, listRule, bookSource
@ -89,10 +106,22 @@ object BookChapterList {
ruleData = book, ruleData = book,
headerMapF = bookSource.getHeaderMap() headerMapF = bookSource.getHeaderMap()
) )
val res = analyzeUrl.getStrResponseAwait() var res: StrResponse? = null
var isConcurrent: Boolean
do {
//控制并发访问
isConcurrent = false
try {
res = analyzeUrl.getStrResponseAwait()
} catch (e: ConcurrentException) {
isConcurrent = true
//如果是并发限制等待再次访问
delay(e.waitTime.toLong())
}
} while (!isConcurrent)
analyzeChapterList( analyzeChapterList(
book, urlStr, res.url, book, urlStr, res!!.url,
res.body!!, tocRule, listRule, bookSource, false res!!.body!!, tocRule, listRule, bookSource, false
).first ).first
} }
} }

Loading…
Cancel
Save