添加多页目录并发访问限制
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user