diff --git a/app/src/main/assets/help/regexHelp.md b/app/src/main/assets/help/regexHelp.md
index 8598c718a..cf0779d80 100644
--- a/app/src/main/assets/help/regexHelp.md
+++ b/app/src/main/assets/help/regexHelp.md
@@ -189,28 +189,6 @@
|g|全局搜索: 搜索整个输入字符串中的所有匹配。|
|m|多行匹配: 会匹配输入字符串每一行。|
-### 5.1 不区分大小写
-
-`i` 修饰符用于执行不区分大小写匹配。例如正则表达式 `/The/gi`,表示: 大写字母 `T`,后跟小写字母 `h`,后跟字母 `e`。
-但是在正则匹配结束时 `i` 标记会告诉正则表达式引擎忽略这种情况。正如你所看到的,我们还使用了 `g` 标记,因为我们要在整个输入字符串中搜索匹配。
"The" => The fat cat sat on the mat.
"/The/gi" => The fat cat sat on the mat.
-
-### 5.2 全局搜索
-
-`g` 修饰符用于执行全局匹配 (会查找所有匹配,不会在查找到第一个匹配时就停止)。
-例如正则表达式 `/.(at)/g`,表示: 除换行符之外的任意字符,后跟小写字母 `a`,后跟小写字母 `t`。
-因为我们在正则表达式的末尾使用了 `g` 标记,它会从整个输入字符串中找到每个匹配项。".(at)" => The fat cat sat on the mat.
"/.(at)/g" => The fat cat sat on the mat.
-
-### 5.3 多行匹配
-
-`m` 修饰符被用来执行多行的匹配。正如我们前面讨论过的 `(^, $)`,使用定位符来检查匹配字符是输入字符串开始或者结束。但是我们希望每一行都使用定位符,所以我们就使用 `m` 修饰符。
-例如正则表达式 `/at(.)?$/gm`,表示: 小写字母 `a`,后跟小写字母 `t`,匹配除了换行符以外任意字符零次或一次。而且因为 `m` 标记,现在正则表达式引擎匹配字符串中每一行的末尾。"/.at(.)?$/" => The fat
- cat sat
- on the mat.
"/.at(.)?$/gm" => The fat
- cat sat
- on the mat.
-
-## 常用正则表达式
-
* **数字**: `\d+$`
* **用户名**: `^[\w\d_.]{4,16}$`
* **字母数字字符**: `^[a-zA-Z0-9]*$`
diff --git a/app/src/main/java/io/legado/app/api/controller/BookController.kt b/app/src/main/java/io/legado/app/api/controller/BookController.kt
index 62abec1be..7239abc47 100644
--- a/app/src/main/java/io/legado/app/api/controller/BookController.kt
+++ b/app/src/main/java/io/legado/app/api/controller/BookController.kt
@@ -9,7 +9,7 @@ import io.legado.app.data.appDb
import io.legado.app.data.entities.Book
import io.legado.app.help.BookHelp
import io.legado.app.help.ContentProcessor
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.model.ReadBook
import io.legado.app.model.localBook.EpubFile
import io.legado.app.model.localBook.LocalBook
diff --git a/app/src/main/java/io/legado/app/help/ImageLoader.kt b/app/src/main/java/io/legado/app/help/glide/ImageLoader.kt
similarity index 95%
rename from app/src/main/java/io/legado/app/help/ImageLoader.kt
rename to app/src/main/java/io/legado/app/help/glide/ImageLoader.kt
index 8b36f397d..62ca20f50 100644
--- a/app/src/main/java/io/legado/app/help/ImageLoader.kt
+++ b/app/src/main/java/io/legado/app/help/glide/ImageLoader.kt
@@ -1,4 +1,4 @@
-package io.legado.app.help
+package io.legado.app.help.glide
import android.content.Context
import android.graphics.Bitmap
@@ -21,7 +21,7 @@ object ImageLoader {
fun load(context: Context, path: String?): RequestBuilder {
return when {
path.isNullOrEmpty() -> Glide.with(context).load(path)
- path.isAbsUrl() -> Glide.with(context).load(AnalyzeUrl(path).getGlideUrl())
+ path.isAbsUrl() -> GlideApp.with(context).load(AnalyzeUrl(path).getGlideUrl())
path.isContentScheme() -> Glide.with(context).load(Uri.parse(path))
else -> kotlin.runCatching {
Glide.with(context).load(File(path))
diff --git a/app/src/main/java/io/legado/app/help/glide/OkHttpGlideModule.kt b/app/src/main/java/io/legado/app/help/glide/OkHttpGlideModule.kt
new file mode 100644
index 000000000..f41871b07
--- /dev/null
+++ b/app/src/main/java/io/legado/app/help/glide/OkHttpGlideModule.kt
@@ -0,0 +1,21 @@
+package io.legado.app.help.glide
+
+import android.content.Context
+import com.bumptech.glide.Glide
+import com.bumptech.glide.Registry
+import com.bumptech.glide.annotation.GlideModule
+import com.bumptech.glide.load.model.GlideUrl
+import com.bumptech.glide.module.AppGlideModule
+import java.io.InputStream
+
+@Suppress("unused")
+@GlideModule
+class OkHttpGlideModule : AppGlideModule() {
+ override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
+ registry.replace(
+ GlideUrl::class.java,
+ InputStream::class.java,
+ OkHttpModeLoaderFactory()
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/help/glide/OkHttpModeLoaderFactory.kt b/app/src/main/java/io/legado/app/help/glide/OkHttpModeLoaderFactory.kt
new file mode 100644
index 000000000..ad06755ea
--- /dev/null
+++ b/app/src/main/java/io/legado/app/help/glide/OkHttpModeLoaderFactory.kt
@@ -0,0 +1,21 @@
+package io.legado.app.help.glide
+
+import com.bumptech.glide.load.model.GlideUrl
+import com.bumptech.glide.load.model.ModelLoader
+import com.bumptech.glide.load.model.ModelLoaderFactory
+import com.bumptech.glide.load.model.MultiModelLoaderFactory
+import io.legado.app.help.http.okHttpClient
+import java.io.InputStream
+
+
+class OkHttpModeLoaderFactory : ModelLoaderFactory {
+
+ override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader {
+ return OkHttpModelLoader(okHttpClient)
+ }
+
+ override fun teardown() {
+ // Do nothing, this instance doesn't own the client.
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/help/glide/OkHttpModelLoader.kt b/app/src/main/java/io/legado/app/help/glide/OkHttpModelLoader.kt
new file mode 100644
index 000000000..3c1c693f5
--- /dev/null
+++ b/app/src/main/java/io/legado/app/help/glide/OkHttpModelLoader.kt
@@ -0,0 +1,24 @@
+package io.legado.app.help.glide
+
+import com.bumptech.glide.load.Options
+import com.bumptech.glide.load.model.GlideUrl
+import com.bumptech.glide.load.model.ModelLoader
+import okhttp3.Call
+import java.io.InputStream
+
+class OkHttpModelLoader(private val client: Call.Factory) : ModelLoader {
+
+ override fun buildLoadData(
+ model: GlideUrl,
+ width: Int,
+ height: Int,
+ options: Options
+ ): ModelLoader.LoadData {
+ return ModelLoader.LoadData(model, OkHttpStreamFetcher(client, model))
+ }
+
+ override fun handles(model: GlideUrl): Boolean {
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt b/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt
new file mode 100644
index 000000000..58d44c505
--- /dev/null
+++ b/app/src/main/java/io/legado/app/help/glide/OkHttpStreamFetcher.kt
@@ -0,0 +1,72 @@
+package io.legado.app.help.glide
+
+import com.bumptech.glide.Priority
+import com.bumptech.glide.load.DataSource
+import com.bumptech.glide.load.HttpException
+import com.bumptech.glide.load.data.DataFetcher
+import com.bumptech.glide.load.model.GlideUrl
+import com.bumptech.glide.util.ContentLengthInputStream
+import com.bumptech.glide.util.Preconditions
+import okhttp3.Call
+import okhttp3.Request
+import okhttp3.Response
+import okhttp3.ResponseBody
+import java.io.IOException
+import java.io.InputStream
+
+
+class OkHttpStreamFetcher(private val client: Call.Factory, private val url: GlideUrl) :
+ DataFetcher, okhttp3.Callback {
+ private var stream: InputStream? = null
+ private var responseBody: ResponseBody? = null
+ private var callback: DataFetcher.DataCallback? = null
+ private var call: Call? = null
+
+ override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) {
+ val requestBuilder: Request.Builder = Request.Builder().url(url.toStringUrl())
+ for ((key, value) in url.headers.entries) {
+ requestBuilder.addHeader(key, value)
+ }
+ val request: Request = requestBuilder.build()
+ this.callback = callback
+ call = client.newCall(request)
+ call?.enqueue(this)
+ }
+
+ override fun cleanup() {
+ try {
+ stream?.close()
+ } catch (e: IOException) {
+ // Ignored
+ }
+ responseBody?.close()
+ callback = null
+ }
+
+ override fun cancel() {
+ call?.cancel()
+ }
+
+ override fun getDataClass(): Class {
+ return InputStream::class.java
+ }
+
+ override fun getDataSource(): DataSource {
+ return DataSource.REMOTE
+ }
+
+ override fun onFailure(call: Call, e: IOException) {
+ callback?.onLoadFailed(e)
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ responseBody = response.body
+ if (response.isSuccessful) {
+ val contentLength: Long = Preconditions.checkNotNull(responseBody).contentLength()
+ stream = ContentLengthInputStream.obtain(responseBody!!.byteStream(), contentLength)
+ callback!!.onDataReady(stream)
+ } else {
+ callback!!.onLoadFailed(HttpException(response.message, response.code))
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt
index d13b395ca..5474bc1ed 100644
--- a/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/audio/AudioPlayActivity.kt
@@ -20,7 +20,7 @@ import io.legado.app.constant.Theme
import io.legado.app.data.entities.Book
import io.legado.app.databinding.ActivityAudioPlayBinding
import io.legado.app.help.BlurTransformation
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.lib.dialogs.alert
import io.legado.app.service.help.AudioPlay
import io.legado.app.ui.book.changesource.ChangeSourceDialog
diff --git a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
index 17191768c..cc525b035 100644
--- a/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
+++ b/app/src/main/java/io/legado/app/ui/book/info/BookInfoActivity.kt
@@ -23,7 +23,7 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookChapter
import io.legado.app.databinding.ActivityBookInfoBinding
import io.legado.app.help.BlurTransformation
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.lib.dialogs.alert
import io.legado.app.lib.theme.backgroundColor
import io.legado.app.lib.theme.bottomBackground
diff --git a/app/src/main/java/io/legado/app/ui/book/read/config/BgAdapter.kt b/app/src/main/java/io/legado/app/ui/book/read/config/BgAdapter.kt
index f0d8ac752..439f8d554 100644
--- a/app/src/main/java/io/legado/app/ui/book/read/config/BgAdapter.kt
+++ b/app/src/main/java/io/legado/app/ui/book/read/config/BgAdapter.kt
@@ -6,10 +6,9 @@ import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.constant.EventBus
import io.legado.app.databinding.ItemBgImageBinding
-import io.legado.app.help.ImageLoader
import io.legado.app.help.ReadBookConfig
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.postEvent
-
import java.io.File
class BgAdapter(context: Context, val textColor: Int) :
diff --git a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt
index 1af9bdb9b..b3df28b0d 100644
--- a/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt
+++ b/app/src/main/java/io/legado/app/ui/main/rss/RssAdapter.kt
@@ -9,7 +9,7 @@ import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.data.entities.RssSource
import io.legado.app.databinding.ItemRssBinding
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import splitties.views.onLongClick
class RssAdapter(context: Context, val callBack: CallBack) :
diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt
index cb5605bc9..b79d8f18f 100644
--- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter.kt
@@ -11,7 +11,7 @@ import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.data.entities.RssArticle
import io.legado.app.databinding.ItemRssArticleBinding
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.gone
import io.legado.app.utils.visible
diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter1.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter1.kt
index 574825624..d92fb4b94 100644
--- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter1.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter1.kt
@@ -11,7 +11,7 @@ import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.data.entities.RssArticle
import io.legado.app.databinding.ItemRssArticle1Binding
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.gone
import io.legado.app.utils.visible
diff --git a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter2.kt b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter2.kt
index c4fef291e..5a512a063 100644
--- a/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter2.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/article/RssArticlesAdapter2.kt
@@ -11,7 +11,7 @@ import io.legado.app.R
import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.data.entities.RssArticle
import io.legado.app.databinding.ItemRssArticle2Binding
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.getCompatColor
import io.legado.app.utils.gone
import io.legado.app.utils.visible
diff --git a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesAdapter.kt b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesAdapter.kt
index 71feb0e4d..ba0a252c2 100644
--- a/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesAdapter.kt
+++ b/app/src/main/java/io/legado/app/ui/rss/favorites/RssFavoritesAdapter.kt
@@ -11,7 +11,7 @@ import io.legado.app.base.adapter.ItemViewHolder
import io.legado.app.base.adapter.RecyclerAdapter
import io.legado.app.data.entities.RssStar
import io.legado.app.databinding.ItemRssArticleBinding
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.gone
import io.legado.app.utils.visible
diff --git a/app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt b/app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
index 986ac63e4..0105fe933 100644
--- a/app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
+++ b/app/src/main/java/io/legado/app/ui/widget/image/CoverImageView.kt
@@ -13,7 +13,7 @@ import com.bumptech.glide.request.target.Target
import io.legado.app.R
import io.legado.app.constant.PreferKey
import io.legado.app.help.AppConfig
-import io.legado.app.help.ImageLoader
+import io.legado.app.help.glide.ImageLoader
import io.legado.app.utils.getPrefString
import splitties.init.appCtx