Merge remote-tracking branch 'source/master'
This commit is contained in:
commit
2f06e144e3
124 files changed
+2971
-805
No files matched your search
@@ -54,6 +54,7 @@ Legado is a free and open source novel reader for Android.
|
||||
* [Coolapk](https://www.coolapk.com/apk/io.legado.app.release)
|
||||
* [Jsdelivr](https://cdn.jsdelivr.net/gh/gedoor/release@release/)
|
||||
* [\#Beta](https://kunfei.lanzoui.com/b0f810h4b)
|
||||
* [IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/io.legado.app.release)
|
||||
|
||||
|
||||
#### IOS-苹果
|
||||
|
||||
@@ -1,30 +1,37 @@
|
||||
# 阅读API
|
||||
|
||||
## 对于Web的配置
|
||||
您需要先在设置中启用"Web 服务"。
|
||||
|
||||
您需要先在设置中启用"Web 服务"。
|
||||
|
||||
## 使用
|
||||
|
||||
### Web
|
||||
|
||||
以下说明假设您的操作在本机进行,且开放端口为1234。
|
||||
如果您要从远程计算机访问[阅读](),请将`127.0.0.1`替换成手机IP。
|
||||
|
||||
#### 插入单个书源
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt)
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/saveSource
|
||||
Method = POST
|
||||
```
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt)
|
||||
|
||||
#### 插入多个书源or订阅源
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/saveBookSources
|
||||
URL = http://127.0.0.1:1234/saveRssSources
|
||||
Method = POST
|
||||
```
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
#### 获取书源
|
||||
|
||||
```
|
||||
@@ -43,151 +50,172 @@ Method = GET
|
||||
|
||||
#### 删除多个书源or订阅源
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/deleteBookSources
|
||||
URL = http://127.0.0.1:1234/deleteRssSources
|
||||
Method = POST
|
||||
```
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
#### 插入书籍
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/saveBook
|
||||
Method = POST
|
||||
```
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。
|
||||
|
||||
#### 获取所有书籍
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/getBookshelf
|
||||
Method = GET
|
||||
```
|
||||
|
||||
获取APP内的所有书籍。
|
||||
获取APP内的所有书籍。
|
||||
|
||||
#### 获取书籍章节列表
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/getChapterList?url=xxx
|
||||
Method = GET
|
||||
```
|
||||
|
||||
获取指定图书的章节列表。
|
||||
获取指定图书的章节列表。
|
||||
|
||||
#### 获取书籍内容
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/getBookContent?url=xxx&index=1
|
||||
Method = GET
|
||||
```
|
||||
|
||||
获取指定图书的第`index`章节的文本内容。
|
||||
|
||||
#### 获取封面
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/cover?path=xxxxx
|
||||
Method = GET
|
||||
```
|
||||
|
||||
#### 保存书籍进度
|
||||
|
||||
请求BODY内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookProgress.kt)。
|
||||
|
||||
```
|
||||
URL = http://127.0.0.1:1234/saveBookProgress
|
||||
Method = POST
|
||||
```
|
||||
|
||||
### Content Provider
|
||||
|
||||
* 需声明`io.legado.READ_WRITE`权限
|
||||
* `providerHost`为`包名.readerProvider`, 如`io.legado.app.release.readerProvider`,不同包的地址不同,防止冲突安装失败
|
||||
* 以下出现的`providerHost`请自行替换
|
||||
|
||||
#### 插入单个书源or订阅源
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt)
|
||||
|
||||
```
|
||||
URL = content://providerHost/bookSource/insert
|
||||
URL = content://providerHost/rssSource/insert
|
||||
Method = insert
|
||||
```
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt)
|
||||
|
||||
#### 插入多个书源or订阅源
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
```
|
||||
URL = content://providerHost/bookSources/insert
|
||||
URL = content://providerHost/rssSources/insert
|
||||
Method = insert
|
||||
```
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
#### 获取书源or订阅源
|
||||
|
||||
获取指定URL对应的书源信息。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
```
|
||||
URL = content://providerHost/bookSource/query?url=xxx
|
||||
URL = content://providerHost/rssSource/query?url=xxx
|
||||
Method = query
|
||||
```
|
||||
|
||||
获取指定URL对应的书源信息。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
#### 获取所有书源or订阅源
|
||||
|
||||
获取APP内的所有订阅源。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
```
|
||||
URL = content://providerHost/bookSources/query
|
||||
URL = content://providerHost/rssSources/query
|
||||
Method = query
|
||||
```
|
||||
|
||||
获取APP内的所有书源。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
#### 删除多个书源or订阅源
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
```
|
||||
URL = content://providerHost/bookSources/delete
|
||||
URL = content://providerHost/rssSources/delete
|
||||
Method = delete
|
||||
```
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。
|
||||
|
||||
#### 插入书籍
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。
|
||||
|
||||
```
|
||||
URL = content://providerHost/book/insert
|
||||
Method = insert
|
||||
```
|
||||
|
||||
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串,
|
||||
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。
|
||||
|
||||
#### 获取所有书籍
|
||||
|
||||
获取APP内的所有书籍。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
```
|
||||
URL = content://providerHost/books/query
|
||||
Method = query
|
||||
```
|
||||
|
||||
获取APP内的所有书籍。
|
||||
#### 获取书籍章节列表
|
||||
|
||||
获取指定图书的章节列表。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
#### 获取书籍章节列表
|
||||
```
|
||||
URL = content://providerHost/book/chapter/query?url=xxx
|
||||
Method = query
|
||||
```
|
||||
|
||||
获取指定图书的章节列表。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
#### 获取书籍内容
|
||||
|
||||
获取指定图书的第`index`章节的文本内容。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
```
|
||||
URL = content://providerHost/book/content/query?url=xxx&index=1
|
||||
Method = query
|
||||
```
|
||||
获取指定图书的第`index`章节的文本内容。
|
||||
用`Cursor.getString(0)`取出返回结果。
|
||||
|
||||
#### 获取封面
|
||||
|
||||
```
|
||||
URL = content://providerHost/book/cover/query?path=xxxx
|
||||
Method = query
|
||||
|
||||
+6
-4
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-parcelize'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'de.timfreiheit.resourceplaceholders'
|
||||
//apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply from: 'download.gradle'
|
||||
|
||||
static def releaseTime() {
|
||||
@@ -179,8 +179,10 @@ dependencies {
|
||||
androidTestImplementation 'androidx.compose.ui:ui-test-junit4:1.1.1'
|
||||
|
||||
//firebase
|
||||
//implementation platform('com.google.firebase:firebase-bom:29.1.0')
|
||||
//implementation 'com.google.firebase:firebase-analytics-ktx'
|
||||
implementation platform('com.google.firebase:firebase-bom:30.0.1')
|
||||
implementation 'com.google.firebase:firebase-analytics-ktx:21.0.0'
|
||||
implementation platform('com.google.firebase:firebase-bom:30.0.1')
|
||||
implementation 'com.google.firebase:firebase-perf-ktx:20.0.6'
|
||||
|
||||
//media
|
||||
implementation("androidx.media:media:1.6.0")
|
||||
@@ -219,7 +221,7 @@ dependencies {
|
||||
implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))
|
||||
|
||||
//Glide
|
||||
def glideVersion = "4.13.1"
|
||||
def glideVersion = "4.13.2"
|
||||
implementation("com.github.bumptech.glide:glide:$glideVersion")
|
||||
kapt("com.github.bumptech.glide:compiler:$glideVersion")
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.legado.app">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
@Json: json规则,直接写时以$.开头可省略@Json
|
||||
: regex规则,不可省略,只可以用在书籍列表和目录列表
|
||||
```
|
||||
* 书源类型: 文件
|
||||
> 对于类似知轩藏书提供文件整合下载的网站,可以'在书源详情的下载URL规则获取文件链接,支持多个链接,阅读会自动下载并导入
|
||||
|
||||
* CookieJar
|
||||
> 启用后会自动保存每次返回头中的Set-Cookie中的值,适用于验证码图片一类需要session的网站
|
||||
* 登录UI
|
||||
> 不使用内置webView登录网站,需要使用`登录URL`规则实现登录逻辑,可使用`登录检查JS`检查登录结果
|
||||
```
|
||||
|
||||
@@ -11,6 +11,25 @@
|
||||
* 正文出现缺字漏字、内容缺失、排版错乱等情况,有可能是净化规则或简繁转换出现问题。
|
||||
* 漫画源看书显示乱码,**阅读与其他软件的源并不通用**,请导入阅读的支持的漫画源!
|
||||
|
||||
**2022/05/16**
|
||||
|
||||
* 添加firebase性能监测
|
||||
* 清除cookie时清除webView的cookie
|
||||
|
||||
**2022/05/15**
|
||||
|
||||
* 源编辑添加cookieJar选项
|
||||
* 源编辑菜单里添加清除cookie,如果之前能用的书源不能用了,可以关闭cookieJar后点下菜单里的清除cookie后再试
|
||||
* 书源支持文件类型 by Xwite
|
||||
* 启用firebase收集崩溃日志
|
||||
* web端阅读实现无限滚动 by Xwite
|
||||
* 进入阅读界面时如果本地书籍有更新自动刷新目录
|
||||
|
||||
**2022/05/11**
|
||||
|
||||
* 修复替换报错的bug
|
||||
* 优化目录界面替换
|
||||
|
||||
**2022/05/10**
|
||||
|
||||
* 更新cronet: 101.0.4951.61
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<div>
|
||||
<div>源类型 :</div>
|
||||
<textarea rows="1" id="bookSourceType" class="base" title="bookSourceType"
|
||||
placeholder="<必填>0:文本 1:音频 2:图片"></textarea>
|
||||
placeholder="<必填>0:文本 1:音频 2:图片 3:文件(只提供下载的网站)"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div>源名称 :</div>
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
@charset "UTF-8";@font-face{font-family:FZZCYSK;src:local("☺"),url(../fonts/shelffont.6c094b6d.ttf);font-style:normal;font-weight:400}.index-wrapper[data-v-570ed4a8]{height:100%;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.index-wrapper .navigation-wrapper[data-v-570ed4a8]{width:260px;min-width:260px;padding:48px 36px;background-color:#f7f7f7}.index-wrapper .navigation-wrapper .navigation-title[data-v-570ed4a8]{font-size:24px;font-weight:500;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .navigation-sub-title[data-v-570ed4a8]{font-size:16px;font-weight:300;font-family:FZZCYSK;margin-top:16px;color:#b1b1b1}.index-wrapper .navigation-wrapper .search-wrapper .search-input[data-v-570ed4a8]{border-radius:50%;margin-top:24px}.index-wrapper .navigation-wrapper .search-wrapper .search-input[data-v-570ed4a8] .el-input__inner{border-radius:50px;border-color:#e3e3e3}.index-wrapper .navigation-wrapper .recent-wrapper[data-v-570ed4a8]{margin-top:36px}.index-wrapper .navigation-wrapper .recent-wrapper .recent-title[data-v-570ed4a8]{font-size:14px;color:#b1b1b1;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .recent-wrapper .reading-recent[data-v-570ed4a8]{margin:18px 0}.index-wrapper .navigation-wrapper .recent-wrapper .reading-recent .recent-book[data-v-570ed4a8]{font-size:10px;cursor:pointer}.index-wrapper .navigation-wrapper .setting-wrapper[data-v-570ed4a8]{margin-top:36px}.index-wrapper .navigation-wrapper .setting-wrapper .setting-title[data-v-570ed4a8]{font-size:14px;color:#b1b1b1;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .setting-wrapper .no-point[data-v-570ed4a8]{pointer-events:none}.index-wrapper .navigation-wrapper .setting-wrapper .setting-connect[data-v-570ed4a8]{font-size:8px;margin-top:16px;cursor:pointer}.index-wrapper .navigation-wrapper .bottom-icons[data-v-570ed4a8]{position:fixed;bottom:0;height:120px;width:260px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.index-wrapper .shelf-wrapper[data-v-570ed4a8]{padding:48px 48px;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.index-wrapper .shelf-wrapper[data-v-570ed4a8] .el-icon-loading{font-size:36px;color:#b5b5b5}.index-wrapper .shelf-wrapper[data-v-570ed4a8] .el-loading-text{font-weight:500;color:#b5b5b5}.index-wrapper .shelf-wrapper .books-wrapper[data-v-570ed4a8]{overflow:scroll}.index-wrapper .shelf-wrapper .books-wrapper .wrapper[data-v-570ed4a8]{display:grid;grid-template-columns:repeat(auto-fill,380px);-ms-flex-pack:distribute;justify-content:space-around;grid-gap:10px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book[data-v-570ed4a8]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-bottom:18px;padding:24px 24px;width:360px;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:distribute;justify-content:space-around}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .cover-img .cover[data-v-570ed4a8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .cover-img[data-v-570ed4a8]{width:84px;height:112px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info[data-v-570ed4a8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:left;-ms-flex-align:left;align-items:left;height:112px;margin-left:20px;-webkit-box-flex:1;-ms-flex:1;flex:1}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .name[data-v-570ed4a8]{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;font-size:16px;font-weight:700;color:#33373d}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .sub[data-v-570ed4a8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;font-size:12px;font-weight:600;color:#6b6b6b}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .sub .dot[data-v-570ed4a8]{margin:0 7px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .dur-chapter[data-v-570ed4a8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .intro[data-v-570ed4a8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .last-chapter[data-v-570ed4a8]{color:#969ba3;font-size:13px;margin-top:3px;font-weight:500;word-wrap:break-word;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;Line truncated
|
||||
@charset "UTF-8";@font-face{font-family:FZZCYSK;src:local("☺"),url(../fonts/shelffont.6c094b6d.ttf);font-style:normal;font-weight:400}.index-wrapper[data-v-4587cbc8]{height:100%;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.index-wrapper .navigation-wrapper[data-v-4587cbc8]{width:260px;min-width:260px;padding:48px 36px;background-color:#f7f7f7}.index-wrapper .navigation-wrapper .navigation-title[data-v-4587cbc8]{font-size:24px;font-weight:500;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .navigation-sub-title[data-v-4587cbc8]{font-size:16px;font-weight:300;font-family:FZZCYSK;margin-top:16px;color:#b1b1b1}.index-wrapper .navigation-wrapper .search-wrapper .search-input[data-v-4587cbc8]{border-radius:50%;margin-top:24px}.index-wrapper .navigation-wrapper .search-wrapper .search-input[data-v-4587cbc8] .el-input__inner{border-radius:50px;border-color:#e3e3e3}.index-wrapper .navigation-wrapper .recent-wrapper[data-v-4587cbc8]{margin-top:36px}.index-wrapper .navigation-wrapper .recent-wrapper .recent-title[data-v-4587cbc8]{font-size:14px;color:#b1b1b1;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .recent-wrapper .reading-recent[data-v-4587cbc8]{margin:18px 0}.index-wrapper .navigation-wrapper .recent-wrapper .reading-recent .recent-book[data-v-4587cbc8]{font-size:10px;cursor:pointer}.index-wrapper .navigation-wrapper .setting-wrapper[data-v-4587cbc8]{margin-top:36px}.index-wrapper .navigation-wrapper .setting-wrapper .setting-title[data-v-4587cbc8]{font-size:14px;color:#b1b1b1;font-family:FZZCYSK}.index-wrapper .navigation-wrapper .setting-wrapper .no-point[data-v-4587cbc8]{pointer-events:none}.index-wrapper .navigation-wrapper .setting-wrapper .setting-connect[data-v-4587cbc8]{font-size:8px;margin-top:16px;cursor:pointer}.index-wrapper .navigation-wrapper .bottom-icons[data-v-4587cbc8]{position:fixed;bottom:0;height:120px;width:260px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.index-wrapper .shelf-wrapper[data-v-4587cbc8]{padding:48px 48px;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.index-wrapper .shelf-wrapper[data-v-4587cbc8] .el-icon-loading{font-size:36px;color:#b5b5b5}.index-wrapper .shelf-wrapper[data-v-4587cbc8] .el-loading-text{font-weight:500;color:#b5b5b5}.index-wrapper .shelf-wrapper .books-wrapper[data-v-4587cbc8]{overflow:scroll}.index-wrapper .shelf-wrapper .books-wrapper .wrapper[data-v-4587cbc8]{display:grid;grid-template-columns:repeat(auto-fill,380px);-ms-flex-pack:distribute;justify-content:space-around;grid-gap:10px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book[data-v-4587cbc8]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-bottom:18px;padding:24px 24px;width:360px;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-pack:distribute;justify-content:space-around}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .cover-img .cover[data-v-4587cbc8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .cover-img[data-v-4587cbc8]{width:84px;height:112px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info[data-v-4587cbc8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:distribute;justify-content:space-around;-webkit-box-align:left;-ms-flex-align:left;align-items:left;height:112px;margin-left:20px;-webkit-box-flex:1;-ms-flex:1;flex:1}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .name[data-v-4587cbc8]{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;font-size:16px;font-weight:700;color:#33373d}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .sub[data-v-4587cbc8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;font-size:12px;font-weight:600;color:#6b6b6b}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .sub .dot[data-v-4587cbc8]{margin:0 7px}.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .dur-chapter[data-v-4587cbc8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .intro[data-v-4587cbc8],.index-wrapper .shelf-wrapper .books-wrapper .wrapper .book .info .last-chapter[data-v-4587cbc8]{color:#969ba3;font-size:13px;margin-top:3px;font-weight:500;word-wrap:break-word;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;Line truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
@charset "UTF-8";@font-face{font-family:FZZCYSK;src:local("☺"),url(../fonts/popfont.f39ecc1a.ttf);font-style:normal;font-weight:400}.cata-wrapper[data-v-0aacaab8]{margin:-16px;padding:18px 0 24px 25px}.cata-wrapper .title[data-v-0aacaab8]{font-size:18px;font-weight:400;font-family:FZZCYSK;margin:0 0 20px 0;color:#ed4259;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;border-bottom:1px solid #ed4259}.cata-wrapper .data-wrapper[data-v-0aacaab8]{height:300px;overflow:auto}.cata-wrapper .data-wrapper .cata[data-v-0aacaab8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.cata-wrapper .data-wrapper .cata .selected[data-v-0aacaab8]{color:#eb4259}.cata-wrapper .data-wrapper .cata .log[data-v-0aacaab8]{width:50%;height:40px;cursor:pointer;float:left;font:16px/40px PingFangSC-Regular,HelveticaNeue-Light,Helvetica Neue Light,Microsoft YaHei,sans-serif}.cata-wrapper .data-wrapper .cata .log .log-text[data-v-0aacaab8]{margin-right:26px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.cata-wrapper .night[data-v-0aacaab8] .log{border-bottom:1px solid #666}.cata-wrapper .day[data-v-0aacaab8] .log{border-bottom:1px solid #f2f2f2}@media screen and (max-width:500px){.cata-wrapper .data-wrapper .cata .log[data-v-0aacaab8]{width:100%}}@font-face{font-family:iconfont;src:url(../fonts/iconfont.f9a3fb0e.woff) format("woff")}[data-v-65e7f0f4] .iconfont,[data-v-65e7f0f4] .moon-icon{font-family:iconfont;font-style:normal}.settings-wrapper[data-v-65e7f0f4]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:-13px;height:300px;text-align:left;padding:40px 0 40px 24px;background:#ede7da url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyBAMAAADsEZWCAAAAD1BMVEX48dr48Nf58tv379X17NJtIBxUAAACFUlEQVQ4y1XRUZakMAgF0Af2AiDWApDZgHZqAV1nZv9rGh7Rj7Y8McUFEg1wvcMESMNVD/neU8Xcaz7nYYkYlYO6Ti82PBI4BvIEg1aj3wKwRvIMgZsUy5LdhCawPFh1sZs4SrlyN9fQKpv8s5dgZ2eLyqqJiu+WkCmUEybXkm3INS01WAiv0PapJ0CZc0SJQUzcWnZYbOOY20iFD8Bk+/j2A3wNxH7GdShFYS5ff237kXh9I9zSkQmIAhOsOSVfJ6DIXTMDaPnzkRJ92S1BQQmXl5LdirgRLLDdcYqcGPwe3QN4xCBiGNbrqq9wpW1XCecChwaQdVOsRDpPCpeoolPdxeXp3WNB9PHVzWBHlygy4NJCCrFHREv6bDt0VGwJZASkpONmm1UseGeFKAQexgaAkrfYWl3AGxWOLL2AIMBNbCXpktmS3k3vHeYjGCPBa43wJTurO3ZFVpQSJdAZGLoHTyk1upkjxMEaIxum3iIARcCa5kSkFAW5fi1mUlL9eyOsaanFmOMruwvEdE3ZYzsRSzo5ewRLXyVPPEvknt8ij4DvCg2O7xOgBCUprEzV4z1WekSpUgI8DT2mrnSOXKRfQavwuKA1F+tFnMKdJSUpMA7wQAifWRkMgjUKKZE4lBl6MCM4B1pq1P4uIjDE6Pq6rL0FnW1nIFmta5vrSvq/Ch4tpqG/ZNyyWa5jZPktq81eYv8Bt5s4iFITOp4AAAAASUVORK5CYII=) repeat}.settings-wrapper .settings-title[data-v-65e7f0f4]{font-size:18px;line-height:22px;margin-bottom:28px;font-family:FZZCYSK;font-weight:400}.settings-wrapper .setting-list ul[data-v-65e7f0f4]{list-style:none outside none;margin:0;padding:0}.settings-wrapper .setting-list ul li[data-v-65e7f0f4]{list-style:none outside none}.settings-wrapper .setting-list ul li i[data-v-65e7f0f4]{font:12px/16px PingFangSC-Regular,-apple-system,Simsun;display:inline-block;min-width:48px;margin-right:16px;vertical-align:middle;color:#666}.settings-wrapper .setting-list ul li .theme-item[data-v-65e7f0f4]{line-height:32px;width:34px;height:34px;margin-right:16px;margin-top:5px;border-radius:100%;display:inline-block;cursor:pointer;text-align:center;vertical-align:middle}.settings-wrapper .setting-list ul li .theme-item .iconfont[data-v-65e7f0f4]{display:none}.settings-wrapper .setting-list ul li .selected[data-v-65e7f0f4]{color:#ed4259}.settings-wrapper .setting-list ul li .selected .iconfont[data-v-65e7f0f4]{display:inline}.settings-wrapper .setting-list ul .font-list[data-v-65e7f0f4]{margin-top:28px}.settings-wrapper .setting-list ul .font-list .font-item[data-v-65e7f0f4]{width:78px;height:34px;cursor:pointer;margin-right:16px;border-radius:2px;text-align:center;vertical-align:middle;display:inline-block;font:14px/34px PingFangSC-Regular,HelveticaNeue-Light,Helvetica Neue Light,Microsoft YaHei,sans-serif}.settings-wrapper .setting-list ul .font-list .font-item[data-v-65e7f0f4]:hover,.settings-wrapper .setting-list ul .font-list .selected[data-v-65e7f0f4]{color:#ed4259;border:1px solid #ed4259}.settings-wrapper .setting-list ul .font-size[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width[data-v-65e7f0f4]{margin-top:28px}.settings-wrapper .setting-list ul .font-size .resize[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width .resize[data-v-65e7f0f4]{display:inline-block;width:274px;height:34px;vertical-align:middle;border-radius:2px}.settings-wrapper .setting-list ul .font-size .resize span[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width .resize span[data-v-65e7f0f4]{width:89px;height:34px;line-height:34px;display:inline-block;cursor:pointer;text-align:center;vertical-align:middle}.settings-wrapper .setting-lisLine truncated
|
||||
@charset "UTF-8";@font-face{font-family:FZZCYSK;src:local("☺"),url(../fonts/popfont.f39ecc1a.ttf);font-style:normal;font-weight:400}.cata-wrapper[data-v-0aacaab8]{margin:-16px;padding:18px 0 24px 25px}.cata-wrapper .title[data-v-0aacaab8]{font-size:18px;font-weight:400;font-family:FZZCYSK;margin:0 0 20px 0;color:#ed4259;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;border-bottom:1px solid #ed4259}.cata-wrapper .data-wrapper[data-v-0aacaab8]{height:300px;overflow:auto}.cata-wrapper .data-wrapper .cata[data-v-0aacaab8]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.cata-wrapper .data-wrapper .cata .selected[data-v-0aacaab8]{color:#eb4259}.cata-wrapper .data-wrapper .cata .log[data-v-0aacaab8]{width:50%;height:40px;cursor:pointer;float:left;font:16px/40px PingFangSC-Regular,HelveticaNeue-Light,Helvetica Neue Light,Microsoft YaHei,sans-serif}.cata-wrapper .data-wrapper .cata .log .log-text[data-v-0aacaab8]{margin-right:26px;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.cata-wrapper .night[data-v-0aacaab8] .log{border-bottom:1px solid #666}.cata-wrapper .day[data-v-0aacaab8] .log{border-bottom:1px solid #f2f2f2}@media screen and (max-width:500px){.cata-wrapper .data-wrapper .cata .log[data-v-0aacaab8]{width:100%}}@font-face{font-family:iconfont;src:url(../fonts/iconfont.f9a3fb0e.woff) format("woff")}[data-v-65e7f0f4] .iconfont,[data-v-65e7f0f4] .moon-icon{font-family:iconfont;font-style:normal}.settings-wrapper[data-v-65e7f0f4]{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:-13px;height:300px;text-align:left;padding:40px 0 40px 24px;background:#ede7da url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyBAMAAADsEZWCAAAAD1BMVEX48dr48Nf58tv379X17NJtIBxUAAACFUlEQVQ4y1XRUZakMAgF0Af2AiDWApDZgHZqAV1nZv9rGh7Rj7Y8McUFEg1wvcMESMNVD/neU8Xcaz7nYYkYlYO6Ti82PBI4BvIEg1aj3wKwRvIMgZsUy5LdhCawPFh1sZs4SrlyN9fQKpv8s5dgZ2eLyqqJiu+WkCmUEybXkm3INS01WAiv0PapJ0CZc0SJQUzcWnZYbOOY20iFD8Bk+/j2A3wNxH7GdShFYS5ff237kXh9I9zSkQmIAhOsOSVfJ6DIXTMDaPnzkRJ92S1BQQmXl5LdirgRLLDdcYqcGPwe3QN4xCBiGNbrqq9wpW1XCecChwaQdVOsRDpPCpeoolPdxeXp3WNB9PHVzWBHlygy4NJCCrFHREv6bDt0VGwJZASkpONmm1UseGeFKAQexgaAkrfYWl3AGxWOLL2AIMBNbCXpktmS3k3vHeYjGCPBa43wJTurO3ZFVpQSJdAZGLoHTyk1upkjxMEaIxum3iIARcCa5kSkFAW5fi1mUlL9eyOsaanFmOMruwvEdE3ZYzsRSzo5ewRLXyVPPEvknt8ij4DvCg2O7xOgBCUprEzV4z1WekSpUgI8DT2mrnSOXKRfQavwuKA1F+tFnMKdJSUpMA7wQAifWRkMgjUKKZE4lBl6MCM4B1pq1P4uIjDE6Pq6rL0FnW1nIFmta5vrSvq/Ch4tpqG/ZNyyWa5jZPktq81eYv8Bt5s4iFITOp4AAAAASUVORK5CYII=) repeat}.settings-wrapper .settings-title[data-v-65e7f0f4]{font-size:18px;line-height:22px;margin-bottom:28px;font-family:FZZCYSK;font-weight:400}.settings-wrapper .setting-list ul[data-v-65e7f0f4]{list-style:none outside none;margin:0;padding:0}.settings-wrapper .setting-list ul li[data-v-65e7f0f4]{list-style:none outside none}.settings-wrapper .setting-list ul li i[data-v-65e7f0f4]{font:12px/16px PingFangSC-Regular,-apple-system,Simsun;display:inline-block;min-width:48px;margin-right:16px;vertical-align:middle;color:#666}.settings-wrapper .setting-list ul li .theme-item[data-v-65e7f0f4]{line-height:32px;width:34px;height:34px;margin-right:16px;margin-top:5px;border-radius:100%;display:inline-block;cursor:pointer;text-align:center;vertical-align:middle}.settings-wrapper .setting-list ul li .theme-item .iconfont[data-v-65e7f0f4]{display:none}.settings-wrapper .setting-list ul li .selected[data-v-65e7f0f4]{color:#ed4259}.settings-wrapper .setting-list ul li .selected .iconfont[data-v-65e7f0f4]{display:inline}.settings-wrapper .setting-list ul .font-list[data-v-65e7f0f4]{margin-top:28px}.settings-wrapper .setting-list ul .font-list .font-item[data-v-65e7f0f4]{width:78px;height:34px;cursor:pointer;margin-right:16px;border-radius:2px;text-align:center;vertical-align:middle;display:inline-block;font:14px/34px PingFangSC-Regular,HelveticaNeue-Light,Helvetica Neue Light,Microsoft YaHei,sans-serif}.settings-wrapper .setting-list ul .font-list .font-item[data-v-65e7f0f4]:hover,.settings-wrapper .setting-list ul .font-list .selected[data-v-65e7f0f4]{color:#ed4259;border:1px solid #ed4259}.settings-wrapper .setting-list ul .font-size[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width[data-v-65e7f0f4]{margin-top:28px}.settings-wrapper .setting-list ul .font-size .resize[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width .resize[data-v-65e7f0f4]{display:inline-block;width:274px;height:34px;vertical-align:middle;border-radius:2px}.settings-wrapper .setting-list ul .font-size .resize span[data-v-65e7f0f4],.settings-wrapper .setting-list ul .read-width .resize span[data-v-65e7f0f4]{width:89px;height:34px;line-height:34px;display:inline-block;cursor:pointer;text-align:center;vertical-align:middle}.settings-wrapper .setting-lisLine truncated
|
||||
@@ -1,3 +1,3 @@
|
||||
<!DOCTYPE html><html lang="en" style="padding: 0;height:100%"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"><link rel="icon" href="../favicon.ico" type="image/x-icon"><link rel="shortcut icon" href="../favicon.ico" type="image/x-icon"><title>Legado Bookshelf</title><link href="css/about.b93f38f9.css" rel="prefetch"><link href="css/detail.7f9a50b2.css" rel="prefetch"><link href="js/about.66694f8c.js" rel="prefetch"><link href="js/detail.08ed5833.js" rel="prefetch"><link href="css/app.e4c919b7.css" rel="preload" as="style"><link href="css/chunk-vendors.bd1373b6.css" rel="preload" as="style"><link href="js/app.9f1876f9.js" rel="preload" as="script"><link href="js/chunk-vendors.7abad833.js" rel="preload" as="script"><link href="css/chunk-vendors.bd1373b6.css" rel="stylesheet"><link href="css/app.e4c919b7.css" rel="stylesheet"></head><style>body::-webkit-scrollbar {
|
||||
<!DOCTYPE html><html lang="en" style="padding: 0;height:100%"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"><link rel="icon" href="../favicon.ico" type="image/x-icon"><link rel="shortcut icon" href="../favicon.ico" type="image/x-icon"><title>Legado Bookshelf</title><link href="css/about.65a00131.css" rel="prefetch"><link href="css/detail.12a39aa7.css" rel="prefetch"><link href="js/about.2456ab2e.js" rel="prefetch"><link href="js/detail.8e2caf8f.js" rel="prefetch"><link href="css/app.e4c919b7.css" rel="preload" as="style"><link href="css/chunk-vendors.bd1373b6.css" rel="preload" as="style"><link href="js/app.a68b7203.js" rel="preload" as="script"><link href="js/chunk-vendors.f36dda93.js" rel="preload" as="script"><link href="css/chunk-vendors.bd1373b6.css" rel="stylesheet"><link href="css/app.e4c919b7.css" rel="stylesheet"></head><style>body::-webkit-scrollbar {
|
||||
display: none;
|
||||
}</style><body style="margin: 0;height:100%"><noscript><strong>We're sorry but yd-web-tool doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.7abad833.js"></script><script src="js/app.9f1876f9.js"></script></body></html>
|
||||
}</style><body style="margin: 0;height:100%"><noscript><strong>We're sorry but yd-web-tool doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="js/chunk-vendors.f36dda93.js"></script><script src="js/app.a68b7203.js"></script></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{"04d1":function(t,e,r){var n=r("342f"),a=n.match(/firefox\/(\d+)/i);t.exports=!!a&&+a[1]},"0cb2":function(t,e,r){var n=r("e330"),a=r("7b0b"),i=Math.floor,o=n("".charAt),s=n("".replace),c=n("".slice),u=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,l=/\$([$&'`]|\d{1,2})/g;t.exports=function(t,e,r,n,d,f){var v=r+t.length,h=n.length,p=l;return void 0!==d&&(d=a(d),p=u),s(f,p,(function(a,s){var u;switch(o(s,0)){case"$":return"$";case"&":return t;case"`":return c(e,0,r);case"'":return c(e,v);case"<":u=d[c(s,1,-1)];break;default:var l=+s;if(0===l)return a;if(l>h){var f=i(l/10);return 0===f?a:f<=h?void 0===n[f-1]?o(s,1):n[f-1]+o(s,1):a}u=n[l-1]}return void 0===u?"":u}))}},"14c3":function(t,e,r){var n=r("da84"),a=r("c65b"),i=r("825a"),o=r("1626"),s=r("c6b6"),c=r("9263"),u=n.TypeError;t.exports=function(t,e){var r=t.exec;if(o(r)){var n=a(r,t,e);return null!==n&&i(n),n}if("RegExp"===s(t))return a(c,t,e);throw u("RegExp#exec called on incompatible receiver")}},"2c3e":function(t,e,r){var n=r("da84"),a=r("83ab"),i=r("9f7f").MISSED_STICKY,o=r("c6b6"),s=r("edd0"),c=r("69f3").get,u=RegExp.prototype,l=n.TypeError;a&&i&&s(u,"sticky",{configurable:!0,get:function(){if(this!==u){if("RegExp"===o(this))return!!c(this).sticky;throw l("Incompatible receiver, RegExp required")}}})},"44e7":function(t,e,r){var n=r("861d"),a=r("c6b6"),i=r("b622"),o=i("match");t.exports=function(t){var e;return n(t)&&(void 0!==(e=t[o])?!!e:"RegExp"==a(t))}},"4d63":function(t,e,r){var n=r("83ab"),a=r("da84"),i=r("e330"),o=r("94ca"),s=r("7156"),c=r("9112"),u=r("241c").f,l=r("3a9b"),d=r("44e7"),f=r("577e"),v=r("90d8"),h=r("9f7f"),p=r("aeb0"),g=r("cb2d"),b=r("d039"),m=r("1a2d"),x=r("69f3").enforce,w=r("2626"),C=r("b622"),A=r("fce3"),y=r("107c"),R=C("match"),I=a.RegExp,E=I.prototype,k=a.SyntaxError,M=i(E.exec),S=i("".charAt),D=i("".replace),T=i("".indexOf),$=i("".slice),B=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,_=/a/g,z=/a/g,F=new I(_)!==_,J=h.MISSED_STICKY,N=h.UNSUPPORTED_Y,O=n&&(!F||J||A||y||b((function(){return z[R]=!1,I(_)!=_||I(z)==z||"/a/i"!=I(_,"i")}))),P=function(t){for(var e,r=t.length,n=0,a="",i=!1;n<=r;n++)e=S(t,n),"\\"!==e?i||"."!==e?("["===e?i=!0:"]"===e&&(i=!1),a+=e):a+="[\\s\\S]":a+=e+S(t,++n);return a},W=function(t){for(var e,r=t.length,n=0,a="",i=[],o={},s=!1,c=!1,u=0,l="";n<=r;n++){if(e=S(t,n),"\\"===e)e+=S(t,++n);else if("]"===e)s=!1;else if(!s)switch(!0){case"["===e:s=!0;break;case"("===e:M(B,$(t,n+1))&&(n+=2,c=!0),a+=e,u++;continue;case">"===e&&c:if(""===l||m(o,l))throw new k("Invalid capture group name");o[l]=!0,i[i.length]=[l,u],c=!1,l="";continue}c?l+=e:a+=e}return[a,i]};if(o("RegExp",O)){for(var H=function(t,e){var r,n,a,i,o,u,h=l(E,this),p=d(t),g=void 0===e,b=[],m=t;if(!h&&p&&g&&t.constructor===H)return t;if((p||l(E,t))&&(t=t.source,g&&(e=v(m))),t=void 0===t?"":f(t),e=void 0===e?"":f(e),m=t,A&&"dotAll"in _&&(n=!!e&&T(e,"s")>-1,n&&(e=D(e,/s/g,""))),r=e,J&&"sticky"in _&&(a=!!e&&T(e,"y")>-1,a&&N&&(e=D(e,/y/g,""))),y&&(i=W(t),t=i[0],b=i[1]),o=s(I(t,e),h?this:E,H),(n||a||b.length)&&(u=x(o),n&&(u.dotAll=!0,u.raw=H(P(t),r)),a&&(u.sticky=!0),b.length&&(u.groups=b)),t!==m)try{c(o,"source",""===m?"(?:)":m)}catch(w){}return o},U=u(I),Y=0;U.length>Y;)p(H,I,U[Y++]);E.constructor=H,H.prototype=E,g(a,"RegExp",H,{constructor:!0})}w("RegExp")},"4dae":function(t,e,r){var n=r("da84"),a=r("23cb"),i=r("07fa"),o=r("8418"),s=n.Array,c=Math.max;t.exports=function(t,e,r){for(var n=i(t),u=a(e,n),l=a(void 0===r?n:r,n),d=s(c(l-u,0)),f=0;u<l;u++,f++)o(d,f,t[u]);return d.length=f,d}},"4e82":function(t,e,r){"use strict";var n=r("23e7"),a=r("e330"),i=r("59ed"),o=r("7b0b"),s=r("07fa"),c=r("577e"),u=r("d039"),l=r("addb"),d=r("a640"),f=r("04d1"),v=r("d998"),h=r("2d00"),p=r("512c"),g=[],b=a(g.sort),m=a(g.push),x=u((function(){g.sort(void 0)})),w=u((function(){g.sort(null)})),C=d("sort"),A=!u((function(){if(h)return h<70;if(!(f&&f>3)){if(v)return!0;if(p)return p<603;var t,e,r,n,a="";for(t=65;t<76;t++){switch(e=String.fromCharCode(t),t){case 66:case 69:case 70:case 72:r=3;break;case 68:case 71:r=4;break;default:r=2}for(n=0;n<47;n++)g.push({k:e+n,v:r})}for(g.sort((function(t,e){return e.v-t.v})),n=0;n<g.length;n++)e=g[n].k.charAt(0),a.charAt(a.length-1)!==e&&(a+=e);return"DGBEFHACIJK"!==a}})),y=x||!w||!C||!A,R=function(t){return function(e,r){return void 0===r?-1:void 0===e?1:void 0!==t?+t(e,r)||0:c(e)>c(r)?1:-1}};n({target:"Array",proto:!0,forced:y},{sort:function(t){void 0!==t&&i(t);var e=o(this);if(A)return void 0===t?b(e):b(e,t);var r,n,a=[],c=s(e);for(n=0;n<c;n++)n in e&&m(a,e[n]);l(a,R(t)),r=a.length,n=0;while(n<r)e[n]=a[n++];while(n<c)delete e[n++];return e}})},"512c":function(t,e,r){var n=r("342f"),a=n.match(/AppleWebKit\/(\d+)\./);t.exports=!!a&&+a[1]},5319:function(t,e,r){"use strict";var n=r("2ba4"),a=r("c65b"),i=r("e330"),o=r("d784"),s=r("d039"),c=r("825a"),u=r("1626"),l=r("5926"),d=r("50c4"),f=r("577e"),v=r("1d80"),h=r("8aa5"),p=r("dc4a"),g=r("0cb2"),b=r("14c3"),m=r("b622"),x=m("replace"),w=Math.max,C=MLine truncated
|
||||
@@ -1 +0,0 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["about"],{"04d1":function(t,e,r){var n=r("342f"),a=n.match(/firefox\/(\d+)/i);t.exports=!!a&&+a[1]},"0cb2":function(t,e,r){var n=r("e330"),a=r("7b0b"),i=Math.floor,o=n("".charAt),s=n("".replace),c=n("".slice),u=/\$([$&'`]|\d{1,2}|<[^>]*>)/g,l=/\$([$&'`]|\d{1,2})/g;t.exports=function(t,e,r,n,d,f){var v=r+t.length,p=n.length,g=l;return void 0!==d&&(d=a(d),g=u),s(f,g,(function(a,s){var u;switch(o(s,0)){case"$":return"$";case"&":return t;case"`":return c(e,0,r);case"'":return c(e,v);case"<":u=d[c(s,1,-1)];break;default:var l=+s;if(0===l)return a;if(l>p){var f=i(l/10);return 0===f?a:f<=p?void 0===n[f-1]?o(s,1):n[f-1]+o(s,1):a}u=n[l-1]}return void 0===u?"":u}))}},"14c3":function(t,e,r){var n=r("da84"),a=r("c65b"),i=r("825a"),o=r("1626"),s=r("c6b6"),c=r("9263"),u=n.TypeError;t.exports=function(t,e){var r=t.exec;if(o(r)){var n=a(r,t,e);return null!==n&&i(n),n}if("RegExp"===s(t))return a(c,t,e);throw u("RegExp#exec called on incompatible receiver")}},"2c3e":function(t,e,r){var n=r("da84"),a=r("83ab"),i=r("9f7f").MISSED_STICKY,o=r("c6b6"),s=r("edd0"),c=r("69f3").get,u=RegExp.prototype,l=n.TypeError;a&&i&&s(u,"sticky",{configurable:!0,get:function(){if(this!==u){if("RegExp"===o(this))return!!c(this).sticky;throw l("Incompatible receiver, RegExp required")}}})},"44e7":function(t,e,r){var n=r("861d"),a=r("c6b6"),i=r("b622"),o=i("match");t.exports=function(t){var e;return n(t)&&(void 0!==(e=t[o])?!!e:"RegExp"==a(t))}},"4d63":function(t,e,r){var n=r("83ab"),a=r("da84"),i=r("e330"),o=r("94ca"),s=r("7156"),c=r("9112"),u=r("241c").f,l=r("3a9b"),d=r("44e7"),f=r("577e"),v=r("90d8"),p=r("9f7f"),g=r("aeb0"),h=r("cb2d"),m=r("d039"),b=r("1a2d"),x=r("69f3").enforce,w=r("2626"),C=r("b622"),y=r("fce3"),A=r("107c"),R=C("match"),I=a.RegExp,E=I.prototype,k=a.SyntaxError,M=i(E.exec),S=i("".charAt),D=i("".replace),T=i("".indexOf),$=i("".slice),B=/^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/,_=/a/g,z=/a/g,F=new I(_)!==_,J=p.MISSED_STICKY,N=p.UNSUPPORTED_Y,O=n&&(!F||J||y||A||m((function(){return z[R]=!1,I(_)!=_||I(z)==z||"/a/i"!=I(_,"i")}))),P=function(t){for(var e,r=t.length,n=0,a="",i=!1;n<=r;n++)e=S(t,n),"\\"!==e?i||"."!==e?("["===e?i=!0:"]"===e&&(i=!1),a+=e):a+="[\\s\\S]":a+=e+S(t,++n);return a},W=function(t){for(var e,r=t.length,n=0,a="",i=[],o={},s=!1,c=!1,u=0,l="";n<=r;n++){if(e=S(t,n),"\\"===e)e+=S(t,++n);else if("]"===e)s=!1;else if(!s)switch(!0){case"["===e:s=!0;break;case"("===e:M(B,$(t,n+1))&&(n+=2,c=!0),a+=e,u++;continue;case">"===e&&c:if(""===l||b(o,l))throw new k("Invalid capture group name");o[l]=!0,i[i.length]=[l,u],c=!1,l="";continue}c?l+=e:a+=e}return[a,i]};if(o("RegExp",O)){for(var H=function(t,e){var r,n,a,i,o,u,p=l(E,this),g=d(t),h=void 0===e,m=[],b=t;if(!p&&g&&h&&t.constructor===H)return t;if((g||l(E,t))&&(t=t.source,h&&(e=v(b))),t=void 0===t?"":f(t),e=void 0===e?"":f(e),b=t,y&&"dotAll"in _&&(n=!!e&&T(e,"s")>-1,n&&(e=D(e,/s/g,""))),r=e,J&&"sticky"in _&&(a=!!e&&T(e,"y")>-1,a&&N&&(e=D(e,/y/g,""))),A&&(i=W(t),t=i[0],m=i[1]),o=s(I(t,e),p?this:E,H),(n||a||m.length)&&(u=x(o),n&&(u.dotAll=!0,u.raw=H(P(t),r)),a&&(u.sticky=!0),m.length&&(u.groups=m)),t!==b)try{c(o,"source",""===b?"(?:)":b)}catch(w){}return o},U=u(I),Y=0;U.length>Y;)g(H,I,U[Y++]);E.constructor=H,H.prototype=E,h(a,"RegExp",H)}w("RegExp")},"4dae":function(t,e,r){var n=r("da84"),a=r("23cb"),i=r("07fa"),o=r("8418"),s=n.Array,c=Math.max;t.exports=function(t,e,r){for(var n=i(t),u=a(e,n),l=a(void 0===r?n:r,n),d=s(c(l-u,0)),f=0;u<l;u++,f++)o(d,f,t[u]);return d.length=f,d}},"4e82":function(t,e,r){"use strict";var n=r("23e7"),a=r("e330"),i=r("59ed"),o=r("7b0b"),s=r("07fa"),c=r("577e"),u=r("d039"),l=r("addb"),d=r("a640"),f=r("04d1"),v=r("d998"),p=r("2d00"),g=r("512c"),h=[],m=a(h.sort),b=a(h.push),x=u((function(){h.sort(void 0)})),w=u((function(){h.sort(null)})),C=d("sort"),y=!u((function(){if(p)return p<70;if(!(f&&f>3)){if(v)return!0;if(g)return g<603;var t,e,r,n,a="";for(t=65;t<76;t++){switch(e=String.fromCharCode(t),t){case 66:case 69:case 70:case 72:r=3;break;case 68:case 71:r=4;break;default:r=2}for(n=0;n<47;n++)h.push({k:e+n,v:r})}for(h.sort((function(t,e){return e.v-t.v})),n=0;n<h.length;n++)e=h[n].k.charAt(0),a.charAt(a.length-1)!==e&&(a+=e);return"DGBEFHACIJK"!==a}})),A=x||!w||!C||!y,R=function(t){return function(e,r){return void 0===r?-1:void 0===e?1:void 0!==t?+t(e,r)||0:c(e)>c(r)?1:-1}};n({target:"Array",proto:!0,forced:A},{sort:function(t){void 0!==t&&i(t);var e=o(this);if(y)return void 0===t?m(e):m(e,t);var r,n,a=[],c=s(e);for(n=0;n<c;n++)n in e&&b(a,e[n]);l(a,R(t)),r=a.length,n=0;while(n<r)e[n]=a[n++];while(n<c)delete e[n++];return e}})},"512c":function(t,e,r){var n=r("342f"),a=n.match(/AppleWebKit\/(\d+)\./);t.exports=!!a&&+a[1]},5319:function(t,e,r){"use strict";var n=r("2ba4"),a=r("c65b"),i=r("e330"),o=r("d784"),s=r("d039"),c=r("825a"),u=r("1626"),l=r("5926"),d=r("50c4"),f=r("577e"),v=r("1d80"),p=r("8aa5"),g=r("dc4a"),h=r("0cb2"),m=r("14c3"),b=r("b622"),x=b("replace"),w=Math.max,C=Math.min,y=i([].coLine truncated
|
||||
+1
-1
@@ -1 +1 @@
|
||||
(function(e){function t(t){for(var r,o,u=t[0],c=t[1],f=t[2],s=0,l=[];s<u.length;s++)o=u[s],Object.prototype.hasOwnProperty.call(a,o)&&a[o]&&l.push(a[o][0]),a[o]=0;for(r in c)Object.prototype.hasOwnProperty.call(c,r)&&(e[r]=c[r]);d&&d(t);while(l.length)l.shift()();return i.push.apply(i,f||[]),n()}function n(){for(var e,t=0;t<i.length;t++){for(var n=i[t],r=!0,o=1;o<n.length;o++){var u=n[o];0!==a[u]&&(r=!1)}r&&(i.splice(t--,1),e=c(c.s=n[0]))}return e}var r={},o={app:0},a={app:0},i=[];function u(e){return c.p+"js/"+({about:"about",detail:"detail"}[e]||e)+"."+{about:"66694f8c",detail:"08ed5833"}[e]+".js"}function c(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,c),n.l=!0,n.exports}c.e=function(e){var t=[],n={about:1,detail:1};o[e]?t.push(o[e]):0!==o[e]&&n[e]&&t.push(o[e]=new Promise((function(t,n){for(var r="css/"+({about:"about",detail:"detail"}[e]||e)+"."+{about:"b93f38f9",detail:"7f9a50b2"}[e]+".css",a=c.p+r,i=document.getElementsByTagName("link"),u=0;u<i.length;u++){var f=i[u],s=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(s===r||s===a))return t()}var l=document.getElementsByTagName("style");for(u=0;u<l.length;u++){f=l[u],s=f.getAttribute("data-href");if(s===r||s===a)return t()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=t,d.onerror=function(t){var r=t&&t.target&&t.target.src||a,i=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");i.code="CSS_CHUNK_LOAD_FAILED",i.request=r,delete o[e],d.parentNode.removeChild(d),n(i)},d.href=a;var p=document.getElementsByTagName("head")[0];p.appendChild(d)})).then((function(){o[e]=0})));var r=a[e];if(0!==r)if(r)t.push(r[2]);else{var i=new Promise((function(t,n){r=a[e]=[t,n]}));t.push(r[2]=i);var f,s=document.createElement("script");s.charset="utf-8",s.timeout=120,c.nc&&s.setAttribute("nonce",c.nc),s.src=u(e);var l=new Error;f=function(t){s.onerror=s.onload=null,clearTimeout(d);var n=a[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+r+": "+o+")",l.name="ChunkLoadError",l.type=r,l.request=o,n[1](l)}a[e]=void 0}};var d=setTimeout((function(){f({type:"timeout",target:s})}),12e4);s.onerror=s.onload=f,document.head.appendChild(s)}return Promise.all(t)},c.m=e,c.c=r,c.d=function(e,t,n){c.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},c.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.t=function(e,t){if(1&t&&(e=c(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(c.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)c.d(n,r,function(t){return e[t]}.bind(null,r));return n},c.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return c.d(t,"a",t),t},c.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},c.p="",c.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],s=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var d=s;i.push([0,"chunk-vendors"]),n()})({0:function(e,t,n){e.exports=n("56d7")},"034f":function(e,t,n){"use strict";n("85ec")},3562:function(e,t,n){e.exports=n.p+"img/loading.550df755.gif"},"56d7":function(e,t,n){"use strict";n.r(t);n("e260"),n("e6cf"),n("cca6"),n("a79d");var r=n("2b0e"),o=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{attrs:{id:"app"}},[n("router-view")],1)},a=[],i={name:"app",components:{},beforeCreate:function(){var e=this;this.$store.commit("setMiniInterface",window.innerWidth<750),window.onresize=function(){e.$store.commit("setMiniInterface",window.innerWidth<750)}}},u=i,c=(n("034f"),n("2877")),f=Object(c["a"])(u,o,a,!1,null,null,null),s=f.exports,l=(n("d3b7"),n("3ca3"),n("ddb0"),n("8c4f"));r["default"].use(l["a"]);var d=l["a"].prototype.push;l["a"].prototype.push=function(e){return d.call(this,e).catch((function(e){return e}))};var p=[{path:"/",name:"index",component:function(){return n.e("about").then(n.bind(null,"d504"))}},{path:"/chapter",name:"Chapter",component:function(){return n.e("detail").then(n.bind(null,"537b"))}}],h=new l["a"]({base:"",routes:p}),g=h,b=(n("0fb7"),n("450d"),n("f529")),m=n.n(b),v=(n("9e1f"),n("6ed5")),y=n.n(v),w=(n("be4f"),n("896a")),C=n.n(w),S=(n("cbb5"),n("8bbc")),O=n.n(S),j=(n("10cb"),n("f3ad")),k=n.n(j),x=(n("06f1"),n("6ac9")),P=n.n(x),T=(n("5466"),n("ecdf")),_=n.n(T),E=(n("38a0"),n("ad41")),L=n.n(E),$=(n("b84d"),n("c216")),A=n.n($),I=(n("8f24"),n("76b9")),M=n.n(I),B=(n("e3ea"),n("7bc3")),N=n.n(B),R=(n("1951"),n("eedf")),V=n.n(R);r["default"].use(V.a),r["default"].use(N.a),r["default"].use(M.a),r["default"].use(A.a),r["default"].use(L.a),r["default"].use(_.a),r["default"].use(P.a),r["default"].use(k.a),r["default"].use(O.a),r["defaultLine truncated
|
||||
(function(e){function t(t){for(var r,o,u=t[0],c=t[1],f=t[2],s=0,l=[];s<u.length;s++)o=u[s],Object.prototype.hasOwnProperty.call(a,o)&&a[o]&&l.push(a[o][0]),a[o]=0;for(r in c)Object.prototype.hasOwnProperty.call(c,r)&&(e[r]=c[r]);d&&d(t);while(l.length)l.shift()();return i.push.apply(i,f||[]),n()}function n(){for(var e,t=0;t<i.length;t++){for(var n=i[t],r=!0,o=1;o<n.length;o++){var u=n[o];0!==a[u]&&(r=!1)}r&&(i.splice(t--,1),e=c(c.s=n[0]))}return e}var r={},o={app:0},a={app:0},i=[];function u(e){return c.p+"js/"+({about:"about",detail:"detail"}[e]||e)+"."+{about:"2456ab2e",detail:"8e2caf8f"}[e]+".js"}function c(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,c),n.l=!0,n.exports}c.e=function(e){var t=[],n={about:1,detail:1};o[e]?t.push(o[e]):0!==o[e]&&n[e]&&t.push(o[e]=new Promise((function(t,n){for(var r="css/"+({about:"about",detail:"detail"}[e]||e)+"."+{about:"65a00131",detail:"12a39aa7"}[e]+".css",a=c.p+r,i=document.getElementsByTagName("link"),u=0;u<i.length;u++){var f=i[u],s=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(s===r||s===a))return t()}var l=document.getElementsByTagName("style");for(u=0;u<l.length;u++){f=l[u],s=f.getAttribute("data-href");if(s===r||s===a)return t()}var d=document.createElement("link");d.rel="stylesheet",d.type="text/css",d.onload=t,d.onerror=function(t){var r=t&&t.target&&t.target.src||a,i=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");i.code="CSS_CHUNK_LOAD_FAILED",i.request=r,delete o[e],d.parentNode.removeChild(d),n(i)},d.href=a;var p=document.getElementsByTagName("head")[0];p.appendChild(d)})).then((function(){o[e]=0})));var r=a[e];if(0!==r)if(r)t.push(r[2]);else{var i=new Promise((function(t,n){r=a[e]=[t,n]}));t.push(r[2]=i);var f,s=document.createElement("script");s.charset="utf-8",s.timeout=120,c.nc&&s.setAttribute("nonce",c.nc),s.src=u(e);var l=new Error;f=function(t){s.onerror=s.onload=null,clearTimeout(d);var n=a[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),o=t&&t.target&&t.target.src;l.message="Loading chunk "+e+" failed.\n("+r+": "+o+")",l.name="ChunkLoadError",l.type=r,l.request=o,n[1](l)}a[e]=void 0}};var d=setTimeout((function(){f({type:"timeout",target:s})}),12e4);s.onerror=s.onload=f,document.head.appendChild(s)}return Promise.all(t)},c.m=e,c.c=r,c.d=function(e,t,n){c.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},c.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.t=function(e,t){if(1&t&&(e=c(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(c.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)c.d(n,r,function(t){return e[t]}.bind(null,r));return n},c.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return c.d(t,"a",t),t},c.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},c.p="",c.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],s=f.push.bind(f);f.push=t,f=f.slice();for(var l=0;l<f.length;l++)t(f[l]);var d=s;i.push([0,"chunk-vendors"]),n()})({0:function(e,t,n){e.exports=n("56d7")},"034f":function(e,t,n){"use strict";n("85ec")},3562:function(e,t,n){e.exports=n.p+"img/loading.550df755.gif"},"56d7":function(e,t,n){"use strict";n.r(t);n("e260"),n("e6cf"),n("cca6"),n("a79d");var r=n("2b0e"),o=function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",{attrs:{id:"app"}},[n("router-view")],1)},a=[],i={name:"app",components:{},beforeCreate:function(){var e=this;this.$store.commit("setMiniInterface",window.innerWidth<750),window.onresize=function(){e.$store.commit("setMiniInterface",window.innerWidth<750)}}},u=i,c=(n("034f"),n("2877")),f=Object(c["a"])(u,o,a,!1,null,null,null),s=f.exports,l=(n("d3b7"),n("3ca3"),n("ddb0"),n("8c4f"));r["default"].use(l["a"]);var d=l["a"].prototype.push;l["a"].prototype.push=function(e){return d.call(this,e).catch((function(e){return e}))};var p=[{path:"/",name:"index",component:function(){return n.e("about").then(n.bind(null,"d504"))}},{path:"/chapter",name:"Chapter",component:function(){return n.e("detail").then(n.bind(null,"537b"))}}],h=new l["a"]({base:"",routes:p}),g=h,b=(n("0fb7"),n("450d"),n("f529")),m=n.n(b),v=(n("9e1f"),n("6ed5")),y=n.n(v),w=(n("be4f"),n("896a")),C=n.n(w),S=(n("cbb5"),n("8bbc")),O=n.n(S),j=(n("10cb"),n("f3ad")),k=n.n(j),x=(n("06f1"),n("6ac9")),P=n.n(x),T=(n("5466"),n("ecdf")),_=n.n(T),E=(n("38a0"),n("ad41")),L=n.n(E),$=(n("b84d"),n("c216")),A=n.n($),I=(n("8f24"),n("76b9")),M=n.n(I),B=(n("e3ea"),n("7bc3")),N=n.n(B),R=(n("1951"),n("eedf")),V=n.n(R);r["default"].use(V.a),r["default"].use(N.a),r["default"].use(M.a),r["default"].use(A.a),r["default"].use(L.a),r["default"].use(_.a),r["default"].use(P.a),r["default"].use(k.a),r["default"].use(O.a),r["defaultLine truncated
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-vendors"],{"00b4":function(e,t,n){"use strict";n("ac1f");var r=n("23e7"),o=n("da84"),i=n("c65b"),a=n("e330"),s=n("1626"),l=n("861d"),u=function(){var e=!1,t=/[ac]/;return t.exec=function(){return e=!0,/./.exec.apply(this,arguments)},!0===t.test("abc")&&e}(),c=o.Error,f=a(/./.test);r({target:"RegExp",proto:!0,forced:!u},{test:function(e){var t=this.exec;if(!s(t))return f(this,e);var n=i(t,this,e);if(null!==n&&!l(n))throw new c("RegExp exec method returned something other than an Object or null");return!!n}})},"00ee":function(e,t,n){var r=n("b622"),o=r("toStringTag"),i={};i[o]="z",e.exports="[object z]"===String(i)},"01b4":function(e,t){var n=function(){this.head=null,this.tail=null};n.prototype={add:function(e){var t={item:e,next:null};this.head?this.tail.next=t:this.head=t,this.tail=t},get:function(){var e=this.head;if(e)return this.head=e.next,this.tail===e&&(this.tail=null),e.item}},e.exports=n},"0366":function(e,t,n){var r=n("e330"),o=n("59ed"),i=n("40d5"),a=r(r.bind);e.exports=function(e,t){return o(e),void 0===t?e:i?a(e,t):function(){return e.apply(t,arguments)}}},"06cf":function(e,t,n){var r=n("83ab"),o=n("c65b"),i=n("d1e7"),a=n("5c6c"),s=n("fc6a"),l=n("a04b"),u=n("1a2d"),c=n("0cfb"),f=Object.getOwnPropertyDescriptor;t.f=r?f:function(e,t){if(e=s(e),t=l(t),c)try{return f(e,t)}catch(n){}if(u(e,t))return a(!o(i.f,e,t),e[t])}},"06f1":function(e,t,n){},"07fa":function(e,t,n){var r=n("50c4");e.exports=function(e){return r(e.length)}},"0a06":function(e,t,n){"use strict";var r=n("c532"),o=n("30b5"),i=n("f6b4"),a=n("5270"),s=n("4a7b"),l=n("848b"),u=l.validators;function c(e){this.defaults=e,this.interceptors={request:new i,response:new i}}c.prototype.request=function(e){"string"===typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=s(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=e.transitional;void 0!==t&&l.assertOptions(t,{silentJSONParsing:u.transitional(u.boolean,"1.0.0"),forcedJSONParsing:u.transitional(u.boolean,"1.0.0"),clarifyTimeoutError:u.transitional(u.boolean,"1.0.0")},!1);var n=[],r=!0;this.interceptors.request.forEach((function(t){"function"===typeof t.runWhen&&!1===t.runWhen(e)||(r=r&&t.synchronous,n.unshift(t.fulfilled,t.rejected))}));var o,i=[];if(this.interceptors.response.forEach((function(e){i.push(e.fulfilled,e.rejected)})),!r){var c=[a,void 0];Array.prototype.unshift.apply(c,n),c=c.concat(i),o=Promise.resolve(e);while(c.length)o=o.then(c.shift(),c.shift());return o}var f=e;while(n.length){var d=n.shift(),p=n.shift();try{f=d(f)}catch(h){p(h);break}}try{o=a(f)}catch(h){return Promise.reject(h)}while(i.length)o=o.then(i.shift(),i.shift());return o},c.prototype.getUri=function(e){return e=s(this.defaults,e),o(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},r.forEach(["delete","get","head","options"],(function(e){c.prototype[e]=function(t,n){return this.request(s(n||{},{method:e,url:t,data:(n||{}).data}))}})),r.forEach(["post","put","patch"],(function(e){c.prototype[e]=function(t,n,r){return this.request(s(r||{},{method:e,url:t,data:n}))}})),e.exports=c},"0b42":function(e,t,n){var r=n("da84"),o=n("e8b5"),i=n("68ee"),a=n("861d"),s=n("b622"),l=s("species"),u=r.Array;e.exports=function(e){var t;return o(e)&&(t=e.constructor,i(t)&&(t===u||o(t.prototype))?t=void 0:a(t)&&(t=t[l],null===t&&(t=void 0))),void 0===t?u:t}},"0cfb":function(e,t,n){var r=n("83ab"),o=n("d039"),i=n("cc12");e.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},"0d51":function(e,t,n){var r=n("da84"),o=r.String;e.exports=function(e){try{return o(e)}catch(t){return"Object"}}},"0df6":function(e,t,n){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},"0e15":function(e,t,n){var r=n("597f");e.exports=function(e,t,n){return void 0===n?r(e,t,!1):r(e,n,!1!==t)}},"0fb7":function(e,t,n){},"107c":function(e,t,n){var r=n("d039"),o=n("da84"),i=o.RegExp;e.exports=r((function(){var e=i("(?<a>b)","g");return"b"!==e.exec("b").groups.a||"bc"!=="b".replace(e,"$<a>c")}))},"10cb":function(e,t,n){},"13d2":function(e,t,n){var r=n("d039"),o=n("1626"),i=n("1a2d"),a=n("9bf2").f,s=n("5e77").CONFIGURABLE,l=n("8925"),u=n("69f3"),c=u.enforce,f=u.get,d=!r((function(){return 8!==a((function(){}),"length",{value:8}).length})),p=String(String).split("String"),h=e.exports=function(e,t,n){"Symbol("===String(t).slice(0,7)&&(t="["+String(t).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),n&&n.getter&&(t="get "+t),n&&n.setter&&(t="set "+t),(!i(e,"name")||s&&e.name!==t)&&a(e,"name",{value:t,configurable:!0}),d&&n&&i(n,"arity")&&e.length!==n.arity&&a(e,"length",{value:n.arity});var r=c(e);return i(r,"source")||(r.source=p.join("string"==typeof t?t:"")),e};Function.prototype.toString=h((function(){return o(this)&&f(this).source||l(this)}),"toString")},"14e5":function(e,t,n){"use strict";var r=n("23e7"),o=n("c65b"),i=n("59eLine truncated
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-vendors"],{"00b4":function(e,t,n){"use strict";n("ac1f");var r=n("23e7"),o=n("da84"),i=n("c65b"),a=n("e330"),s=n("1626"),l=n("861d"),u=function(){var e=!1,t=/[ac]/;return t.exec=function(){return e=!0,/./.exec.apply(this,arguments)},!0===t.test("abc")&&e}(),c=o.Error,f=a(/./.test);r({target:"RegExp",proto:!0,forced:!u},{test:function(e){var t=this.exec;if(!s(t))return f(this,e);var n=i(t,this,e);if(null!==n&&!l(n))throw new c("RegExp exec method returned something other than an Object or null");return!!n}})},"00ee":function(e,t,n){var r=n("b622"),o=r("toStringTag"),i={};i[o]="z",e.exports="[object z]"===String(i)},"01b4":function(e,t){var n=function(){this.head=null,this.tail=null};n.prototype={add:function(e){var t={item:e,next:null};this.head?this.tail.next=t:this.head=t,this.tail=t},get:function(){var e=this.head;if(e)return this.head=e.next,this.tail===e&&(this.tail=null),e.item}},e.exports=n},"0366":function(e,t,n){var r=n("e330"),o=n("59ed"),i=n("40d5"),a=r(r.bind);e.exports=function(e,t){return o(e),void 0===t?e:i?a(e,t):function(){return e.apply(t,arguments)}}},"06cf":function(e,t,n){var r=n("83ab"),o=n("c65b"),i=n("d1e7"),a=n("5c6c"),s=n("fc6a"),l=n("a04b"),u=n("1a2d"),c=n("0cfb"),f=Object.getOwnPropertyDescriptor;t.f=r?f:function(e,t){if(e=s(e),t=l(t),c)try{return f(e,t)}catch(n){}if(u(e,t))return a(!o(i.f,e,t),e[t])}},"06f1":function(e,t,n){},"07fa":function(e,t,n){var r=n("50c4");e.exports=function(e){return r(e.length)}},"0a06":function(e,t,n){"use strict";var r=n("c532"),o=n("30b5"),i=n("f6b4"),a=n("5270"),s=n("4a7b"),l=n("848b"),u=l.validators;function c(e){this.defaults=e,this.interceptors={request:new i,response:new i}}c.prototype.request=function(e){"string"===typeof e?(e=arguments[1]||{},e.url=arguments[0]):e=e||{},e=s(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var t=e.transitional;void 0!==t&&l.assertOptions(t,{silentJSONParsing:u.transitional(u.boolean,"1.0.0"),forcedJSONParsing:u.transitional(u.boolean,"1.0.0"),clarifyTimeoutError:u.transitional(u.boolean,"1.0.0")},!1);var n=[],r=!0;this.interceptors.request.forEach((function(t){"function"===typeof t.runWhen&&!1===t.runWhen(e)||(r=r&&t.synchronous,n.unshift(t.fulfilled,t.rejected))}));var o,i=[];if(this.interceptors.response.forEach((function(e){i.push(e.fulfilled,e.rejected)})),!r){var c=[a,void 0];Array.prototype.unshift.apply(c,n),c=c.concat(i),o=Promise.resolve(e);while(c.length)o=o.then(c.shift(),c.shift());return o}var f=e;while(n.length){var d=n.shift(),p=n.shift();try{f=d(f)}catch(h){p(h);break}}try{o=a(f)}catch(h){return Promise.reject(h)}while(i.length)o=o.then(i.shift(),i.shift());return o},c.prototype.getUri=function(e){return e=s(this.defaults,e),o(e.url,e.params,e.paramsSerializer).replace(/^\?/,"")},r.forEach(["delete","get","head","options"],(function(e){c.prototype[e]=function(t,n){return this.request(s(n||{},{method:e,url:t,data:(n||{}).data}))}})),r.forEach(["post","put","patch"],(function(e){c.prototype[e]=function(t,n,r){return this.request(s(r||{},{method:e,url:t,data:n}))}})),e.exports=c},"0b42":function(e,t,n){var r=n("da84"),o=n("e8b5"),i=n("68ee"),a=n("861d"),s=n("b622"),l=s("species"),u=r.Array;e.exports=function(e){var t;return o(e)&&(t=e.constructor,i(t)&&(t===u||o(t.prototype))?t=void 0:a(t)&&(t=t[l],null===t&&(t=void 0))),void 0===t?u:t}},"0cfb":function(e,t,n){var r=n("83ab"),o=n("d039"),i=n("cc12");e.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},"0d51":function(e,t,n){var r=n("da84"),o=r.String;e.exports=function(e){try{return o(e)}catch(t){return"Object"}}},"0df6":function(e,t,n){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},"0e15":function(e,t,n){var r=n("597f");e.exports=function(e,t,n){return void 0===n?r(e,t,!1):r(e,n,!1!==t)}},"0fb7":function(e,t,n){},"107c":function(e,t,n){var r=n("d039"),o=n("da84"),i=o.RegExp;e.exports=r((function(){var e=i("(?<a>b)","g");return"b"!==e.exec("b").groups.a||"bc"!=="b".replace(e,"$<a>c")}))},"10cb":function(e,t,n){},"13d2":function(e,t,n){var r=n("d039"),o=n("1626"),i=n("1a2d"),a=n("83ab"),s=n("5e77").CONFIGURABLE,l=n("8925"),u=n("69f3"),c=u.enforce,f=u.get,d=Object.defineProperty,p=a&&!r((function(){return 8!==d((function(){}),"length",{value:8}).length})),h=String(String).split("String"),v=e.exports=function(e,t,n){if("Symbol("===String(t).slice(0,7)&&(t="["+String(t).replace(/^Symbol\(([^)]*)\)/,"$1")+"]"),n&&n.getter&&(t="get "+t),n&&n.setter&&(t="set "+t),(!i(e,"name")||s&&e.name!==t)&&d(e,"name",{value:t,configurable:!0}),p&&n&&i(n,"arity")&&e.length!==n.arity&&d(e,"length",{value:n.arity}),n&&i(n,"constructor")&&n.constructor){if(a)try{d(e,"prototype",{writable:!1})}catch(o){}}else e.prototype=void 0;var r=c(e);return i(r,"source")||(r.source=h.join("string"==typeof t?t:"")),e};Function.prototype.toString=Line truncated
|
||||
/*!
|
||||
* Vue.js v2.6.14
|
||||
* (c) 2014-2021 Evan You
|
||||
@@ -10,7 +10,7 @@ var n=Object.freeze({});function r(e){return void 0===e||null===e}function o(e){
|
||||
* (c) 2021 Evan You
|
||||
* @license MIT
|
||||
*/
|
||||
function n(e){var t=Number(e.version.split(".")[0]);if(t>=2)e.mixin({beforeCreate:r});else{var n=e.prototype._init;e.prototype._init=function(e){void 0===e&&(e={}),e.init=e.init?[r].concat(e.init):r,n.call(this,e)}}function r(){var e=this.$options;e.store?this.$store="function"===typeof e.store?e.store():e.store:e.parent&&e.parent.$store&&(this.$store=e.parent.$store)}}var r="undefined"!==typeof window?window:"undefined"!==typeof e?e:{},o=r.__VUE_DEVTOOLS_GLOBAL_HOOK__;function i(e){o&&(e._devtoolHook=o,o.emit("vuex:init",e),o.on("vuex:travel-to-state",(function(t){e.replaceState(t)})),e.subscribe((function(e,t){o.emit("vuex:mutation",e,t)}),{prepend:!0}),e.subscribeAction((function(e,t){o.emit("vuex:action",e,t)}),{prepend:!0}))}function a(e,t){return e.filter(t)[0]}function s(e,t){if(void 0===t&&(t=[]),null===e||"object"!==typeof e)return e;var n=a(t,(function(t){return t.original===e}));if(n)return n.copy;var r=Array.isArray(e)?[]:{};return t.push({original:e,copy:r}),Object.keys(e).forEach((function(n){r[n]=s(e[n],t)})),r}function l(e,t){Object.keys(e).forEach((function(n){return t(e[n],n)}))}function u(e){return null!==e&&"object"===typeof e}function c(e){return e&&"function"===typeof e.then}function f(e,t){return function(){return e(t)}}var d=function(e,t){this.runtime=t,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=("function"===typeof n?n():n)||{}},p={namespaced:{configurable:!0}};p.namespaced.get=function(){return!!this._rawModule.namespaced},d.prototype.addChild=function(e,t){this._children[e]=t},d.prototype.removeChild=function(e){delete this._children[e]},d.prototype.getChild=function(e){return this._children[e]},d.prototype.hasChild=function(e){return e in this._children},d.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)},d.prototype.forEachChild=function(e){l(this._children,e)},d.prototype.forEachGetter=function(e){this._rawModule.getters&&l(this._rawModule.getters,e)},d.prototype.forEachAction=function(e){this._rawModule.actions&&l(this._rawModule.actions,e)},d.prototype.forEachMutation=function(e){this._rawModule.mutations&&l(this._rawModule.mutations,e)},Object.defineProperties(d.prototype,p);var h=function(e){this.register([],e,!1)};function v(e,t,n){if(t.update(n),n.modules)for(var r in n.modules){if(!t.getChild(r))return void 0;v(e.concat(r),t.getChild(r),n.modules[r])}}h.prototype.get=function(e){return e.reduce((function(e,t){return e.getChild(t)}),this.root)},h.prototype.getNamespace=function(e){var t=this.root;return e.reduce((function(e,n){return t=t.getChild(n),e+(t.namespaced?n+"/":"")}),"")},h.prototype.update=function(e){v([],this.root,e)},h.prototype.register=function(e,t,n){var r=this;void 0===n&&(n=!0);var o=new d(t,n);if(0===e.length)this.root=o;else{var i=this.get(e.slice(0,-1));i.addChild(e[e.length-1],o)}t.modules&&l(t.modules,(function(t,o){r.register(e.concat(o),t,n)}))},h.prototype.unregister=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1],r=t.getChild(n);r&&r.runtime&&t.removeChild(n)},h.prototype.isRegistered=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1];return!!t&&t.hasChild(n)};var m;var y=function(e){var t=this;void 0===e&&(e={}),!m&&"undefined"!==typeof window&&window.Vue&&T(window.Vue);var n=e.plugins;void 0===n&&(n=[]);var r=e.strict;void 0===r&&(r=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new h(e),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new m,this._makeLocalGettersCache=Object.create(null);var o=this,a=this,s=a.dispatch,l=a.commit;this.dispatch=function(e,t){return s.call(o,e,t)},this.commit=function(e,t,n){return l.call(o,e,t,n)},this.strict=r;var u=this._modules.root.state;w(this,u,[],this._modules.root),x(this,u),n.forEach((function(e){return e(t)}));var c=void 0!==e.devtools?e.devtools:m.config.devtools;c&&i(this)},g={state:{configurable:!0}};function b(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function _(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;w(e,n,[],e._modules.root,!0),x(e,n,t)}function x(e,t,n){var r=e._vm;e.getters={},e._makeLocalGettersCache=Object.create(null);var o=e._wrappedGetters,i={};l(o,(function(t,n){i[n]=f(t,e),Object.defineProperty(e.getters,n,{get:function(){return e._vm[n]},enumerable:!0})}));var a=m.config.silent;m.config.silent=!0,e._vm=new m({data:{$$state:t},computed:i}),m.config.silent=a,e.strict&&j(e),r&&(n&&e._withCommit((function(){r._data.$$state=null})),m.nextTick((function(){return r.$destroy()})))}function w(e,t,n,r,o){var i=!n.length,aLine truncated
|
||||
function n(e){var t=Number(e.version.split(".")[0]);if(t>=2)e.mixin({beforeCreate:r});else{var n=e.prototype._init;e.prototype._init=function(e){void 0===e&&(e={}),e.init=e.init?[r].concat(e.init):r,n.call(this,e)}}function r(){var e=this.$options;e.store?this.$store="function"===typeof e.store?e.store():e.store:e.parent&&e.parent.$store&&(this.$store=e.parent.$store)}}var r="undefined"!==typeof window?window:"undefined"!==typeof e?e:{},o=r.__VUE_DEVTOOLS_GLOBAL_HOOK__;function i(e){o&&(e._devtoolHook=o,o.emit("vuex:init",e),o.on("vuex:travel-to-state",(function(t){e.replaceState(t)})),e.subscribe((function(e,t){o.emit("vuex:mutation",e,t)}),{prepend:!0}),e.subscribeAction((function(e,t){o.emit("vuex:action",e,t)}),{prepend:!0}))}function a(e,t){return e.filter(t)[0]}function s(e,t){if(void 0===t&&(t=[]),null===e||"object"!==typeof e)return e;var n=a(t,(function(t){return t.original===e}));if(n)return n.copy;var r=Array.isArray(e)?[]:{};return t.push({original:e,copy:r}),Object.keys(e).forEach((function(n){r[n]=s(e[n],t)})),r}function l(e,t){Object.keys(e).forEach((function(n){return t(e[n],n)}))}function u(e){return null!==e&&"object"===typeof e}function c(e){return e&&"function"===typeof e.then}function f(e,t){return function(){return e(t)}}var d=function(e,t){this.runtime=t,this._children=Object.create(null),this._rawModule=e;var n=e.state;this.state=("function"===typeof n?n():n)||{}},p={namespaced:{configurable:!0}};p.namespaced.get=function(){return!!this._rawModule.namespaced},d.prototype.addChild=function(e,t){this._children[e]=t},d.prototype.removeChild=function(e){delete this._children[e]},d.prototype.getChild=function(e){return this._children[e]},d.prototype.hasChild=function(e){return e in this._children},d.prototype.update=function(e){this._rawModule.namespaced=e.namespaced,e.actions&&(this._rawModule.actions=e.actions),e.mutations&&(this._rawModule.mutations=e.mutations),e.getters&&(this._rawModule.getters=e.getters)},d.prototype.forEachChild=function(e){l(this._children,e)},d.prototype.forEachGetter=function(e){this._rawModule.getters&&l(this._rawModule.getters,e)},d.prototype.forEachAction=function(e){this._rawModule.actions&&l(this._rawModule.actions,e)},d.prototype.forEachMutation=function(e){this._rawModule.mutations&&l(this._rawModule.mutations,e)},Object.defineProperties(d.prototype,p);var h=function(e){this.register([],e,!1)};function v(e,t,n){if(t.update(n),n.modules)for(var r in n.modules){if(!t.getChild(r))return void 0;v(e.concat(r),t.getChild(r),n.modules[r])}}h.prototype.get=function(e){return e.reduce((function(e,t){return e.getChild(t)}),this.root)},h.prototype.getNamespace=function(e){var t=this.root;return e.reduce((function(e,n){return t=t.getChild(n),e+(t.namespaced?n+"/":"")}),"")},h.prototype.update=function(e){v([],this.root,e)},h.prototype.register=function(e,t,n){var r=this;void 0===n&&(n=!0);var o=new d(t,n);if(0===e.length)this.root=o;else{var i=this.get(e.slice(0,-1));i.addChild(e[e.length-1],o)}t.modules&&l(t.modules,(function(t,o){r.register(e.concat(o),t,n)}))},h.prototype.unregister=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1],r=t.getChild(n);r&&r.runtime&&t.removeChild(n)},h.prototype.isRegistered=function(e){var t=this.get(e.slice(0,-1)),n=e[e.length-1];return!!t&&t.hasChild(n)};var m;var y=function(e){var t=this;void 0===e&&(e={}),!m&&"undefined"!==typeof window&&window.Vue&&T(window.Vue);var n=e.plugins;void 0===n&&(n=[]);var r=e.strict;void 0===r&&(r=!1),this._committing=!1,this._actions=Object.create(null),this._actionSubscribers=[],this._mutations=Object.create(null),this._wrappedGetters=Object.create(null),this._modules=new h(e),this._modulesNamespaceMap=Object.create(null),this._subscribers=[],this._watcherVM=new m,this._makeLocalGettersCache=Object.create(null);var o=this,a=this,s=a.dispatch,l=a.commit;this.dispatch=function(e,t){return s.call(o,e,t)},this.commit=function(e,t,n){return l.call(o,e,t,n)},this.strict=r;var u=this._modules.root.state;w(this,u,[],this._modules.root),x(this,u),n.forEach((function(e){return e(t)}));var c=void 0!==e.devtools?e.devtools:m.config.devtools;c&&i(this)},g={state:{configurable:!0}};function b(e,t,n){return t.indexOf(e)<0&&(n&&n.prepend?t.unshift(e):t.push(e)),function(){var n=t.indexOf(e);n>-1&&t.splice(n,1)}}function _(e,t){e._actions=Object.create(null),e._mutations=Object.create(null),e._wrappedGetters=Object.create(null),e._modulesNamespaceMap=Object.create(null);var n=e.state;w(e,n,[],e._modules.root,!0),x(e,n,t)}function x(e,t,n){var r=e._vm;e.getters={},e._makeLocalGettersCache=Object.create(null);var o=e._wrappedGetters,i={};l(o,(function(t,n){i[n]=f(t,e),Object.defineProperty(e.getters,n,{get:function(){return e._vm[n]},enumerable:!0})}));var a=m.config.silent;m.config.silent=!0,e._vm=new m({data:{$$state:t},computed:i}),m.config.silent=a,e.strict&&j(e),r&&(n&&e._withCommit((function(){r._data.$$state=null})),m.nextTick((function(){return r.$destroy()})))}function w(e,t,n,r,o){var i=!n.length,aLine truncated
|
||||
/**
|
||||
* Checks if an event is supported in the current execution environment.
|
||||
*
|
||||
@@ -1 +0,0 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["detail"],{"004c":function(t,e,n){"use strict";n("fe9c")},"057f":function(t,e,n){var o=n("c6b6"),i=n("fc6a"),r=n("241c").f,s=n("4dae"),a="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],c=function(t){try{return r(t)}catch(e){return s(a)}};t.exports.f=function(t){return a&&"Window"==o(t)?c(t):r(i(t))}},"05b3":function(t,e,n){},"0827":function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEUWGBkYGhsdHyAfISI1t/v6AAAB5ElEQVQozxXQsYoTURSA4f/EeycZsDgDdySDjihk38Hy3GWi2J2BCaziQhaiaB+tt9AFu1kwvYUPsIXNPoB9BAUfwAfwEUzKv/v4odGrroyp9/rUaC6rZ5skv5F8qPsfYYP+yKUMymmAEEeW55oUR4o8jr05KNzJ07yvB7w0KKfLwcQUSjfmMU0PJfPHFoEVU+ohNrcKMEzMQ23FDnVSI2dqtYWI7KlLu6vE4UnyvKc3SJuL7lBbeEEl42ItpGLjzIT8PRJCmkRjVpVpsbJFVN0687okJNZiHAr5Z7MV0BnGIDc+THM1zlbieBc1Fq+tH5BH+OpnbWkj40hSqC8Lw2TvFuF0SUFJCk2IytXbjeqcRAt6NHpnrUkUU4KRzZs8RCK8N/Akn2W04LwxMU/V7XK0bDyN2RxfDyx7I4h5vjZby72V8UnOWumZL3qtYc+8DTE0siSBMXGhywx2dMYPnQHbxdFZ7deiNGxCCtD/QWnbwDoGhRYPDzUdUA3krjpnkvdAgDN4ddLkEQSov9qjd42HaDjI34gEqS9TUueAk+sc4qg5ws407KQYKs8G1jv4xBlqBVk6cb4dISZIwVi1Jzu4+HLk6lyfUxkXvwy+1Q+4WVdHIhwfybZ6CWVhxMEhShOgsP/HOW0MvZJeFwAAAABJRU5ErkJggg=="},"0928":function(t,e,n){"use strict";n("7715")},1276:function(t,e,n){"use strict";var o=n("2ba4"),i=n("c65b"),r=n("e330"),s=n("d784"),a=n("44e7"),c=n("825a"),l=n("1d80"),u=n("4840"),f=n("8aa5"),d=n("50c4"),h=n("577e"),p=n("dc4a"),g=n("4dae"),A=n("14c3"),m=n("9263"),v=n("9f7f"),b=n("d039"),y=v.UNSUPPORTED_Y,C=4294967295,S=Math.min,x=[].push,B=r(/./.exec),w=r(x),k=r("".slice),I=!b((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));s("split",(function(t,e,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var r=h(l(this)),s=void 0===n?C:n>>>0;if(0===s)return[];if(void 0===t)return[r];if(!a(t))return i(e,r,t,s);var c,u,f,d=[],p=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),A=0,v=new RegExp(t.source,p+"g");while(c=i(m,v,r)){if(u=v.lastIndex,u>A&&(w(d,k(r,A,c.index)),c.length>1&&c.index<r.length&&o(x,d,g(c,1)),f=c[0].length,A=u,d.length>=s))break;v.lastIndex===c.index&&v.lastIndex++}return A===r.length?!f&&B(v,"")||w(d,""):w(d,k(r,A)),d.length>s?g(d,0,s):d}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:i(e,this,t,n)}:e,[function(e,n){var o=l(this),s=void 0==e?void 0:p(e,t);return s?i(s,e,o,n):i(r,h(o),e,n)},function(t,o){var i=c(this),s=h(t),a=n(r,i,s,o,r!==e);if(a.done)return a.value;var l=u(i,RegExp),p=i.unicode,g=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.unicode?"u":"")+(y?"g":"y"),m=new l(y?"^(?:"+i.source+")":i,g),v=void 0===o?C:o>>>0;if(0===v)return[];if(0===s.length)return null===A(m,s)?[s]:[];var b=0,x=0,B=[];while(x<s.length){m.lastIndex=y?0:x;var I,E=A(m,y?k(s,x):s);if(null===E||(I=S(d(m.lastIndex+(y?x:0)),s.length))===b)x=f(s,x,p);else{if(w(B,k(s,b,x)),B.length===v)return B;for(var T=1;T<=E.length-1;T++)if(w(B,E[T]),B.length===v)return B;x=b=I}}return w(B,k(s,b)),B}]}),!I,y)},"14c3":function(t,e,n){var o=n("da84"),i=n("c65b"),r=n("825a"),s=n("1626"),a=n("c6b6"),c=n("9263"),l=o.TypeError;t.exports=function(t,e){var n=t.exec;if(s(n)){var o=i(n,t,e);return null!==o&&r(o),o}if("RegExp"===a(t))return i(c,t,e);throw l("RegExp#exec called on incompatible receiver")}},1632:function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEXh7vLf7PDj8PTm8/ecW+lZAAACZElEQVQozw2RsU8TUQCHfz3fw7MS87jeI7DdmSMpDEoHE+P0HqGkvRR8vb5XC4NpN2RQZqcK9xJkwtriekcggerC4OZADDiT+A+goxv/gfwB3zd8H/T6vYF/pTZkCSmDNd3CBEtmZJP4N+CvvhecDvmntKsvwB17rpbIRTLOEoYkj9KZzRUuJsuBQFwgptyJ3Y7EL4V+ud5LO1UnMeQSSObqisiISZkbQBlliP3qWSk3GPQXjxv6VF2BTDO4ySx1zhuJXbA2wBNJF4t5vH9keg6wu5NvUpLtXrZ3OHC9ZsgVcZdOl38PM1y/L6m8GRiErj4AqezUjHGatGGIgs5NJDHh8Ua1IuB4035haVT6SaYWMoQ0eJ3rB/Gpnr3fB49YAy1Wa21YKqAHOmAveVw6CCMGMZh5bGtVI7jnZaiQNbta1Z+285oSoKoRbta1KZ/1bBdKH/RIxv2pRVpkoCmvpr097RWoo0CpMlTWllIenSjECU8mV43mHx2fIRfH/pncrJm3+58BWdbSqCS07/yiQnvHiCG4ZPGRFeAtfreoOubyctzHvLNHhjNvIhukxQzjU5O6QdOEzUp1Ef4d98Pxz+IPYX0bcpnT52dbedfz8y7C4R89RV+MjJkuCCx7mWDt4eyK/62lQB55xXGJK7p8u6bgRv4hVHylelYGGFs64W94tng8sAIVqSRJBpqRA9rFvAysS+9ak8s7557pz5HR4qhCRmWgplpTRJ+bhYfSAMO8/YBucWPuSdmFFtOnuWqvV2NbF6CJnbhNDzEZ/T0XSDrUydzkZCG1z/oIEyUFYxW/KPXNfwopuHDcO04UAAAAAElFTkSuQmCC"},"1e75":function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEXM2t7O3ODQ3uLR4OTDp25yAAACdUlEQVQozw3P70sTcQDH8c/3/M7NG+j35mnHwjwh4hRy/QFK3zvPNbeIG1koPZmxfj2IDAwihL53zj0JYisfmEHcZJZOiBUG60lZiI8T/ANusuftgQ+kCPIPeMP7hS5mUrV9c1g6MQCAEZ8tDLHwofImAGRlX+SZK3Vu9rRRPuO4PK6/9nA4GIATsxlODS+rdCMhkAZivpYV0LWoQHSLSA4NfUg+6mY+7BKL2++F9LvnrBDYm6JO9i/YO3i/HJTGQ4pdIV82TbEDFG6vGYCd4wZchgK5J2CrKTLE+Tx0v+YGlIbdWJFcQl4ptBNLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["detail"],{"004c":function(t,e,n){"use strict";n("fe9c")},"057f":function(t,e,n){var o=n("c6b6"),i=n("fc6a"),r=n("241c").f,a=n("4dae"),s="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],c=function(t){try{return r(t)}catch(e){return a(s)}};t.exports.f=function(t){return s&&"Window"==o(t)?c(t):r(i(t))}},"05b3":function(t,e,n){},"0827":function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEUWGBkYGhsdHyAfISI1t/v6AAAB5ElEQVQozxXQsYoTURSA4f/EeycZsDgDdySDjihk38Hy3GWi2J2BCaziQhaiaB+tt9AFu1kwvYUPsIXNPoB9BAUfwAfwEUzKv/v4odGrroyp9/rUaC6rZ5skv5F8qPsfYYP+yKUMymmAEEeW55oUR4o8jr05KNzJ07yvB7w0KKfLwcQUSjfmMU0PJfPHFoEVU+ohNrcKMEzMQ23FDnVSI2dqtYWI7KlLu6vE4UnyvKc3SJuL7lBbeEEl42ItpGLjzIT8PRJCmkRjVpVpsbJFVN0687okJNZiHAr5Z7MV0BnGIDc+THM1zlbieBc1Fq+tH5BH+OpnbWkj40hSqC8Lw2TvFuF0SUFJCk2IytXbjeqcRAt6NHpnrUkUU4KRzZs8RCK8N/Akn2W04LwxMU/V7XK0bDyN2RxfDyx7I4h5vjZby72V8UnOWumZL3qtYc+8DTE0siSBMXGhywx2dMYPnQHbxdFZ7deiNGxCCtD/QWnbwDoGhRYPDzUdUA3krjpnkvdAgDN4ddLkEQSov9qjd42HaDjI34gEqS9TUueAk+sc4qg5ws407KQYKs8G1jv4xBlqBVk6cb4dISZIwVi1Jzu4+HLk6lyfUxkXvwy+1Q+4WVdHIhwfybZ6CWVhxMEhShOgsP/HOW0MvZJeFwAAAABJRU5ErkJggg=="},"0928":function(t,e,n){"use strict";n("7715")},1276:function(t,e,n){"use strict";var o=n("2ba4"),i=n("c65b"),r=n("e330"),a=n("d784"),s=n("44e7"),c=n("825a"),u=n("1d80"),f=n("4840"),l=n("8aa5"),A=n("50c4"),d=n("577e"),g=n("dc4a"),h=n("4dae"),p=n("14c3"),m=n("9263"),v=n("9f7f"),b=n("d039"),C=v.UNSUPPORTED_Y,y=4294967295,S=Math.min,I=[].push,B=r(/./.exec),x=r(I),w=r("".slice),k=!b((function(){var t=/(?:)/,e=t.exec;t.exec=function(){return e.apply(this,arguments)};var n="ab".split(t);return 2!==n.length||"a"!==n[0]||"b"!==n[1]}));a("split",(function(t,e,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var r=d(u(this)),a=void 0===n?y:n>>>0;if(0===a)return[];if(void 0===t)return[r];if(!s(t))return i(e,r,t,a);var c,f,l,A=[],g=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),p=0,v=new RegExp(t.source,g+"g");while(c=i(m,v,r)){if(f=v.lastIndex,f>p&&(x(A,w(r,p,c.index)),c.length>1&&c.index<r.length&&o(I,A,h(c,1)),l=c[0].length,p=f,A.length>=a))break;v.lastIndex===c.index&&v.lastIndex++}return p===r.length?!l&&B(v,"")||x(A,""):x(A,w(r,p)),A.length>a?h(A,0,a):A}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:i(e,this,t,n)}:e,[function(e,n){var o=u(this),a=void 0==e?void 0:g(e,t);return a?i(a,e,o,n):i(r,d(o),e,n)},function(t,o){var i=c(this),a=d(t),s=n(r,i,a,o,r!==e);if(s.done)return s.value;var u=f(i,RegExp),g=i.unicode,h=(i.ignoreCase?"i":"")+(i.multiline?"m":"")+(i.unicode?"u":"")+(C?"g":"y"),m=new u(C?"^(?:"+i.source+")":i,h),v=void 0===o?y:o>>>0;if(0===v)return[];if(0===a.length)return null===p(m,a)?[a]:[];var b=0,I=0,B=[];while(I<a.length){m.lastIndex=C?0:I;var k,E=p(m,C?w(a,I):a);if(null===E||(k=S(A(m.lastIndex+(C?I:0)),a.length))===b)I=l(a,I,g);else{if(x(B,w(a,b,I)),B.length===v)return B;for(var D=1;D<=E.length-1;D++)if(x(B,E[D]),B.length===v)return B;I=b=k}}return x(B,w(a,b)),B}]}),!k,C)},"14c3":function(t,e,n){var o=n("da84"),i=n("c65b"),r=n("825a"),a=n("1626"),s=n("c6b6"),c=n("9263"),u=o.TypeError;t.exports=function(t,e){var n=t.exec;if(a(n)){var o=i(n,t,e);return null!==o&&r(o),o}if("RegExp"===s(t))return i(c,t,e);throw u("RegExp#exec called on incompatible receiver")}},1632:function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEXh7vLf7PDj8PTm8/ecW+lZAAACZElEQVQozw2RsU8TUQCHfz3fw7MS87jeI7DdmSMpDEoHE+P0HqGkvRR8vb5XC4NpN2RQZqcK9xJkwtriekcggerC4OZADDiT+A+goxv/gfwB3zd8H/T6vYF/pTZkCSmDNd3CBEtmZJP4N+CvvhecDvmntKsvwB17rpbIRTLOEoYkj9KZzRUuJsuBQFwgptyJ3Y7EL4V+ud5LO1UnMeQSSObqisiISZkbQBlliP3qWSk3GPQXjxv6VF2BTDO4ySx1zhuJXbA2wBNJF4t5vH9keg6wu5NvUpLtXrZ3OHC9ZsgVcZdOl38PM1y/L6m8GRiErj4AqezUjHGatGGIgs5NJDHh8Ua1IuB4035haVT6SaYWMoQ0eJ3rB/Gpnr3fB49YAy1Wa21YKqAHOmAveVw6CCMGMZh5bGtVI7jnZaiQNbta1Z+285oSoKoRbta1KZ/1bBdKH/RIxv2pRVpkoCmvpr097RWoo0CpMlTWllIenSjECU8mV43mHx2fIRfH/pncrJm3+58BWdbSqCS07/yiQnvHiCG4ZPGRFeAtfreoOubyctzHvLNHhjNvIhukxQzjU5O6QdOEzUp1Ef4d98Pxz+IPYX0bcpnT52dbedfz8y7C4R89RV+MjJkuCCx7mWDt4eyK/62lQB55xXGJK7p8u6bgRv4hVHylelYGGFs64W94tng8sAIVqSRJBpqRA9rFvAysS+9ak8s7557pz5HR4qhCRmWgplpTRJ+bhYfSAMO8/YBucWPuSdmFFtOnuWqvV2NbF6CJnbhNDzEZ/T0XSDrUydzkZCG1z/oIEyUFYxW/KPXNfwopuHDcO04UAAAAAElFTkSuQmCC"},"1e75":function(t,e){t.exports="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyAgMAAABjUWAiAAAADFBMVEXM2t7O3ODQ3uLR4OTDp25yAAACdUlEQVQozw3P70sTcQDH8c/3/M7NG+j35mnHwjwh4hRy/QFK3zvPNbeIG1koPZmxfj2IDAwihL53zj0JYisfmEHcZJZOiBUG60lZiI8T/ANusuftgQ+kCPIPeMP7hS5mUrV9c1g6MQCAEZ8tDLHwofImAGRlX+SZK3Vu9rRRPuO4PK6/9nA4GIATsxlODS+rdCMhkAZivpYV0LWoQHSLSA4NfUg+6mY+7BKL2++F9LvnrBDYm6JO9i/YO3i/HJTGQ4pdIV82TbEDFG6vGYCd4wZchgK5J2CrKTLE+Tx0v+YGlIbdWJFcQl4ptBNLine truncated
|
||||
@@ -21,7 +21,8 @@ class ReaderProvider : ContentProvider() {
|
||||
private enum class RequestCode {
|
||||
SaveBookSource, SaveBookSources, DeleteBookSources, GetBookSource, GetBookSources,
|
||||
SaveRssSource, SaveRssSources, DeleteRssSources, GetRssSource, GetRssSources,
|
||||
SaveBook, GetBookshelf, RefreshToc, GetChapterList, GetBookContent, GetBookCover
|
||||
SaveBook, GetBookshelf, RefreshToc, GetChapterList, GetBookContent, GetBookCover,
|
||||
SaveBookProgress
|
||||
}
|
||||
|
||||
private val postBodyKey = "json"
|
||||
@@ -86,6 +87,9 @@ class ReaderProvider : ContentProvider() {
|
||||
RequestCode.SaveBook -> values?.let {
|
||||
BookController.saveBook(values.getAsString(postBodyKey))
|
||||
}
|
||||
RequestCode.SaveBookProgress -> values?.let {
|
||||
BookController.saveBookProgress(values.getAsString(postBodyKey))
|
||||
}
|
||||
else -> throw IllegalStateException(
|
||||
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name
|
||||
)
|
||||
|
||||
@@ -1,33 +1,26 @@
|
||||
package io.legado.app.api.controller
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import androidx.core.graphics.drawable.toBitmap
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import io.legado.app.api.ReturnData
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookProgress
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.help.BookHelp
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.ContentProcessor
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.glide.ImageLoader
|
||||
import io.legado.app.help.storage.AppWebDav
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.model.ReadBook
|
||||
import io.legado.app.model.localBook.EpubFile
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.model.localBook.UmdFile
|
||||
import io.legado.app.model.webBook.WebBook
|
||||
import io.legado.app.ui.book.read.page.provider.ImageProvider
|
||||
import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
object BookController {
|
||||
|
||||
@@ -177,7 +170,6 @@ object BookController {
|
||||
var content: String? = BookHelp.getContent(book, chapter)
|
||||
if (content != null) {
|
||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||
saveBookReadIndex(book, index)
|
||||
content = runBlocking {
|
||||
contentProcessor.getContent(book, chapter, content!!, includeTitle = false)
|
||||
.joinToString("\n")
|
||||
@@ -190,7 +182,6 @@ object BookController {
|
||||
content = runBlocking {
|
||||
WebBook.getContentAwait(this, bookSource, book, chapter).let {
|
||||
val contentProcessor = ContentProcessor.get(book.name, book.origin)
|
||||
saveBookReadIndex(book, index)
|
||||
contentProcessor.getContent(book, chapter, it, includeTitle = false)
|
||||
.joinToString("\n")
|
||||
}
|
||||
@@ -222,20 +213,26 @@ object BookController {
|
||||
/**
|
||||
* 保存进度
|
||||
*/
|
||||
private fun saveBookReadIndex(book: Book, index: Int) {
|
||||
book.durChapterIndex = index
|
||||
book.durChapterTime = System.currentTimeMillis()
|
||||
appDb.bookChapterDao.getChapter(book.bookUrl, index)?.let {
|
||||
book.durChapterTitle = it.title
|
||||
}
|
||||
appDb.bookDao.update(book)
|
||||
AppWebDav.uploadBookProgress(book)
|
||||
if (ReadBook.book?.bookUrl == book.bookUrl) {
|
||||
ReadBook.book = book
|
||||
ReadBook.durChapterIndex = index
|
||||
ReadBook.clearTextChapter()
|
||||
ReadBook.loadContent(true)
|
||||
}
|
||||
fun saveBookProgress(postData: String?): ReturnData {
|
||||
val returnData = ReturnData()
|
||||
GSON.fromJsonObject<BookProgress>(postData)
|
||||
.onFailure { it.printOnDebug() }
|
||||
.getOrNull()?.let { bookProgress ->
|
||||
appDb.bookDao.getBook(bookProgress.name, bookProgress.author)?.let { book ->
|
||||
book.durChapterIndex = bookProgress.durChapterIndex
|
||||
book.durChapterPos = bookProgress.durChapterPos
|
||||
book.durChapterTitle = bookProgress.durChapterTitle
|
||||
book.durChapterTime = bookProgress.durChapterTime
|
||||
appDb.bookDao.update(book)
|
||||
AppWebDav.uploadBookProgress(bookProgress)
|
||||
if (ReadBook.book?.bookUrl == book.bookUrl) {
|
||||
ReadBook.book = book
|
||||
ReadBook.durChapterIndex = book.durChapterIndex
|
||||
}
|
||||
return returnData.setData("")
|
||||
}
|
||||
}
|
||||
return returnData.setErrorMsg("格式不对")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,45 +245,7 @@ object BookController {
|
||||
val fileData = parameters["fileData"]?.firstOrNull()
|
||||
?: return returnData.setErrorMsg("fileData 不能为空")
|
||||
kotlin.runCatching {
|
||||
val defaultBookTreeUri = AppConfig.defaultBookTreeUri
|
||||
if (defaultBookTreeUri.isNullOrBlank()) return returnData.setErrorMsg("没有设置书籍保存位置!")
|
||||
val treeUri = Uri.parse(defaultBookTreeUri)
|
||||
val fileBytes =
|
||||
Base64.decode(fileData.substringAfter("base64,"), Base64.DEFAULT)
|
||||
val uri = if (treeUri.isContentScheme()) {
|
||||
val treeDoc = DocumentFile.fromTreeUri(appCtx, treeUri)
|
||||
var doc = treeDoc!!.findFile(fileName)
|
||||
if (doc == null) {
|
||||
doc = treeDoc.createFile(FileUtils.getMimeType(fileName), fileName)
|
||||
?: throw SecurityException("Permission Denial")
|
||||
}
|
||||
appCtx.contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
|
||||
oStream.write(fileBytes)
|
||||
}
|
||||
doc.uri
|
||||
} else {
|
||||
val treeFile = File(treeUri.path!!)
|
||||
val file = treeFile.getFile(fileName)
|
||||
FileOutputStream(file).use { oStream ->
|
||||
oStream.write(fileBytes)
|
||||
}
|
||||
Uri.fromFile(file)
|
||||
}
|
||||
val nameAuthor = LocalBook.analyzeNameAuthor(fileName)
|
||||
val book = Book(
|
||||
bookUrl = uri.toString(),
|
||||
name = nameAuthor.first,
|
||||
author = nameAuthor.second,
|
||||
originName = fileName,
|
||||
coverUrl = FileUtils.getPath(
|
||||
appCtx.externalFiles,
|
||||
"covers",
|
||||
"${MD5Utils.md5Encode16(uri.toString())}.jpg"
|
||||
)
|
||||
)
|
||||
if (book.isEpub()) EpubFile.upBookInfo(book)
|
||||
if (book.isUmd()) UmdFile.upBookInfo(book)
|
||||
appDb.bookDao.insert(book)
|
||||
LocalBook.importFileOnLine(fileData, fileName)
|
||||
}.onFailure {
|
||||
return when (it) {
|
||||
is SecurityException -> returnData.setErrorMsg("需重新设置书籍保存位置!")
|
||||
|
||||
@@ -5,11 +5,12 @@ import androidx.annotation.IntDef
|
||||
object BookType {
|
||||
const val default = 0 // 0 文本
|
||||
const val audio = 1 // 1 音频
|
||||
const val image = 2 //图片
|
||||
const val image = 2 // 2 图片
|
||||
const val file = 3 // 3 只提供下载服务的网站
|
||||
const val local = "loc_book"
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@IntDef(default, audio, image)
|
||||
@IntDef(default, audio, image, file)
|
||||
annotation class Type
|
||||
}
|
||||
@@ -28,4 +28,5 @@ object EventBus {
|
||||
const val TIP_COLOR = "tipColor"
|
||||
const val SOURCE_CHANGED = "sourceChanged"
|
||||
const val SEARCH_RESULT = "searchResult"
|
||||
const val BOOK_URL_CHANGED = "bookUrlChanged"
|
||||
}
|
||||
@@ -20,7 +20,7 @@ val appDb by lazy {
|
||||
}
|
||||
|
||||
@Database(
|
||||
version = 48,
|
||||
version = 49,
|
||||
exportSchema = true,
|
||||
entities = [Book::class, BookGroup::class, BookSource::class, BookChapter::class,
|
||||
ReplaceRule::class, SearchBook::class, SearchKeyword::class, Cookie::class,
|
||||
@@ -32,7 +32,8 @@ val appDb by lazy {
|
||||
AutoMigration(from = 44, to = 45),
|
||||
AutoMigration(from = 45, to = 46),
|
||||
AutoMigration(from = 46, to = 47),
|
||||
AutoMigration(from = 47, to = 48)
|
||||
AutoMigration(from = 47, to = 48),
|
||||
AutoMigration(from = 48, to = 49)
|
||||
]
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
@@ -21,6 +21,7 @@ interface BaseSource : JsExtensions {
|
||||
var loginUrl: String? // 登录地址
|
||||
var loginUi: String? // 登录UI
|
||||
var header: String? // 请求头
|
||||
var enabledCookieJar: Boolean? //启用cookieJar
|
||||
|
||||
fun getTag(): String
|
||||
|
||||
|
||||
@@ -154,6 +154,10 @@ data class Book(
|
||||
@IgnoredOnParcel
|
||||
override var tocHtml: String? = null
|
||||
|
||||
@Ignore
|
||||
@IgnoredOnParcel
|
||||
var downloadUrls: List<String>? = null
|
||||
|
||||
fun getRealAuthor() = author.replace(AppPattern.authorRegex, "")
|
||||
|
||||
fun getUnreadChapterNum() = max(totalChapterNum - durChapterIndex - 1, 0)
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.room.Ignore
|
||||
import androidx.room.Index
|
||||
import com.github.liuyueyi.quick.transfer.ChineseUtils
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.exception.RegexTimeoutException
|
||||
@@ -15,6 +16,7 @@ import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||
import io.legado.app.model.analyzeRule.RuleDataInterface
|
||||
import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import splitties.init.appCtx
|
||||
@@ -93,7 +95,7 @@ data class BookChapter(
|
||||
2 -> displayTitle = ChineseUtils.s2t(displayTitle)
|
||||
}
|
||||
}
|
||||
if (useReplace && replaceRules != null) {
|
||||
if (useReplace && replaceRules != null) kotlin.run {
|
||||
replaceRules.forEach { item ->
|
||||
if (item.pattern.isNotEmpty()) {
|
||||
try {
|
||||
@@ -112,7 +114,10 @@ data class BookChapter(
|
||||
} catch (e: RegexTimeoutException) {
|
||||
item.isEnabled = false
|
||||
appDb.replaceRuleDao.update(item)
|
||||
} catch (e: CancellationException) {
|
||||
return@run
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("${item.name}替换出错\n替换内容\n${displayTitle}", e)
|
||||
appCtx.toastOnUi("${item.name}替换出错")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import kotlinx.parcelize.Parcelize
|
||||
import splitties.init.appCtx
|
||||
import java.io.InputStream
|
||||
|
||||
@Suppress("unused")
|
||||
@Parcelize
|
||||
@TypeConverters(BookSource.Converters::class)
|
||||
@Entity(
|
||||
@@ -27,7 +28,7 @@ data class BookSource(
|
||||
var bookSourceName: String = "",
|
||||
// 分组
|
||||
var bookSourceGroup: String? = null,
|
||||
// 类型,0 文本,1 音频, 2 图片
|
||||
// 类型,0 文本,1 音频, 2 图片, 3 文件(指的是类似知轩藏书只提供下载的网站)
|
||||
@BookType.Type
|
||||
var bookSourceType: Int = 0,
|
||||
// 详情页url正则
|
||||
@@ -38,6 +39,9 @@ data class BookSource(
|
||||
var enabled: Boolean = true,
|
||||
// 启用发现
|
||||
var enabledExplore: Boolean = true,
|
||||
// 启用okhttp CookieJAr 自动保存每次请求的cookie
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
override var enabledCookieJar: Boolean? = false,
|
||||
// 并发率
|
||||
override var concurrentRate: String? = null,
|
||||
// 请求头
|
||||
@@ -158,7 +162,7 @@ data class BookSource(
|
||||
|
||||
fun removeGroup(groups: String): BookSource {
|
||||
bookSourceGroup?.splitNotBlank(AppPattern.splitGroupRegex)?.toHashSet()?.let {
|
||||
it.removeAll(groups.splitNotBlank(AppPattern.splitGroupRegex))
|
||||
it.removeAll(groups.splitNotBlank(AppPattern.splitGroupRegex).toSet())
|
||||
bookSourceGroup = TextUtils.join(",", it)
|
||||
}
|
||||
return this
|
||||
@@ -190,6 +194,7 @@ data class BookSource(
|
||||
&& equal(bookSourceComment, source.bookSourceComment)
|
||||
&& enabled == source.enabled
|
||||
&& enabledExplore == source.enabledExplore
|
||||
&& enabledCookieJar == source.enabledCookieJar
|
||||
&& equal(header, source.header)
|
||||
&& loginUrl == source.loginUrl
|
||||
&& equal(exploreUrl, source.exploreUrl)
|
||||
|
||||
@@ -24,6 +24,8 @@ data class HttpTTS(
|
||||
override var loginUrl: String? = null,
|
||||
override var loginUi: String? = null,
|
||||
override var header: String? = null,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
override var enabledCookieJar: Boolean? = false,
|
||||
var loginCheckJs: String? = null,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
var lastUpdateTime: Long = System.currentTimeMillis()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.legado.app.data.entities
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
@@ -19,6 +20,8 @@ data class RssSource(
|
||||
var sourceGroup: String? = null,
|
||||
var sourceComment: String? = null,
|
||||
var enabled: Boolean = true,
|
||||
@ColumnInfo(defaultValue = "0")
|
||||
override var enabledCookieJar: Boolean? = false,
|
||||
override var concurrentRate: String? = null, //并发率
|
||||
override var header: String? = null, // 请求头
|
||||
override var loginUrl: String? = null, // 登录地址
|
||||
@@ -150,6 +153,7 @@ data class RssSource(
|
||||
style = doc.readString("$.style"),
|
||||
enableJs = doc.readBool("$.enableJs") ?: true,
|
||||
loadWithBaseUrl = doc.readBool("$.loadWithBaseUrl") ?: true,
|
||||
enabledCookieJar = doc.readBool("$.enabledCookieJar") ?: false,
|
||||
customOrder = doc.readInt("$.customOrder") ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,5 +16,6 @@ data class BookInfoRule(
|
||||
var coverUrl: String? = null,
|
||||
var tocUrl: String? = null,
|
||||
var wordCount: String? = null,
|
||||
var canReName: String? = null
|
||||
var canReName: String? = null,
|
||||
var downloadUrls: String? = null
|
||||
) : Parcelable
|
||||
@@ -12,6 +12,7 @@ import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.utils.msg
|
||||
import io.legado.app.utils.replace
|
||||
import io.legado.app.utils.toastOnUi
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import splitties.init.appCtx
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
@@ -135,7 +136,7 @@ class ContentProcessor private constructor(
|
||||
var mContent = content
|
||||
getContentReplaceRules().forEach { item ->
|
||||
if (item.pattern.isNotEmpty()) {
|
||||
kotlin.runCatching {
|
||||
try {
|
||||
mContent = if (item.isRegex) {
|
||||
mContent.replace(
|
||||
item.pattern.toRegex(),
|
||||
@@ -145,18 +146,15 @@ class ContentProcessor private constructor(
|
||||
} else {
|
||||
mContent.replace(item.pattern, item.replacement)
|
||||
}
|
||||
}.onFailure {
|
||||
when (it) {
|
||||
is RegexTimeoutException -> {
|
||||
item.isEnabled = false
|
||||
appDb.replaceRuleDao.update(item)
|
||||
return item.name + it.msg
|
||||
}
|
||||
else -> {
|
||||
AppLog.put("${item.name}替换出错\n${it.localizedMessage}", it)
|
||||
appCtx.toastOnUi("${item.name}替换出错")
|
||||
}
|
||||
}
|
||||
} catch (e: RegexTimeoutException) {
|
||||
item.isEnabled = false
|
||||
appDb.replaceRuleDao.update(item)
|
||||
return item.name + e.msg
|
||||
} catch (e: CancellationException) {
|
||||
return mContent
|
||||
} catch (e: Exception) {
|
||||
AppLog.put("${item.name}替换出错\n替换内容\n${mContent}", e)
|
||||
appCtx.toastOnUi("${item.name}替换出错")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,12 +197,10 @@ interface JsExtensions {
|
||||
*js实现读取cookie
|
||||
*/
|
||||
fun getCookie(tag: String, key: String? = null): String {
|
||||
val cookie = CookieStore.getCookie(tag)
|
||||
val cookieMap = CookieStore.cookieToMap(cookie)
|
||||
return if (key != null) {
|
||||
cookieMap[key] ?: ""
|
||||
CookieStore.getKey(tag, key)
|
||||
} else {
|
||||
cookie
|
||||
CookieStore.getCookie(tag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,10 +468,8 @@ interface JsExtensions {
|
||||
* @return zip指定文件的数据
|
||||
*/
|
||||
fun getZipByteArrayContent(url: String, path: String): ByteArray? {
|
||||
val bytes = if (url.startsWith("http://") || url.startsWith("https://")) {
|
||||
runBlocking {
|
||||
return@runBlocking okHttpClient.newCallResponseBody { url(url) }.bytes()
|
||||
}
|
||||
val bytes = if (url.isAbsUrl()) {
|
||||
AnalyzeUrl(url, source = getSource()).getByteArray()
|
||||
} else {
|
||||
StringUtils.hexStringToByte(url)
|
||||
}
|
||||
@@ -517,7 +513,7 @@ interface JsExtensions {
|
||||
str.isAbsUrl() -> runBlocking {
|
||||
var x = CacheManager.getByteArray(key)
|
||||
if (x == null) {
|
||||
x = okHttpClient.newCallResponseBody { url(str) }.bytes()
|
||||
x = AnalyzeUrl(str, source = getSource()).getByteArray()
|
||||
x.let {
|
||||
CacheManager.put(key, it)
|
||||
}
|
||||
|
||||
@@ -1,43 +1,47 @@
|
||||
package io.legado.app.help
|
||||
|
||||
import io.legado.app.data.entities.ReplaceRule
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.utils.*
|
||||
|
||||
object ReplaceAnalyzer {
|
||||
|
||||
fun jsonToReplaceRules(json: String): List<ReplaceRule> {
|
||||
val replaceRules = mutableListOf<ReplaceRule>()
|
||||
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
|
||||
for (item in items) {
|
||||
val jsonItem = jsonPath.parse(item)
|
||||
jsonToReplaceRule(jsonItem.jsonString())?.let {
|
||||
if (it.isValid()) {
|
||||
replaceRules.add(it)
|
||||
fun jsonToReplaceRules(json: String): Result<MutableList<ReplaceRule>> {
|
||||
return kotlin.runCatching {
|
||||
val replaceRules = mutableListOf<ReplaceRule>()
|
||||
val items: List<Map<String, Any>> = jsonPath.parse(json).read("$")
|
||||
for (item in items) {
|
||||
val jsonItem = jsonPath.parse(item)
|
||||
jsonToReplaceRule(jsonItem.jsonString()).getOrThrow().let {
|
||||
if (it.isValid()) {
|
||||
replaceRules.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
replaceRules
|
||||
}
|
||||
return replaceRules
|
||||
}
|
||||
|
||||
private fun jsonToReplaceRule(json: String): ReplaceRule? {
|
||||
val replaceRule: ReplaceRule? = GSON.fromJsonObject<ReplaceRule>(json.trim()).getOrNull()
|
||||
runCatching {
|
||||
fun jsonToReplaceRule(json: String): Result<ReplaceRule> {
|
||||
return runCatching {
|
||||
val replaceRule: ReplaceRule? =
|
||||
GSON.fromJsonObject<ReplaceRule>(json.trim()).getOrNull()
|
||||
if (replaceRule == null || replaceRule.pattern.isBlank()) {
|
||||
val jsonItem = jsonPath.parse(json.trim())
|
||||
val rule = ReplaceRule()
|
||||
rule.id = jsonItem.readLong("$.id") ?: System.currentTimeMillis()
|
||||
rule.pattern = jsonItem.readString("$.regex") ?: ""
|
||||
if (rule.pattern.isEmpty()) return null
|
||||
if (rule.pattern.isEmpty()) throw NoStackTraceException("格式不对")
|
||||
rule.name = jsonItem.readString("$.replaceSummary") ?: ""
|
||||
rule.replacement = jsonItem.readString("$.replacement") ?: ""
|
||||
rule.isRegex = jsonItem.readBool("$.isRegex") == true
|
||||
rule.scope = jsonItem.readString("$.useTo")
|
||||
rule.isEnabled = jsonItem.readBool("$.enable") == true
|
||||
rule.order = jsonItem.readInt("$.serialNumber") ?: 0
|
||||
return rule
|
||||
return@runCatching rule
|
||||
}
|
||||
return@runCatching replaceRule
|
||||
}
|
||||
return replaceRule
|
||||
}
|
||||
|
||||
}
|
||||
@@ -150,6 +150,7 @@ object SourceAnalyzer {
|
||||
source.customOrder = sourceAny.customOrder
|
||||
source.enabled = sourceAny.enabled
|
||||
source.enabledExplore = sourceAny.enabledExplore
|
||||
source.enabledCookieJar = sourceAny.enabledCookieJar
|
||||
source.concurrentRate = sourceAny.concurrentRate
|
||||
source.header = sourceAny.header
|
||||
source.loginUrl = when (sourceAny.loginUrl) {
|
||||
@@ -219,6 +220,7 @@ object SourceAnalyzer {
|
||||
var customOrder: Int = 0, // 手动排序编号
|
||||
var enabled: Boolean = true, // 是否启用
|
||||
var enabledExplore: Boolean = true, // 启用发现
|
||||
var enabledCookieJar: Boolean = false, // 启用CookieJar
|
||||
var concurrentRate: String? = null, // 并发率
|
||||
var header: String? = null, // 请求头
|
||||
var loginUrl: Any? = null, // 登录规则
|
||||
|
||||
@@ -32,7 +32,7 @@ object SourceVerificationHelp {
|
||||
startBrowser(source, url, title, true)
|
||||
}
|
||||
|
||||
var waitUserInput: Boolean = false
|
||||
var waitUserInput = false
|
||||
while(CacheManager.get(key) == null) {
|
||||
if (!waitUserInput) {
|
||||
AppLog.putDebug("等待返回验证结果...")
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.apache.commons.text.StringEscapeUtils
|
||||
import splitties.init.appCtx
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
/**
|
||||
* 后台webView
|
||||
@@ -50,14 +51,14 @@ class BackstageWebView(
|
||||
|
||||
override fun onError(error: Throwable) {
|
||||
if (!block.isCompleted)
|
||||
block.cancel(error)
|
||||
block.resumeWithException(error)
|
||||
}
|
||||
}
|
||||
runOnUI {
|
||||
try {
|
||||
load()
|
||||
} catch (error: Throwable) {
|
||||
block.cancel(error)
|
||||
block.resumeWithException(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ package io.legado.app.help.http
|
||||
import android.text.TextUtils
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Cookie
|
||||
import io.legado.app.help.http.api.CookieManager
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.http.api.CookieManager
|
||||
import io.legado.app.utils.NetworkUtils
|
||||
|
||||
object CookieStore : CookieManager {
|
||||
@@ -44,7 +44,7 @@ object CookieStore : CookieManager {
|
||||
CacheManager.getFromMemory("${domain}_cookie")?.let { return it }
|
||||
val cookieBean = appDb.cookieDao.get(domain)
|
||||
val cookie = cookieBean?.cookie ?: ""
|
||||
CacheManager.putMemory(url, cookie ?: "")
|
||||
CacheManager.putMemory(url, cookie)
|
||||
return cookie
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ object CookieStore : CookieManager {
|
||||
|
||||
override fun removeCookie(url: String) {
|
||||
val domain = NetworkUtils.getSubDomain(url)
|
||||
CacheManager.deleteMemory("${domain}_cookie")
|
||||
appDb.cookieDao.delete(domain)
|
||||
CacheManager.deleteMemory("${domain}_cookie")
|
||||
android.webkit.CookieManager.getInstance().removeAllCookies(null)
|
||||
}
|
||||
|
||||
override fun cookieToMap(cookie: String): MutableMap<String, String> {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package io.legado.app.help.http
|
||||
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.help.CacheManager
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.http.cronet.CronetInterceptor
|
||||
import io.legado.app.help.http.cronet.CronetLoader
|
||||
import io.legado.app.utils.NetworkUtils
|
||||
import okhttp3.*
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
@@ -23,7 +25,10 @@ val cookieJar by lazy {
|
||||
|
||||
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
|
||||
cookies.forEach {
|
||||
CookieStore.replaceCookie(url.toString(), "${it.name}=${it.value}")
|
||||
//CookieStore.replaceCookie(url.toString(), "${it.name}=${it.value}")
|
||||
//临时保存 书源启用cookie选项再添加到数据库
|
||||
val domain = NetworkUtils.getSubDomain(url.toString())
|
||||
CacheManager.putMemory("${domain}_cookieJar", "${it.name}=${it.value}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -194,15 +194,28 @@ object AppWebDav {
|
||||
Coroutine.async {
|
||||
val bookProgress = BookProgress(book)
|
||||
val json = GSON.toJson(bookProgress)
|
||||
val url = getProgressUrl(book)
|
||||
val url = getProgressUrl(book.name, book.author)
|
||||
WebDav(url, authorization).upload(json.toByteArray(), "application/json")
|
||||
}.onError {
|
||||
AppLog.put("上传进度失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProgressUrl(book: Book): String {
|
||||
return bookProgressUrl + book.name + "_" + book.author + ".json"
|
||||
fun uploadBookProgress(bookProgress: BookProgress) {
|
||||
val authorization = authorization ?: return
|
||||
if (!syncBookProgress) return
|
||||
if (!NetworkUtils.isAvailable()) return
|
||||
Coroutine.async {
|
||||
val json = GSON.toJson(bookProgress)
|
||||
val url = getProgressUrl(bookProgress.name, bookProgress.author)
|
||||
WebDav(url, authorization).upload(json.toByteArray(), "application/json")
|
||||
}.onError {
|
||||
AppLog.put("上传进度失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getProgressUrl(name: String, author: String): String {
|
||||
return bookProgressUrl + name + "_" + author + ".json"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -210,7 +223,7 @@ object AppWebDav {
|
||||
*/
|
||||
suspend fun getBookProgress(book: Book): BookProgress? {
|
||||
authorization?.let {
|
||||
val url = getProgressUrl(book)
|
||||
val url = getProgressUrl(book.name, book.author)
|
||||
kotlin.runCatching {
|
||||
WebDav(url, it).download().let { byteArray ->
|
||||
val json = String(byteArray)
|
||||
|
||||
@@ -98,9 +98,12 @@ object ImportOldData {
|
||||
}
|
||||
|
||||
private fun importOldReplaceRule(json: String): Int {
|
||||
val rules = ReplaceAnalyzer.jsonToReplaceRules(json)
|
||||
appDb.replaceRuleDao.insert(*rules.toTypedArray())
|
||||
return rules.size
|
||||
val rules = ReplaceAnalyzer.jsonToReplaceRules(json).getOrNull()
|
||||
rules?.let {
|
||||
appDb.replaceRuleDao.insert(*rules.toTypedArray())
|
||||
return rules.size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun fromOldBooks(json: String): List<Book> {
|
||||
|
||||
@@ -22,40 +22,36 @@ import kotlinx.coroutines.withContext
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
||||
|
||||
object Restore {
|
||||
|
||||
suspend fun restore(context: Context, path: String) {
|
||||
withContext(IO) {
|
||||
kotlin.runCatching {
|
||||
if (path.isContentScheme()) {
|
||||
DocumentFile.fromTreeUri(context, Uri.parse(path))?.listFiles()?.forEach { doc ->
|
||||
for (fileName in Backup.backupFileNames) {
|
||||
if (doc.name == fileName) {
|
||||
DocumentUtils.readText(context, doc.uri).let {
|
||||
FileUtils.createFileIfNotExist("${Backup.backupPath}${File.separator}$fileName")
|
||||
.writeText(it)
|
||||
if (Backup.backupFileNames.contains(doc.name)) {
|
||||
context.contentResolver.openInputStream(doc.uri)?.use { inputStream ->
|
||||
val file = File("${Backup.backupPath}${File.separator}${doc.name}")
|
||||
FileOutputStream(file).use { outputStream ->
|
||||
inputStream.copyTo(outputStream)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
val file = File(path)
|
||||
for (fileName in Backup.backupFileNames) {
|
||||
file.getFile(fileName).let {
|
||||
if (it.exists()) {
|
||||
it.copyTo(
|
||||
FileUtils.createFileIfNotExist("${Backup.backupPath}${File.separator}$fileName"),
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
val dir = File(path)
|
||||
for (fileName in Backup.backupFileNames) {
|
||||
val file = dir.getFile(fileName)
|
||||
if (file.exists()) {
|
||||
val target = File("${Backup.backupPath}${File.separator}$fileName")
|
||||
file.copyTo(target, true)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
AppLog.put("恢复复制文件出错\n${it.localizedMessage}", it)
|
||||
}
|
||||
restoreDatabase()
|
||||
restoreConfig()
|
||||
@@ -129,7 +125,7 @@ object Restore {
|
||||
ThemeConfig.upConfig()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("恢复主题出错\n${e.localizedMessage}", e)
|
||||
}
|
||||
if (!BackupConfig.ignoreReadConfig) {
|
||||
//恢复阅读界面配置
|
||||
@@ -142,7 +138,7 @@ object Restore {
|
||||
ReadBookConfig.initConfigs()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("恢复阅读界面出错\n${e.localizedMessage}", e)
|
||||
}
|
||||
try {
|
||||
val file =
|
||||
@@ -153,7 +149,7 @@ object Restore {
|
||||
ReadBookConfig.initShareConfig()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printOnDebug()
|
||||
AppLog.put("恢复阅读界面出错\n${e.localizedMessage}", e)
|
||||
}
|
||||
}
|
||||
Preferences.getSharedPreferences(appCtx, path, "config")?.all?.let { map ->
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
@@ -118,7 +118,7 @@ class ColorPreference(context: Context, attrs: AttributeSet) : Preference(contex
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
val v = io.legado.app.ui.widget.prefs.Preference.bindView<ColorPanelView>(
|
||||
val v = io.legado.app.lib.prefs.Preference.bindView<ColorPanelView>(
|
||||
context, holder, icon, title, summary, widgetLayoutResource,
|
||||
io.legado.app.R.id.cpv_preference_preview_color_panel, 30, 30
|
||||
)
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.TextView
|
||||
import androidx.preference.EditTextPreference.OnBindEditTextListener
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import io.legado.app.R
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.utils.applyTint
|
||||
|
||||
class EditTextPreference(context: Context, attrs: AttributeSet) :
|
||||
androidx.preference.EditTextPreference(context, attrs) {
|
||||
|
||||
private var mOnBindEditTextListener: OnBindEditTextListener? = null
|
||||
private val onBindEditTextListener = OnBindEditTextListener { editText ->
|
||||
editText.applyTint(context.accentColor)
|
||||
mOnBindEditTextListener?.onBindEditText(editText)
|
||||
}
|
||||
|
||||
init {
|
||||
// isPersistent = true
|
||||
layoutResource = R.layout.view_preference
|
||||
super.setOnBindEditTextListener(onBindEditTextListener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
Preference.bindView<TextView>(context, holder, icon, title, summary, null, null)
|
||||
super.onBindViewHolder(holder)
|
||||
}
|
||||
|
||||
override fun setOnBindEditTextListener(onBindEditTextListener: OnBindEditTextListener?) {
|
||||
mOnBindEditTextListener = onBindEditTextListener
|
||||
}
|
||||
|
||||
}
|
||||
+10
-1
@@ -1,9 +1,11 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.EditTextPreferenceDialogFragmentCompat
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.lib.theme.filletBackground
|
||||
|
||||
class EditTextPreferenceDialog : EditTextPreferenceDialogFragmentCompat() {
|
||||
@@ -23,6 +25,13 @@ class EditTextPreferenceDialog : EditTextPreferenceDialogFragmentCompat() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window?.setBackgroundDrawable(requireContext().filletBackground)
|
||||
dialog.window?.decorView?.post {
|
||||
(dialog as AlertDialog).run {
|
||||
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
+10
-1
@@ -1,9 +1,11 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.ListPreferenceDialogFragmentCompat
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.lib.theme.filletBackground
|
||||
|
||||
class ListPreferenceDialog : ListPreferenceDialogFragmentCompat() {
|
||||
@@ -23,6 +25,13 @@ class ListPreferenceDialog : ListPreferenceDialogFragmentCompat() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window?.setBackgroundDrawable(requireContext().filletBackground)
|
||||
dialog.window?.decorView?.post {
|
||||
(dialog as AlertDialog).run {
|
||||
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
+10
-1
@@ -1,9 +1,11 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.MultiSelectListPreferenceDialogFragmentCompat
|
||||
import androidx.preference.PreferenceDialogFragmentCompat
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.lib.theme.filletBackground
|
||||
|
||||
class MultiSelectListPreferenceDialog : MultiSelectListPreferenceDialogFragmentCompat() {
|
||||
@@ -25,6 +27,13 @@ class MultiSelectListPreferenceDialog : MultiSelectListPreferenceDialogFragmentC
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window?.setBackgroundDrawable(requireContext().filletBackground)
|
||||
dialog.window?.decorView?.post {
|
||||
(dialog as AlertDialog).run {
|
||||
getButton(AlertDialog.BUTTON_NEGATIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_POSITIVE)?.setTextColor(accentColor)
|
||||
getButton(AlertDialog.BUTTON_NEUTRAL)?.setTextColor(accentColor)
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
+3
-9
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
@@ -25,14 +25,8 @@ class NameListPreference(context: Context, attrs: AttributeSet) : ListPreference
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
val v = Preference.bindView<TextView>(
|
||||
context,
|
||||
holder,
|
||||
icon,
|
||||
title,
|
||||
summary,
|
||||
widgetLayoutResource,
|
||||
R.id.text_view,
|
||||
isBottomBackground = isBottomBackground
|
||||
context, holder, icon, title, summary, widgetLayoutResource,
|
||||
R.id.text_view, isBottomBackground = isBottomBackground
|
||||
)
|
||||
if (v is TextView) {
|
||||
v.text = entry
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
package io.legado.app.lib.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
+8
-9
@@ -1,13 +1,13 @@
|
||||
package io.legado.app.base
|
||||
package io.legado.app.lib.prefs.fragment
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.preference.*
|
||||
import io.legado.app.ui.widget.prefs.EditTextPreferenceDialog
|
||||
import io.legado.app.ui.widget.prefs.ListPreferenceDialog
|
||||
import io.legado.app.ui.widget.prefs.MultiSelectListPreferenceDialog
|
||||
import io.legado.app.lib.prefs.EditTextPreferenceDialog
|
||||
import io.legado.app.lib.prefs.ListPreferenceDialog
|
||||
import io.legado.app.lib.prefs.MultiSelectListPreferenceDialog
|
||||
|
||||
abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
|
||||
abstract class PreferenceFragment : PreferenceFragmentCompat() {
|
||||
|
||||
private val dialogFragmentTag = "androidx.preference.PreferenceFragment.DIALOG"
|
||||
|
||||
@@ -34,7 +34,7 @@ abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
|
||||
return
|
||||
}
|
||||
|
||||
val f: DialogFragment = when (preference) {
|
||||
val dialogFragment: DialogFragment = when (preference) {
|
||||
is EditTextPreference -> {
|
||||
EditTextPreferenceDialog.newInstance(preference.getKey())
|
||||
}
|
||||
@@ -54,10 +54,9 @@ abstract class BasePreferenceFragment : PreferenceFragmentCompat() {
|
||||
}
|
||||
}
|
||||
@Suppress("DEPRECATION")
|
||||
f.setTargetFragment(this, 0)
|
||||
dialogFragment.setTargetFragment(this, 0)
|
||||
|
||||
f.show(parentFragmentManager, dialogFragmentTag)
|
||||
dialogFragment.show(parentFragmentManager, dialogFragmentTag)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -150,6 +150,7 @@ object BookCover {
|
||||
override var loginUrl: String? = null,
|
||||
override var loginUi: String? = null,
|
||||
override var header: String? = null,
|
||||
override var enabledCookieJar: Boolean? = false,
|
||||
) : BaseSource {
|
||||
|
||||
override fun getTag(): String {
|
||||
|
||||
@@ -131,9 +131,9 @@ object CacheBook {
|
||||
|
||||
class CacheBookModel(var bookSource: BookSource, var book: Book) {
|
||||
|
||||
private val waitDownloadSet = hashSetOf<Int>()
|
||||
private val onDownloadSet = hashSetOf<Int>()
|
||||
private val successDownloadSet = hashSetOf<Int>()
|
||||
private val waitDownloadSet = linkedSetOf<Int>()
|
||||
private val onDownloadSet = linkedSetOf<Int>()
|
||||
private val successDownloadSet = linkedSetOf<Int>()
|
||||
private val errorDownloadMap = hashMapOf<Int, Int>()
|
||||
|
||||
val waitCount get() = waitDownloadSet.size
|
||||
@@ -174,7 +174,7 @@ object CacheBook {
|
||||
}
|
||||
onDownloadSet.remove(index)
|
||||
//重试3次
|
||||
if (errorDownloadMap[index] ?: 0 < 3) {
|
||||
if ((errorDownloadMap[index] ?: 0) < 3) {
|
||||
waitDownloadSet.add(index)
|
||||
} else {
|
||||
AppLog.put(
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.legado.app.model
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.data.entities.*
|
||||
import io.legado.app.help.coroutine.CompositeCoroutine
|
||||
import io.legado.app.model.rss.Rss
|
||||
@@ -238,7 +239,11 @@ object Debug {
|
||||
.onSuccess {
|
||||
log(debugSource, "︽详情页解析完成")
|
||||
log(debugSource, showTime = false)
|
||||
tocDebug(scope, bookSource, book)
|
||||
if (book.type != BookType.file) {
|
||||
tocDebug(scope, bookSource, book)
|
||||
} else {
|
||||
log(debugSource, "≡文件类书源跳过解析目录", state = 1000)
|
||||
}
|
||||
}
|
||||
.onError {
|
||||
log(debugSource, it.msg, state = -1)
|
||||
|
||||
@@ -69,6 +69,7 @@ class AnalyzeUrl(
|
||||
private var retry: Int = 0
|
||||
private var useWebView: Boolean = false
|
||||
private var webJs: String? = null
|
||||
private val enabledCookieJar = source?.enabledCookieJar ?: false
|
||||
|
||||
init {
|
||||
if (!mUrl.isDataUrl()) {
|
||||
@@ -519,17 +520,26 @@ class AnalyzeUrl(
|
||||
}
|
||||
|
||||
/**
|
||||
*设置cookie urlOption的优先级大于书源保存的cookie
|
||||
*设置cookie 优先级
|
||||
* urlOption临时cookie > 数据库cookie = okhttp CookieJar保存在内存中的cookie
|
||||
*@param tag 书源url 缺省为传入的url
|
||||
*/
|
||||
private fun setCookie(tag: String?) {
|
||||
val cookie = CookieStore.getCookie(tag ?: url)
|
||||
val domain = NetworkUtils.getSubDomain(tag ?: url)
|
||||
//书源启用保存cookie时 添加内存中的cookie到数据库
|
||||
if (enabledCookieJar) {
|
||||
val key = "${domain}_cookieJar"
|
||||
CacheManager.getFromMemory(key)?.let {
|
||||
CookieStore.replaceCookie(domain, it)
|
||||
CacheManager.deleteMemory(key)
|
||||
}
|
||||
}
|
||||
val cookie = CookieStore.getCookie(domain)
|
||||
if (cookie.isNotEmpty()) {
|
||||
val cookieMap = CookieStore.cookieToMap(cookie)
|
||||
val customCookieMap = CookieStore.cookieToMap(headerMap["Cookie"] ?: "")
|
||||
cookieMap.putAll(customCookieMap)
|
||||
val newCookie = CookieStore.mapToCookie(cookieMap)
|
||||
newCookie?.let {
|
||||
CookieStore.mapToCookie(cookieMap)?.let {
|
||||
headerMap.put("Cookie", it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
package io.legado.app.model.localBook
|
||||
|
||||
import android.net.Uri
|
||||
import android.util.Base64
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.script.SimpleBindings
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.BaseSource
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookChapter
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.exception.TocEmptyException
|
||||
import io.legado.app.help.BookHelp
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||
import io.legado.app.utils.*
|
||||
import splitties.init.appCtx
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStream
|
||||
import java.io.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
/**
|
||||
* 书籍文件导入 目录正文解析
|
||||
* 支持在线文件(txt epub umd 压缩文件需要用户解压) 本地文件
|
||||
*/
|
||||
object LocalBook {
|
||||
|
||||
private val nameAuthorPatterns = arrayOf(
|
||||
@@ -41,6 +46,20 @@ object LocalBook {
|
||||
throw FileNotFoundException("${uri.path} 文件不存在")
|
||||
}
|
||||
|
||||
fun getLastModified(book: Book): Result<Long> {
|
||||
return kotlin.runCatching {
|
||||
val uri = Uri.parse(book.bookUrl)
|
||||
if (uri.isContentScheme()) {
|
||||
return@runCatching DocumentFile.fromSingleUri(appCtx, uri)!!.lastModified()
|
||||
}
|
||||
val file = File(uri.path!!)
|
||||
if (file.exists()) {
|
||||
return@runCatching File(uri.path!!).lastModified()
|
||||
}
|
||||
throw FileNotFoundException("${uri.path} 文件不存在")
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun getChapterList(book: Book): ArrayList<BookChapter> {
|
||||
val chapters = when {
|
||||
@@ -79,6 +98,23 @@ object LocalBook {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载在线的文件并自动导入到阅读(txt umd epub)
|
||||
* 压缩文件请先提示用户解压
|
||||
*/
|
||||
fun importFileOnLine(
|
||||
str: String,
|
||||
fileName: String,
|
||||
source: BaseSource? = null,
|
||||
): Book {
|
||||
return saveBookFile(str, fileName, source).let {
|
||||
importFile(it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入本地文件
|
||||
*/
|
||||
fun importFile(uri: Uri): Book {
|
||||
val bookUrl: String
|
||||
val updateTime: Long
|
||||
@@ -119,7 +155,10 @@ object LocalBook {
|
||||
return book
|
||||
}
|
||||
|
||||
fun analyzeNameAuthor(fileName: String): Pair<String, String> {
|
||||
/**
|
||||
* 从文件分析书籍必要信息(书名 作者等)
|
||||
*/
|
||||
private fun analyzeNameAuthor(fileName: String): Pair<String, String> {
|
||||
val tempFileName = fileName.substringBeforeLast(".")
|
||||
var name: String
|
||||
var author: String
|
||||
@@ -171,4 +210,75 @@ object LocalBook {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载在线的文件
|
||||
*/
|
||||
fun saveBookFile(
|
||||
str: String,
|
||||
fileName: String,
|
||||
source: BaseSource? = null,
|
||||
): Uri {
|
||||
val bytes = when {
|
||||
str.isAbsUrl() -> AnalyzeUrl(str, source = source).getByteArray()
|
||||
str.isDataUrl() -> Base64.decode(str.substringAfter("base64,"), Base64.DEFAULT)
|
||||
else -> throw NoStackTraceException("在线导入书籍支持http/https/DataURL")
|
||||
}
|
||||
return saveBookFile(bytes, fileName)
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析下载文件类书源的下载链接的文件后缀
|
||||
* https://www.example.com/download/{fileName}.{type} 含有文件名和后缀
|
||||
* https://www.example.com/download/?fileid=1234, {type: "txt"} 规则设置
|
||||
*/
|
||||
fun parseFileSuffix(url: String): String {
|
||||
val analyzeUrl = AnalyzeUrl(url)
|
||||
val urlNoOption = analyzeUrl.url
|
||||
val lastPath = urlNoOption.substringAfterLast("/")
|
||||
val fileType = lastPath.substringAfterLast(".")
|
||||
val type = analyzeUrl.type
|
||||
return type ?: fileType
|
||||
}
|
||||
|
||||
private fun saveBookFile(
|
||||
bytes: ByteArray,
|
||||
fileName: String
|
||||
): Uri {
|
||||
val defaultBookTreeUri = AppConfig.defaultBookTreeUri
|
||||
if (defaultBookTreeUri.isNullOrBlank()) throw NoStackTraceException("没有设置书籍保存位置!")
|
||||
val treeUri = Uri.parse(defaultBookTreeUri)
|
||||
return if (treeUri.isContentScheme()) {
|
||||
val treeDoc = DocumentFile.fromTreeUri(appCtx, treeUri)
|
||||
var doc = treeDoc!!.findFile(fileName)
|
||||
if (doc == null) {
|
||||
doc = treeDoc.createFile(FileUtils.getMimeType(fileName), fileName)
|
||||
?: throw SecurityException("Permission Denial")
|
||||
}
|
||||
appCtx.contentResolver.openOutputStream(doc.uri)!!.use { oStream ->
|
||||
oStream.write(bytes)
|
||||
}
|
||||
doc.uri
|
||||
} else {
|
||||
val treeFile = File(treeUri.path!!)
|
||||
val file = treeFile.getFile(fileName)
|
||||
FileOutputStream(file).use { oStream ->
|
||||
oStream.write(bytes)
|
||||
}
|
||||
Uri.fromFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
//文件类书源 合并在线书籍信息 在线 > 本地
|
||||
fun mergeBook(localBook: Book, onLineBook: Book?): Book {
|
||||
onLineBook ?: return localBook
|
||||
localBook.name = onLineBook.name.ifBlank { localBook.name }
|
||||
localBook.author = onLineBook.author.ifBlank { localBook.author }
|
||||
localBook.coverUrl = onLineBook.coverUrl
|
||||
localBook.intro =
|
||||
if (onLineBook.intro.isNullOrBlank()) localBook.intro else onLineBook.intro
|
||||
localBook.save()
|
||||
return localBook
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# 本地书籍解析
|
||||
# 书籍文件导入解析
|
||||
|
||||
* BaseLocalBookParse.kt 本地书籍解析接口
|
||||
* LocalBook.kt 总入口
|
||||
* LocalBook.kt 导入解析总入口
|
||||
* TextFile.kt 解析txt
|
||||
* EpubFile.kt 解析epub
|
||||
* UmdFile.kt 解析umd
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.legado.app.model.webBook
|
||||
|
||||
import android.text.TextUtils
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
@@ -137,14 +139,29 @@ object BookInfo {
|
||||
Debug.log(bookSource.bookSourceUrl, "└${e.localizedMessage}")
|
||||
DebugLog.e("获取封面出错", e)
|
||||
}
|
||||
scope.ensureActive()
|
||||
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
|
||||
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
|
||||
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
|
||||
if (book.tocUrl == baseUrl) {
|
||||
book.tocHtml = body
|
||||
if (book.type != BookType.file) {
|
||||
scope.ensureActive()
|
||||
Debug.log(bookSource.bookSourceUrl, "┌获取目录链接")
|
||||
book.tocUrl = analyzeRule.getString(infoRule.tocUrl, isUrl = true)
|
||||
if (book.tocUrl.isEmpty()) book.tocUrl = baseUrl
|
||||
if (book.tocUrl == baseUrl) {
|
||||
book.tocHtml = body
|
||||
}
|
||||
Debug.log(bookSource.bookSourceUrl, "└${book.tocUrl}")
|
||||
} else {
|
||||
scope.ensureActive()
|
||||
Debug.log(bookSource.bookSourceUrl, "┌获取文件下载链接")
|
||||
book.downloadUrls = analyzeRule.getStringList(infoRule.downloadUrls, isUrl = true)
|
||||
if (book.downloadUrls == null) {
|
||||
Debug.log(bookSource.bookSourceUrl, "└")
|
||||
throw NoStackTraceException("下载链接为空")
|
||||
} else {
|
||||
Debug.log(
|
||||
bookSource.bookSourceUrl,
|
||||
"└" + TextUtils.join(",\n", book.downloadUrls!!)
|
||||
)
|
||||
}
|
||||
}
|
||||
Debug.log(bookSource.bookSourceUrl, "└${book.tocUrl}")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.script.ScriptException
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseService
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.IntentAction
|
||||
import io.legado.app.data.appDb
|
||||
@@ -208,7 +209,9 @@ class CheckSourceService : BaseService() {
|
||||
mBook = WebBook.getBookInfoAwait(this, source, mBook)
|
||||
}
|
||||
//校验目录
|
||||
if (CheckSource.checkCategory) {
|
||||
if (CheckSource.checkCategory &&
|
||||
source.bookSourceType != BookType.file
|
||||
) {
|
||||
val toc = WebBook.getChapterListAwait(this, source, mBook).getOrThrow()
|
||||
val nextChapterUrl = toc.getOrNull(1)?.url ?: toc.first().url
|
||||
//校验正文
|
||||
|
||||
@@ -38,7 +38,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
private val ttsFolderPath: String by lazy {
|
||||
cacheDir.absolutePath + File.separator + "httpTTS" + File.separator
|
||||
}
|
||||
private var speechRate: Int = AppConfig.speechRatePlay
|
||||
private var speechRate: Int = AppConfig.speechRatePlay + 5
|
||||
private var downloadTask: Coroutine<*>? = null
|
||||
private var playIndexJob: Job? = null
|
||||
private var downloadTaskIsActive = false
|
||||
@@ -301,7 +301,7 @@ class HttpReadAloudService : BaseReadAloudService(),
|
||||
override fun upSpeechRate(reset: Boolean) {
|
||||
downloadTask?.cancel()
|
||||
exoPlayer.stop()
|
||||
speechRate = AppConfig.speechRatePlay
|
||||
speechRate = AppConfig.speechRatePlay + 5
|
||||
downloadAudio()
|
||||
}
|
||||
|
||||
|
||||
@@ -2,16 +2,7 @@ package io.legado.app.ui.association
|
||||
|
||||
import android.app.Application
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.TxtTocRule
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.fromJsonArray
|
||||
import io.legado.app.utils.fromJsonObject
|
||||
import io.legado.app.utils.isJsonArray
|
||||
|
||||
abstract class BaseAssociationViewModel(application: Application) : BaseViewModel(application) {
|
||||
|
||||
@@ -37,47 +28,4 @@ abstract class BaseAssociationViewModel(application: Application) : BaseViewMode
|
||||
}
|
||||
}
|
||||
|
||||
fun importTextTocRule(json: String, finally: (title: String, msg: String) -> Unit) {
|
||||
execute {
|
||||
if (json.isJsonArray()) {
|
||||
GSON.fromJsonArray<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(*it.toTypedArray())
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
} else {
|
||||
GSON.fromJsonObject<TxtTocRule>(json).getOrThrow()?.let {
|
||||
appDb.txtTocRuleDao.insert(it)
|
||||
} ?: throw NoStackTraceException("格式不对")
|
||||
}
|
||||
}.onSuccess {
|
||||
finally.invoke(context.getString(R.string.success), "导入Txt规则成功")
|
||||
}.onError {
|
||||
finally.invoke(
|
||||
context.getString(R.string.error),
|
||||
it.localizedMessage ?: context.getString(R.string.unknown_error)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun importTheme(json: String, finally: (title: String, msg: String) -> Unit) {
|
||||
execute {
|
||||
if (json.isJsonArray()) {
|
||||
GSON.fromJsonArray<ThemeConfig.Config>(json).getOrThrow()?.forEach {
|
||||
ThemeConfig.addConfig(it)
|
||||
}
|
||||
} else {
|
||||
GSON.fromJsonObject<ThemeConfig.Config>(json).getOrThrow()?.let {
|
||||
ThemeConfig.addConfig(it)
|
||||
}
|
||||
}
|
||||
}.onSuccess {
|
||||
finally.invoke(context.getString(R.string.success), "导入主题成功")
|
||||
}.onError {
|
||||
finally.invoke(
|
||||
context.getString(R.string.error),
|
||||
it.localizedMessage ?: context.getString(R.string.unknown_error)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -61,21 +61,7 @@ class ImportHttpTtsViewModel(app: Application) : BaseViewModel(app) {
|
||||
|
||||
fun importSource(text: String) {
|
||||
execute {
|
||||
val mText = text.trim()
|
||||
when {
|
||||
mText.isJsonObject() -> {
|
||||
HttpTTS.fromJson(mText).getOrThrow().let {
|
||||
allSources.add(it)
|
||||
}
|
||||
}
|
||||
mText.isJsonArray() -> HttpTTS.fromJsonArray(mText).getOrThrow().let { items ->
|
||||
allSources.addAll(items)
|
||||
}
|
||||
mText.isAbsUrl() -> {
|
||||
importSourceUrl(mText)
|
||||
}
|
||||
else -> throw NoStackTraceException(context.getString(R.string.wrong_format))
|
||||
}
|
||||
importSourceAwait(text.trim())
|
||||
}.onError {
|
||||
it.printOnDebug()
|
||||
errorLiveData.postValue(it.localizedMessage ?: "")
|
||||
@@ -84,11 +70,28 @@ class ImportHttpTtsViewModel(app: Application) : BaseViewModel(app) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun importSourceAwait(text: String) {
|
||||
when {
|
||||
text.isJsonObject() -> {
|
||||
HttpTTS.fromJson(text).getOrThrow().let {
|
||||
allSources.add(it)
|
||||
}
|
||||
}
|
||||
text.isJsonArray() -> HttpTTS.fromJsonArray(text).getOrThrow().let { items ->
|
||||
allSources.addAll(items)
|
||||
}
|
||||
text.isAbsUrl() -> {
|
||||
importSourceUrl(text)
|
||||
}
|
||||
else -> throw NoStackTraceException(context.getString(R.string.wrong_format))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun importSourceUrl(url: String) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
}.text().let {
|
||||
allSources.addAll(HttpTTS.fromJsonArray(it).getOrThrow())
|
||||
importSourceAwait(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package io.legado.app.ui.association
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.net.Uri
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseDialogFragment
|
||||
import io.legado.app.base.adapter.ItemViewHolder
|
||||
import io.legado.app.base.adapter.RecyclerAdapter
|
||||
import io.legado.app.databinding.DialogRecyclerViewBinding
|
||||
import io.legado.app.databinding.ItemBookFileImportBinding
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.widget.dialog.WaitDialog
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
|
||||
|
||||
/**
|
||||
* 导入在线书籍文件弹出窗口
|
||||
*/
|
||||
class ImportOnLineBookFileDialog() : BaseDialogFragment(R.layout.dialog_recycler_view) {
|
||||
|
||||
|
||||
private val binding by viewBinding(DialogRecyclerViewBinding::bind)
|
||||
private val viewModel by viewModels<ImportOnLineBookFileViewModel>()
|
||||
private val adapter by lazy { BookFileAdapter(requireContext()) }
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
}
|
||||
|
||||
override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val bookUrl = arguments?.getString("bookUrl")
|
||||
viewModel.initData(bookUrl)
|
||||
binding.toolBar.setBackgroundColor(primaryColor)
|
||||
binding.toolBar.setTitle(R.string.download_and_import_file)
|
||||
binding.rotateLoading.show()
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.recyclerView.adapter = adapter
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
visible()
|
||||
}
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allBookFiles)
|
||||
}
|
||||
}
|
||||
viewModel.savedFileUriData.observe(this) {
|
||||
requireContext().openFileUri(it, "*/*")
|
||||
}
|
||||
}
|
||||
|
||||
private fun importFileAndUpdate(url: String, fileName: String) {
|
||||
val waitDialog = WaitDialog(requireContext())
|
||||
waitDialog.show()
|
||||
viewModel.importOnLineBookFile(url, fileName) {
|
||||
waitDialog.dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun downloadFile(url: String, fileName: String) {
|
||||
val waitDialog = WaitDialog(requireContext())
|
||||
waitDialog.show()
|
||||
viewModel.downloadUrl(url, fileName) {
|
||||
waitDialog.dismiss()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
inner class BookFileAdapter(context: Context) :
|
||||
RecyclerAdapter<Triple<String, String, Boolean>
|
||||
, ItemBookFileImportBinding>(context) {
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemBookFileImportBinding {
|
||||
return ItemBookFileImportBinding.inflate(inflater, parent, false)
|
||||
}
|
||||
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemBookFileImportBinding,
|
||||
item: Triple<String, String, Boolean>,
|
||||
payloads: MutableList<Any>
|
||||
) {
|
||||
binding.apply {
|
||||
cbFileName.text = item.second
|
||||
}
|
||||
}
|
||||
|
||||
override fun registerListener(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemBookFileImportBinding
|
||||
) {
|
||||
binding.apply {
|
||||
cbFileName.setOnClickListener {
|
||||
val selectFile = viewModel.allBookFiles[holder.layoutPosition]
|
||||
if (selectFile.third) {
|
||||
importFileAndUpdate(selectFile.first, selectFile.second)
|
||||
} else {
|
||||
alert(
|
||||
title = getString(R.string.draw),
|
||||
message = getString(R.string.file_not_supported, selectFile.second)
|
||||
) {
|
||||
okButton {
|
||||
importFileAndUpdate(selectFile.first, selectFile.second)
|
||||
}
|
||||
neutralButton(R.string.open_fun) {
|
||||
downloadFile(selectFile.first, selectFile.second)
|
||||
}
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.legado.app.ui.association
|
||||
|
||||
import android.app.Application
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Book
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.model.analyzeRule.AnalyzeRule
|
||||
import io.legado.app.model.analyzeRule.AnalyzeUrl
|
||||
import io.legado.app.model.localBook.LocalBook
|
||||
import io.legado.app.utils.*
|
||||
|
||||
class ImportOnLineBookFileViewModel(app: Application) : BaseViewModel(app) {
|
||||
|
||||
val allBookFiles = arrayListOf<Triple<String, String, Boolean>>()
|
||||
val errorLiveData = MutableLiveData<String>()
|
||||
val successLiveData = MutableLiveData<Int>()
|
||||
val savedFileUriData = MutableLiveData<Uri>()
|
||||
var bookSource: BookSource? = null
|
||||
|
||||
fun initData(bookUrl: String?) {
|
||||
execute {
|
||||
bookUrl ?: throw NoStackTraceException("书籍详情页链接为空")
|
||||
val book = appDb.searchBookDao.getSearchBook(bookUrl)?.toBook()
|
||||
?: throw NoStackTraceException("book is null")
|
||||
bookSource = appDb.bookSourceDao.getBookSource(book.origin)
|
||||
?: throw NoStackTraceException("bookSource is null")
|
||||
val ruleDownloadUrls = bookSource?.getBookInfoRule()?.downloadUrls
|
||||
val content = AnalyzeUrl(bookUrl, source = bookSource).getStrResponse().body
|
||||
val analyzeRule = AnalyzeRule(book, bookSource)
|
||||
analyzeRule.setContent(content).setBaseUrl(bookUrl)
|
||||
val fileName = "${book.name} 作者:${book.author}"
|
||||
analyzeRule.getStringList(ruleDownloadUrls, isUrl = true)?.let {
|
||||
it.forEach { url ->
|
||||
val mFileName = "${fileName}.${LocalBook.parseFileSuffix(url)}"
|
||||
val isSupportedFile = AppPattern.bookFileRegex.matches(mFileName)
|
||||
allBookFiles.add(Triple(url, mFileName, isSupportedFile))
|
||||
}
|
||||
} ?: throw NoStackTraceException("下载链接规则解析为空")
|
||||
}.onSuccess {
|
||||
successLiveData.postValue(allBookFiles.size)
|
||||
}.onError {
|
||||
errorLiveData.postValue(it.localizedMessage ?: "")
|
||||
context.toastOnUi("获取书籍下载链接失败\n${it.localizedMessage}")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun downloadUrl(url: String, fileName: String, success: () -> Unit) {
|
||||
execute {
|
||||
LocalBook.saveBookFile(url, fileName, bookSource).let {
|
||||
savedFileUriData.postValue(it)
|
||||
}
|
||||
}.onSuccess {
|
||||
success.invoke()
|
||||
}.onError {
|
||||
context.toastOnUi("下载书籍文件失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
fun importOnLineBookFile(url: String, fileName: String, success: () -> Unit) {
|
||||
execute {
|
||||
LocalBook.importFileOnLine(url, fileName, bookSource).let {
|
||||
postEvent(EventBus.BOOK_URL_CHANGED, it.bookUrl)
|
||||
}
|
||||
}.onSuccess {
|
||||
success.invoke()
|
||||
}.onError {
|
||||
context.toastOnUi("下载书籍文件失败\n${it.localizedMessage}")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -88,14 +88,14 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi
|
||||
adapter.notifyDataSetChanged()
|
||||
upSelectText()
|
||||
}
|
||||
viewModel.errorLiveData.observe(this, {
|
||||
viewModel.errorLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
binding.tvMsg.apply {
|
||||
text = it
|
||||
visible()
|
||||
}
|
||||
})
|
||||
viewModel.successLiveData.observe(this, {
|
||||
}
|
||||
viewModel.successLiveData.observe(this) {
|
||||
binding.rotateLoading.hide()
|
||||
if (it > 0) {
|
||||
adapter.setItems(viewModel.allRules)
|
||||
@@ -106,7 +106,7 @@ class ImportReplaceRuleDialog() : BaseDialogFragment(R.layout.dialog_recycler_vi
|
||||
visible()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
val source = arguments?.getString("source")
|
||||
if (source.isNullOrEmpty()) {
|
||||
dismiss()
|
||||
|
||||
@@ -6,12 +6,15 @@ import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppPattern
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.ReplaceRule
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.ReplaceAnalyzer
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.http.newCallResponseBody
|
||||
import io.legado.app.help.http.okHttpClient
|
||||
import io.legado.app.help.http.text
|
||||
import io.legado.app.utils.isAbsUrl
|
||||
import io.legado.app.utils.isJsonArray
|
||||
import io.legado.app.utils.isJsonObject
|
||||
import io.legado.app.utils.splitNotBlank
|
||||
|
||||
class ImportReplaceRuleViewModel(app: Application) : BaseViewModel(app) {
|
||||
@@ -83,17 +86,7 @@ class ImportReplaceRuleViewModel(app: Application) : BaseViewModel(app) {
|
||||
|
||||
fun import(text: String) {
|
||||
execute {
|
||||
if (text.isAbsUrl()) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(text)
|
||||
}.text("utf-8").let {
|
||||
val rules = ReplaceAnalyzer.jsonToReplaceRules(it)
|
||||
allRules.addAll(rules)
|
||||
}
|
||||
} else {
|
||||
val rules = ReplaceAnalyzer.jsonToReplaceRules(text)
|
||||
allRules.addAll(rules)
|
||||
}
|
||||
importAwait(text.trim())
|
||||
}.onError {
|
||||
errorLiveData.postValue(it.localizedMessage ?: "ERROR")
|
||||
}.onSuccess {
|
||||
@@ -101,6 +94,29 @@ class ImportReplaceRuleViewModel(app: Application) : BaseViewModel(app) {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun importAwait(text: String) {
|
||||
when {
|
||||
text.isAbsUrl() -> importUrl(text)
|
||||
text.isJsonArray() -> {
|
||||
val rules = ReplaceAnalyzer.jsonToReplaceRules(text).getOrThrow()
|
||||
allRules.addAll(rules)
|
||||
}
|
||||
text.isJsonObject() -> {
|
||||
val rule = ReplaceAnalyzer.jsonToReplaceRule(text).getOrThrow()
|
||||
allRules.add(rule)
|
||||
}
|
||||
else -> throw NoStackTraceException("格式不对")
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun importUrl(url: String) {
|
||||
okHttpClient.newCallResponseBody {
|
||||
url(url)
|
||||
}.text("utf-8").let {
|
||||
importAwait(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun comparisonSource() {
|
||||
execute {
|
||||
allRules.forEach {
|
||||
|
||||
@@ -13,6 +13,7 @@ import androidx.activity.viewModels
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.VMBaseActivity
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.Theme
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Book
|
||||
@@ -26,6 +27,7 @@ import io.legado.app.lib.theme.bottomBackground
|
||||
import io.legado.app.lib.theme.getPrimaryTextColor
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.ui.about.AppLogDialog
|
||||
import io.legado.app.ui.association.ImportOnLineBookFileDialog
|
||||
import io.legado.app.ui.book.audio.AudioPlayActivity
|
||||
import io.legado.app.ui.book.changecover.ChangeCoverDialog
|
||||
import io.legado.app.ui.book.changesource.ChangeBookSourceDialog
|
||||
@@ -245,7 +247,7 @@ class BookInfoActivity :
|
||||
binding.tvToc.text = getString(R.string.toc_s, getString(R.string.loading))
|
||||
}
|
||||
chapterList.isNullOrEmpty() -> {
|
||||
binding.tvToc.text = getString(R.string.toc_s, getString(R.string.error_load_toc))
|
||||
binding.tvToc.text = if (viewModel.isImportBookOnLine) getString(R.string.click_read_button_load) else getString(R.string.toc_s, getString(R.string.error_load_toc))
|
||||
}
|
||||
else -> {
|
||||
viewModel.bookData.value?.let {
|
||||
@@ -293,8 +295,14 @@ class BookInfoActivity :
|
||||
true
|
||||
}
|
||||
tvRead.setOnClickListener {
|
||||
viewModel.bookData.value?.let {
|
||||
readBook(it)
|
||||
viewModel.bookData.value?.let { book ->
|
||||
if (viewModel.isImportBookOnLine) {
|
||||
showDialogFragment<ImportOnLineBookFileDialog> {
|
||||
putString("bookUrl", book.bookUrl)
|
||||
}
|
||||
} else {
|
||||
readBook(book)
|
||||
}
|
||||
} ?: toastOnUi("Book is null")
|
||||
}
|
||||
tvShelf.setOnClickListener {
|
||||
@@ -497,4 +505,9 @@ class BookInfoActivity :
|
||||
}
|
||||
}
|
||||
|
||||
override fun observeLiveBus() {
|
||||
observeEvent<String>(EventBus.BOOK_URL_CHANGED) {
|
||||
viewModel.changeToLocalBook(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,13 @@ package io.legado.app.ui.book.info
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.BookType
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.Book
|
||||
@@ -30,6 +32,7 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
var inBookshelf = false
|
||||
var bookSource: BookSource? = null
|
||||
private var changeSourceCoroutine: Coroutine<*>? = null
|
||||
var isImportBookOnLine = false
|
||||
|
||||
fun initData(intent: Intent) {
|
||||
execute {
|
||||
@@ -73,8 +76,11 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
upCoverByRule(book)
|
||||
bookSource = if (book.isLocalBook()) null else
|
||||
appDb.bookSourceDao.getBookSource(book.origin)
|
||||
isImportBookOnLine = (bookSource?.bookSourceType ?: BookType.local) == BookType.file
|
||||
if (book.tocUrl.isEmpty()) {
|
||||
loadBookInfo(book)
|
||||
} else if (isImportBookOnLine) {
|
||||
chapterListData.postValue(emptyList())
|
||||
} else {
|
||||
val chapterList = appDb.bookChapterDao.getChapterList(book.bookUrl)
|
||||
if (chapterList.isNotEmpty()) {
|
||||
@@ -113,6 +119,9 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
WebBook.getBookInfo(this, bookSource, book, canReName = canReName)
|
||||
.onSuccess(IO) {
|
||||
bookData.postValue(book)
|
||||
if (isImportBookOnLine) {
|
||||
appDb.searchBookDao.update(book.toSearchBook())
|
||||
}
|
||||
if (inBookshelf) {
|
||||
appDb.bookDao.update(book)
|
||||
}
|
||||
@@ -141,6 +150,8 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
appDb.bookChapterDao.insert(*it.toTypedArray())
|
||||
chapterListData.postValue(it)
|
||||
}
|
||||
} else if (isImportBookOnLine) {
|
||||
chapterListData.postValue(emptyList())
|
||||
} else {
|
||||
bookSource?.let { bookSource ->
|
||||
WebBook.getChapterList(this, bookSource, book)
|
||||
@@ -282,4 +293,16 @@ class BookInfoViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun changeToLocalBook(bookUrl: String) {
|
||||
appDb.bookDao.getBook(bookUrl)?.let { localBook ->
|
||||
isImportBookOnLine = false
|
||||
inBookshelf = true
|
||||
LocalBook.mergeBook(localBook, bookData.value).let {
|
||||
bookData.postValue(it)
|
||||
loadChapter(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -229,8 +229,12 @@ abstract class BaseReadBookActivity :
|
||||
customView { alertBinding.root }
|
||||
yesButton {
|
||||
alertBinding.run {
|
||||
val start = editStart.text?.toString()?.toInt() ?: 0
|
||||
val end = editEnd.text?.toString()?.toInt() ?: book.totalChapterNum
|
||||
val start = editStart.text!!.toString().let {
|
||||
if (it.isEmpty()) 0 else it.toInt()
|
||||
}
|
||||
val end = editEnd.text!!.toString().let {
|
||||
if (it.isEmpty()) book.totalChapterNum else it.toInt()
|
||||
}
|
||||
CacheBook.start(this@BaseReadBookActivity, book, start - 1, end - 1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,41 +61,33 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
||||
}
|
||||
|
||||
private fun initBook(book: Book) {
|
||||
if (ReadBook.book?.bookUrl != book.bookUrl) {
|
||||
ReadBook.resetData(book)
|
||||
isInitFinish = true
|
||||
if (ReadBook.chapterSize == 0) {
|
||||
if (book.tocUrl.isEmpty()) {
|
||||
loadBookInfo(book)
|
||||
} else {
|
||||
loadChapterList(book)
|
||||
}
|
||||
val isSameBook = ReadBook.book?.bookUrl == book.bookUrl
|
||||
if (isSameBook) ReadBook.upData(book) else ReadBook.resetData(book)
|
||||
isInitFinish = true
|
||||
if (ReadBook.chapterSize == 0) {
|
||||
if (book.tocUrl.isEmpty()) {
|
||||
loadBookInfo(book)
|
||||
} else {
|
||||
loadChapterList(book)
|
||||
}
|
||||
} else if (book.isLocalBook()
|
||||
&& LocalBook.getLastModified(book).getOrDefault(0L) > book.latestChapterTime
|
||||
) {
|
||||
loadChapterList(book)
|
||||
} else if (isSameBook) {
|
||||
if (ReadBook.curTextChapter != null) {
|
||||
ReadBook.callBack?.upContent(resetPageOffset = false)
|
||||
} else {
|
||||
if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
|
||||
ReadBook.durChapterIndex = ReadBook.chapterSize - 1
|
||||
}
|
||||
ReadBook.loadContent(resetPageOffset = true)
|
||||
}
|
||||
syncBookProgress(book)
|
||||
} else {
|
||||
ReadBook.upData(book)
|
||||
isInitFinish = true
|
||||
if (ReadBook.chapterSize == 0) {
|
||||
if (book.tocUrl.isEmpty()) {
|
||||
loadBookInfo(book)
|
||||
} else {
|
||||
loadChapterList(book)
|
||||
}
|
||||
} else {
|
||||
if (ReadBook.curTextChapter != null) {
|
||||
ReadBook.callBack?.upContent(resetPageOffset = false)
|
||||
} else {
|
||||
ReadBook.loadContent(resetPageOffset = true)
|
||||
}
|
||||
}
|
||||
if (!BaseReadAloudService.isRun) {
|
||||
syncBookProgress(book)
|
||||
if (ReadBook.durChapterIndex > ReadBook.chapterSize - 1) {
|
||||
ReadBook.durChapterIndex = ReadBook.chapterSize - 1
|
||||
}
|
||||
ReadBook.loadContent(resetPageOffset = isSameBook)
|
||||
}
|
||||
if (!isSameBook || !BaseReadAloudService.isRun) {
|
||||
syncBookProgress(book)
|
||||
}
|
||||
if (!book.isLocalBook() && ReadBook.bookSource == null) {
|
||||
autoChangeSource(book.name, book.author)
|
||||
|
||||
@@ -9,10 +9,10 @@ import android.widget.LinearLayout
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.config.ReadBookConfig
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.bottomBackground
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.ReadBook
|
||||
@@ -67,7 +67,7 @@ class MoreConfigDialog : DialogFragment() {
|
||||
(activity as ReadBookActivity).bottomDialog--
|
||||
}
|
||||
|
||||
class ReadPreferenceFragment : BasePreferenceFragment(),
|
||||
class ReadPreferenceFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
|
||||
@@ -10,12 +10,12 @@ import androidx.fragment.app.DialogFragment
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.help.IntentHelp
|
||||
import io.legado.app.lib.dialogs.SelectItem
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.backgroundColor
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.ReadAloud
|
||||
@@ -54,7 +54,7 @@ class ReadAloudConfigDialog : DialogFragment() {
|
||||
.commit()
|
||||
}
|
||||
|
||||
class ReadAloudPreferenceFragment : BasePreferenceFragment(),
|
||||
class ReadAloudPreferenceFragment : PreferenceFragment(),
|
||||
SpeakEngineDialog.CallBack,
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.legado.app.databinding.ActivityBookSourceEditBinding
|
||||
import io.legado.app.help.config.LocalConfig
|
||||
import io.legado.app.lib.dialogs.SelectItem
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.lib.theme.backgroundColor
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.book.source.debug.BookSourceDebugActivity
|
||||
@@ -47,7 +48,7 @@ class BookSourceEditActivity :
|
||||
private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
|
||||
it ?: return@registerForActivityResult
|
||||
viewModel.importSource(it) { source ->
|
||||
upRecyclerView(source)
|
||||
upSourceView(source)
|
||||
}
|
||||
}
|
||||
private val selectDoc = registerForActivityResult(HandleFileContract()) {
|
||||
@@ -68,7 +69,7 @@ class BookSourceEditActivity :
|
||||
softKeyboardTool.attachToWindow(window)
|
||||
initView()
|
||||
viewModel.initData(intent) {
|
||||
upRecyclerView()
|
||||
upSourceView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,9 +110,10 @@ class BookSourceEditActivity :
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.menu_clear_cookie -> viewModel.clearCookie(getSource().bookSourceUrl)
|
||||
R.id.menu_auto_complete -> viewModel.autoComplete = !viewModel.autoComplete
|
||||
R.id.menu_copy_source -> sendToClip(GSON.toJson(getSource()))
|
||||
R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) }
|
||||
R.id.menu_paste_source -> viewModel.pasteSource { upSourceView(it) }
|
||||
R.id.menu_qr_code_camera -> qrCodeResult.launch()
|
||||
R.id.menu_share_str -> share(GSON.toJson(getSource()))
|
||||
R.id.menu_share_qr -> shareWithQr(
|
||||
@@ -139,6 +141,7 @@ class BookSourceEditActivity :
|
||||
binding.recyclerView.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.tabLayout.setBackgroundColor(backgroundColor)
|
||||
binding.tabLayout.setSelectedTabIndicatorColor(accentColor)
|
||||
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
|
||||
override fun onTabReselected(tab: TabLayout.Tab?) {
|
||||
|
||||
@@ -186,12 +189,14 @@ class BookSourceEditActivity :
|
||||
binding.recyclerView.scrollToPosition(0)
|
||||
}
|
||||
|
||||
private fun upRecyclerView(source: BookSource? = viewModel.bookSource) {
|
||||
private fun upSourceView(source: BookSource? = viewModel.bookSource) {
|
||||
source?.let {
|
||||
binding.cbIsEnable.isChecked = it.enabled
|
||||
binding.cbIsEnableFind.isChecked = it.enabledExplore
|
||||
binding.cbIsEnableCookie.isChecked = it.enabledCookieJar ?: false
|
||||
binding.spType.setSelection(
|
||||
when (it.bookSourceType) {
|
||||
BookType.file -> 3
|
||||
BookType.image -> 2
|
||||
BookType.audio -> 1
|
||||
else -> 0
|
||||
@@ -261,6 +266,7 @@ class BookSourceEditActivity :
|
||||
add(EditEntity("coverUrl", ir?.coverUrl, R.string.rule_cover_url))
|
||||
add(EditEntity("tocUrl", ir?.tocUrl, R.string.rule_toc_url))
|
||||
add(EditEntity("canReName", ir?.canReName, R.string.rule_can_re_name))
|
||||
add(EditEntity("downloadUrls", ir?.downloadUrls, R.string.download_url_rule))
|
||||
}
|
||||
//目录页
|
||||
val tr = source?.getTocRule()
|
||||
@@ -295,7 +301,9 @@ class BookSourceEditActivity :
|
||||
val source = viewModel.bookSource?.copy() ?: BookSource()
|
||||
source.enabled = binding.cbIsEnable.isChecked
|
||||
source.enabledExplore = binding.cbIsEnableFind.isChecked
|
||||
source.enabledCookieJar = binding.cbIsEnableCookie.isChecked
|
||||
source.bookSourceType = when (binding.spType.selectedItemPosition) {
|
||||
3 -> BookType.file
|
||||
2 -> BookType.image
|
||||
1 -> BookType.audio
|
||||
else -> BookType.default
|
||||
@@ -389,6 +397,7 @@ class BookSourceEditActivity :
|
||||
"tocUrl" -> bookInfoRule.tocUrl =
|
||||
viewModel.ruleComplete(it.value, bookInfoRule.init, 2)
|
||||
"canReName" -> bookInfoRule.canReName = it.value
|
||||
"downloadUrls" -> bookInfoRule.downloadUrls = viewModel.ruleComplete(it.value, bookInfoRule.init)
|
||||
}
|
||||
}
|
||||
tocEntities.forEach {
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.BookSource
|
||||
import io.legado.app.exception.NoStackTraceException
|
||||
import io.legado.app.help.RuleComplete
|
||||
import io.legado.app.help.http.CookieStore
|
||||
import io.legado.app.help.http.newCallStrResponse
|
||||
import io.legado.app.help.http.okHttpClient
|
||||
import io.legado.app.utils.*
|
||||
@@ -95,6 +96,12 @@ class BookSourceEditViewModel(application: Application) : BaseViewModel(applicat
|
||||
}
|
||||
}
|
||||
|
||||
fun clearCookie(url: String) {
|
||||
execute {
|
||||
CookieStore.removeCookie(url)
|
||||
}
|
||||
}
|
||||
|
||||
fun ruleComplete(rule: String?, preRule: String? = null, type: Int = 1): String? {
|
||||
if (autoComplete) {
|
||||
return RuleComplete.autoComplete(rule, preRule, type)
|
||||
|
||||
@@ -19,8 +19,10 @@ import io.legado.app.utils.gone
|
||||
import io.legado.app.utils.longToastOnUi
|
||||
import io.legado.app.utils.visible
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
@@ -54,17 +56,10 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
|
||||
}
|
||||
|
||||
private val replaceRules
|
||||
get() = callback.book?.let {
|
||||
ContentProcessor.get(it.name, it.origin).getTitleReplaceRules()
|
||||
}
|
||||
private val useReplace
|
||||
get() = AppConfig.tocUiUseReplace && callback.book?.getUseReplaceRule() == true
|
||||
private var upDisplayTileJob: Coroutine<*>? = null
|
||||
|
||||
override fun onCurrentListChanged() {
|
||||
super.onCurrentListChanged()
|
||||
upDisplayTitle()
|
||||
callback.onListChanged()
|
||||
}
|
||||
|
||||
@@ -73,38 +68,52 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
displayTitleMap.clear()
|
||||
}
|
||||
|
||||
fun upDisplayTitle() {
|
||||
fun upDisplayTitles(startIndex: Int) {
|
||||
upDisplayTileJob?.cancel()
|
||||
upDisplayTileJob = Coroutine.async(callback.scope) {
|
||||
val replaceRules = replaceRules
|
||||
val useReplace = useReplace
|
||||
getItems().forEach {
|
||||
if (!isActive) {
|
||||
return@async
|
||||
val book = callback.book ?: return@async
|
||||
val replaceRules = ContentProcessor.get(book.name, book.origin).getTitleReplaceRules()
|
||||
val useReplace = AppConfig.tocUiUseReplace && book.getUseReplaceRule()
|
||||
val items = getItems()
|
||||
async {
|
||||
for (i in startIndex until items.size) {
|
||||
val item = items[i]
|
||||
if (displayTitleMap[item.title] == null) {
|
||||
ensureActive()
|
||||
val displayTitle = item.getDisplayTitle(replaceRules, useReplace)
|
||||
ensureActive()
|
||||
displayTitleMap[item.title] = displayTitle
|
||||
withContext(Main) {
|
||||
notifyItemChanged(i, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (displayTitleMap[it.title] == null) {
|
||||
displayTitleMap[it.title] = it.getDisplayTitle(replaceRules, useReplace)
|
||||
}.start()
|
||||
async {
|
||||
for (i in startIndex downTo 0) {
|
||||
val item = items[i]
|
||||
if (displayTitleMap[item.title] == null) {
|
||||
ensureActive()
|
||||
val displayTitle = item.getDisplayTitle(replaceRules, useReplace)
|
||||
ensureActive()
|
||||
displayTitleMap[item.title] = displayTitle
|
||||
withContext(Main) {
|
||||
notifyItemChanged(i, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDisplayTitle(chapter: BookChapter): String {
|
||||
return displayTitleMap[chapter.title] ?: chapter.title
|
||||
}
|
||||
|
||||
override fun getViewBinding(parent: ViewGroup): ItemChapterListBinding {
|
||||
return ItemChapterListBinding.inflate(inflater, parent, false)
|
||||
}
|
||||
|
||||
private fun getDisplayTile(chapter: BookChapter): String {
|
||||
var displayTitle = displayTitleMap[chapter.title]
|
||||
if (displayTitle != null) {
|
||||
return displayTitle
|
||||
}
|
||||
displayTitle = runBlocking {
|
||||
chapter.getDisplayTitle(replaceRules, useReplace)
|
||||
}
|
||||
displayTitleMap[chapter.title] = displayTitle
|
||||
return displayTitle
|
||||
}
|
||||
|
||||
override fun convert(
|
||||
holder: ItemViewHolder,
|
||||
binding: ItemChapterListBinding,
|
||||
@@ -120,7 +129,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
} else {
|
||||
tvChapterName.setTextColor(context.getCompatColor(R.color.primaryText))
|
||||
}
|
||||
tvChapterName.text = getDisplayTile(item)
|
||||
tvChapterName.text = getDisplayTitle(item)
|
||||
if (item.isVolume) {
|
||||
//卷名,如第一卷 突出显示
|
||||
tvChapterItem.setBackgroundColor(context.getCompatColor(R.color.btn_bg_press))
|
||||
@@ -138,6 +147,7 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
}
|
||||
upHasCache(binding, isDur, cached)
|
||||
} else {
|
||||
tvChapterName.text = getDisplayTitle(item)
|
||||
upHasCache(binding, isDur, cached)
|
||||
}
|
||||
}
|
||||
@@ -150,8 +160,8 @@ class ChapterListAdapter(context: Context, val callback: Callback) :
|
||||
}
|
||||
}
|
||||
holder.itemView.setOnLongClickListener {
|
||||
getItem(holder.layoutPosition)?.let {
|
||||
context.longToastOnUi(getDisplayTile(it))
|
||||
getItem(holder.layoutPosition)?.let { item ->
|
||||
context.longToastOnUi(getDisplayTitle(item))
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
@@ -97,7 +97,15 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
|
||||
viewModel.bookData.value?.bookUrl?.let { bookUrl ->
|
||||
if (chapter.bookUrl == bookUrl) {
|
||||
adapter.cacheFileNames.add(chapter.getFileName())
|
||||
adapter.notifyItemChanged(chapter.index, true)
|
||||
if (viewModel.searchKey.isNullOrEmpty()) {
|
||||
adapter.notifyItemChanged(chapter.index, true)
|
||||
} else {
|
||||
adapter.getItems().forEachIndexed { index, bookChapter ->
|
||||
if (bookChapter.index == chapter.index) {
|
||||
adapter.notifyItemChanged(index, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,12 +136,13 @@ class ChapterListFragment : VMBaseFragment<TocViewModel>(R.layout.fragment_chapt
|
||||
}
|
||||
}
|
||||
mLayoutManager.scrollToPositionWithOffset(scrollPos, 0)
|
||||
adapter.upDisplayTitles(scrollPos)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearDisplayTitle() {
|
||||
adapter.clearDisplayTitle()
|
||||
adapter.upDisplayTitle()
|
||||
adapter.upDisplayTitles(mLayoutManager.findFirstVisibleItemPosition())
|
||||
}
|
||||
|
||||
override val scope: CoroutineScope
|
||||
|
||||
@@ -59,10 +59,12 @@ class TocActivity : VMBaseActivity<ActivityChapterListBinding, TocViewModel>() {
|
||||
setOnSearchClickListener { tabLayout.gone() }
|
||||
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
|
||||
override fun onQueryTextSubmit(query: String): Boolean {
|
||||
viewModel.searchKey = query
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onQueryTextChange(newText: String): Boolean {
|
||||
viewModel.searchKey = newText
|
||||
if (tabLayout.selectedTabPosition == 1) {
|
||||
viewModel.startBookmarkSearch(newText)
|
||||
} else {
|
||||
|
||||
@@ -12,6 +12,7 @@ class TocViewModel(application: Application) : BaseViewModel(application) {
|
||||
var bookData = MutableLiveData<Book>()
|
||||
var chapterListCallBack: ChapterListCallBack? = null
|
||||
var bookMarkCallBack: BookmarkCallBack? = null
|
||||
var searchKey: String? = null
|
||||
|
||||
fun initBook(bookUrl: String) {
|
||||
this.bookUrl = bookUrl
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.AppLog
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.help.config.AppConfig
|
||||
@@ -25,7 +24,7 @@ import io.legado.app.help.storage.*
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.permission.Permissions
|
||||
import io.legado.app.lib.permission.PermissionsCompat
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.document.HandleFileContract
|
||||
import io.legado.app.ui.widget.dialog.TextDialog
|
||||
@@ -33,8 +32,9 @@ import io.legado.app.utils.*
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.launch
|
||||
import splitties.init.appCtx
|
||||
import kotlin.collections.set
|
||||
|
||||
class BackupConfigFragment : BasePreferenceFragment(),
|
||||
class BackupConfigFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val viewModel by activityViewModels<ConfigViewModel>()
|
||||
@@ -100,34 +100,18 @@ class BackupConfigFragment : BasePreferenceFragment(),
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_config_backup)
|
||||
findPreference<EditTextPreference>(PreferKey.webDavUrl)?.let {
|
||||
it.setOnBindEditTextListener { editText ->
|
||||
editText.applyTint(requireContext().accentColor)
|
||||
}
|
||||
}
|
||||
findPreference<EditTextPreference>(PreferKey.webDavAccount)?.let {
|
||||
it.setOnBindEditTextListener { editText ->
|
||||
editText.applyTint(requireContext().accentColor)
|
||||
}
|
||||
}
|
||||
findPreference<EditTextPreference>(PreferKey.webDavPassword)?.let {
|
||||
it.setOnBindEditTextListener { editText ->
|
||||
editText.applyTint(requireContext().accentColor)
|
||||
editText.inputType =
|
||||
InputType.TYPE_TEXT_VARIATION_PASSWORD or InputType.TYPE_CLASS_TEXT
|
||||
}
|
||||
}
|
||||
findPreference<EditTextPreference>(PreferKey.webDavDir)?.let {
|
||||
it.setOnBindEditTextListener { editText ->
|
||||
editText.applyTint(requireContext().accentColor)
|
||||
}
|
||||
}
|
||||
upPreferenceSummary(PreferKey.webDavUrl, getPrefString(PreferKey.webDavUrl))
|
||||
upPreferenceSummary(PreferKey.webDavAccount, getPrefString(PreferKey.webDavAccount))
|
||||
upPreferenceSummary(PreferKey.webDavPassword, getPrefString(PreferKey.webDavPassword))
|
||||
upPreferenceSummary(PreferKey.webDavDir, AppConfig.webDavDir)
|
||||
upPreferenceSummary(PreferKey.backupPath, getPrefString(PreferKey.backupPath))
|
||||
findPreference<io.legado.app.ui.widget.prefs.Preference>("web_dav_restore")
|
||||
findPreference<io.legado.app.lib.prefs.Preference>("web_dav_restore")
|
||||
?.onLongClick { restoreDir.launch(); true }
|
||||
}
|
||||
|
||||
@@ -226,7 +210,9 @@ class BackupConfigFragment : BasePreferenceFragment(),
|
||||
return super.onPreferenceTreeClick(preference)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 备份忽略设置
|
||||
*/
|
||||
private fun backupIgnore() {
|
||||
val checkedItems = BooleanArray(BackupConfig.ignoreKeys.size) {
|
||||
BackupConfig.ignoreConfig[BackupConfig.ignoreKeys[it]] ?: false
|
||||
|
||||
@@ -7,16 +7,16 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.prefs.SwitchPreference
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.ui.widget.prefs.SwitchPreference
|
||||
import io.legado.app.utils.*
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class CoverConfigFragment : BasePreferenceFragment(),
|
||||
class CoverConfigFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val requestCodeCover = 111
|
||||
|
||||
@@ -6,16 +6,17 @@ import android.content.SharedPreferences
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.core.view.postDelayed
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.CheckSource
|
||||
import io.legado.app.receiver.SharedReceiverActivity
|
||||
@@ -26,7 +27,7 @@ import io.legado.app.utils.*
|
||||
import splitties.init.appCtx
|
||||
|
||||
|
||||
class OtherConfigFragment : BasePreferenceFragment(),
|
||||
class OtherConfigFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val viewModel by activityViewModels<ConfigViewModel>()
|
||||
@@ -131,9 +132,9 @@ class OtherConfigFragment : BasePreferenceFragment(),
|
||||
setProcessTextEnable(it.getBoolean(key, true))
|
||||
}
|
||||
PreferKey.showDiscovery, PreferKey.showRss -> postEvent(EventBus.NOTIFY_MAIN, true)
|
||||
PreferKey.language -> listView.postDelayed({
|
||||
PreferKey.language -> listView.postDelayed(1000) {
|
||||
appCtx.restart()
|
||||
}, 1000)
|
||||
}
|
||||
PreferKey.userAgent -> listView.post {
|
||||
upPreferenceSummary(PreferKey.userAgent, AppConfig.userAgent)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ import android.widget.SeekBar
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.AppContextWrapper
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.AppConst
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
@@ -24,16 +23,17 @@ import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.prefs.ColorPreference
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.ui.widget.number.NumberPickerDialog
|
||||
import io.legado.app.ui.widget.prefs.ColorPreference
|
||||
import io.legado.app.ui.widget.seekbar.SeekBarChangeListener
|
||||
import io.legado.app.utils.*
|
||||
import java.io.FileOutputStream
|
||||
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
class ThemeConfigFragment : BasePreferenceFragment(),
|
||||
class ThemeConfigFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val requestCodeBgLight = 121
|
||||
|
||||
@@ -7,15 +7,15 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.model.BookCover
|
||||
import io.legado.app.utils.*
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class WelcomeConfigFragment : BasePreferenceFragment(),
|
||||
class WelcomeConfigFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
private val requestWelcomeImage = 221
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.KeyEvent
|
||||
import android.view.MenuItem
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.viewModels
|
||||
import androidx.core.view.postDelayed
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
@@ -87,13 +88,13 @@ class MainActivity : VMBaseActivity<ActivityMainBinding, MainViewModel>(),
|
||||
upVersion()
|
||||
//自动更新书籍
|
||||
if (AppConfig.autoRefreshBook) {
|
||||
binding.viewPagerMain.postDelayed({
|
||||
binding.viewPagerMain.postDelayed(1000) {
|
||||
viewModel.upAllBookToc()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
binding.viewPagerMain.postDelayed({
|
||||
binding.viewPagerMain.postDelayed(3000) {
|
||||
viewModel.postLoad()
|
||||
}, 3000)
|
||||
}
|
||||
launch {
|
||||
val lastBackupFile = withContext(IO) { AppWebDav.lastBackUp().getOrNull() }
|
||||
?: return@launch
|
||||
|
||||
@@ -8,13 +8,16 @@ import android.view.View
|
||||
import androidx.preference.Preference
|
||||
import io.legado.app.R
|
||||
import io.legado.app.base.BaseFragment
|
||||
import io.legado.app.base.BasePreferenceFragment
|
||||
import io.legado.app.constant.EventBus
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.databinding.FragmentMyConfigBinding
|
||||
import io.legado.app.help.config.AppConfig
|
||||
import io.legado.app.help.config.ThemeConfig
|
||||
import io.legado.app.lib.dialogs.selector
|
||||
import io.legado.app.lib.prefs.NameListPreference
|
||||
import io.legado.app.lib.prefs.PreferenceCategory
|
||||
import io.legado.app.lib.prefs.SwitchPreference
|
||||
import io.legado.app.lib.prefs.fragment.PreferenceFragment
|
||||
import io.legado.app.lib.theme.primaryColor
|
||||
import io.legado.app.service.WebService
|
||||
import io.legado.app.ui.about.AboutActivity
|
||||
@@ -26,9 +29,6 @@ import io.legado.app.ui.config.ConfigActivity
|
||||
import io.legado.app.ui.config.ConfigTag
|
||||
import io.legado.app.ui.replace.ReplaceRuleActivity
|
||||
import io.legado.app.ui.widget.dialog.TextDialog
|
||||
import io.legado.app.ui.widget.prefs.NameListPreference
|
||||
import io.legado.app.ui.widget.prefs.PreferenceCategory
|
||||
import io.legado.app.ui.widget.prefs.SwitchPreference
|
||||
import io.legado.app.utils.*
|
||||
import io.legado.app.utils.viewbindingdelegate.viewBinding
|
||||
|
||||
@@ -40,7 +40,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) {
|
||||
setSupportToolbar(binding.titleBar.toolbar)
|
||||
val fragmentTag = "prefFragment"
|
||||
var preferenceFragment = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||
if (preferenceFragment == null) preferenceFragment = PreferenceFragment()
|
||||
if (preferenceFragment == null) preferenceFragment = MyPreferenceFragment()
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.pre_fragment, preferenceFragment, fragmentTag).commit()
|
||||
}
|
||||
@@ -61,7 +61,7 @@ class MyFragment : BaseFragment(R.layout.fragment_my_config) {
|
||||
/**
|
||||
* 配置
|
||||
*/
|
||||
class PreferenceFragment : BasePreferenceFragment(),
|
||||
class MyPreferenceFragment : PreferenceFragment(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.legado.app.base.VMBaseActivity
|
||||
import io.legado.app.databinding.ActivityRssArtivlesBinding
|
||||
import io.legado.app.databinding.DialogEditTextBinding
|
||||
import io.legado.app.lib.dialogs.alert
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.ui.login.SourceLoginActivity
|
||||
import io.legado.app.ui.rss.source.edit.RssSourceEditActivity
|
||||
import io.legado.app.utils.StartActivityContract
|
||||
@@ -45,9 +46,10 @@ class RssSortActivity : VMBaseActivity<ActivityRssArtivlesBinding, RssSortViewMo
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
binding.viewPager.adapter = adapter
|
||||
binding.tabLayout.setupWithViewPager(binding.viewPager)
|
||||
viewModel.titleLiveData.observe(this, {
|
||||
binding.tabLayout.setSelectedTabIndicatorColor(accentColor)
|
||||
viewModel.titleLiveData.observe(this) {
|
||||
binding.titleBar.title = it
|
||||
})
|
||||
}
|
||||
viewModel.initData(intent) {
|
||||
upFragments()
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ class RssSourceEditActivity :
|
||||
private val qrCodeResult = registerForActivityResult(QrCodeResult()) {
|
||||
it?.let {
|
||||
viewModel.importSource(it) { source: RssSource ->
|
||||
upRecyclerView(source)
|
||||
upSourceView(source)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ class RssSourceEditActivity :
|
||||
softKeyboardTool.attachToWindow(window)
|
||||
initView()
|
||||
viewModel.initData(intent) {
|
||||
upRecyclerView()
|
||||
upSourceView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,10 +130,11 @@ class RssSourceEditActivity :
|
||||
}
|
||||
}
|
||||
}
|
||||
R.id.menu_clear_cookie -> viewModel.clearCookie(getRssSource().sourceUrl)
|
||||
R.id.menu_auto_complete -> viewModel.autoComplete = !viewModel.autoComplete
|
||||
R.id.menu_copy_source -> sendToClip(GSON.toJson(getRssSource()))
|
||||
R.id.menu_qr_code_camera -> qrCodeResult.launch()
|
||||
R.id.menu_paste_source -> viewModel.pasteSource { upRecyclerView(it) }
|
||||
R.id.menu_paste_source -> viewModel.pasteSource { upSourceView(it) }
|
||||
R.id.menu_share_str -> share(GSON.toJson(getRssSource()))
|
||||
R.id.menu_share_qr -> shareWithQr(
|
||||
GSON.toJson(getRssSource()),
|
||||
@@ -150,10 +151,11 @@ class RssSourceEditActivity :
|
||||
binding.recyclerView.adapter = adapter
|
||||
}
|
||||
|
||||
private fun upRecyclerView(source: RssSource? = viewModel.rssSource) {
|
||||
private fun upSourceView(source: RssSource? = viewModel.rssSource) {
|
||||
source?.let {
|
||||
binding.cbIsEnable.isChecked = source.enabled
|
||||
binding.cbSingleUrl.isChecked = source.singleUrl
|
||||
binding.cbIsEnableCookie.isChecked = source.enabledCookieJar == true
|
||||
binding.cbEnableJs.isChecked = source.enableJs
|
||||
binding.cbEnableBaseUrl.isChecked = source.loadWithBaseUrl
|
||||
}
|
||||
@@ -191,6 +193,7 @@ class RssSourceEditActivity :
|
||||
val source = viewModel.rssSource
|
||||
source.enabled = binding.cbIsEnable.isChecked
|
||||
source.singleUrl = binding.cbSingleUrl.isChecked
|
||||
source.enabledCookieJar = binding.cbIsEnableCookie.isChecked
|
||||
source.enableJs = binding.cbEnableJs.isChecked
|
||||
source.loadWithBaseUrl = binding.cbEnableBaseUrl.isChecked
|
||||
sourceEntities.forEach {
|
||||
|
||||
@@ -6,6 +6,7 @@ import io.legado.app.base.BaseViewModel
|
||||
import io.legado.app.data.appDb
|
||||
import io.legado.app.data.entities.RssSource
|
||||
import io.legado.app.help.RuleComplete
|
||||
import io.legado.app.help.http.CookieStore
|
||||
import io.legado.app.utils.getClipText
|
||||
import io.legado.app.utils.msg
|
||||
import io.legado.app.utils.printOnDebug
|
||||
@@ -77,6 +78,12 @@ class RssSourceEditViewModel(application: Application) : BaseViewModel(applicati
|
||||
}
|
||||
}
|
||||
|
||||
fun clearCookie(url: String) {
|
||||
execute {
|
||||
CookieStore.removeCookie(url)
|
||||
}
|
||||
}
|
||||
|
||||
fun ruleComplete(rule: String?, preRule: String? = null, type: Int = 1): String? {
|
||||
if (autoComplete) {
|
||||
return RuleComplete.autoComplete(rule, preRule, type)
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.legado.app.ui.welcome
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.postDelayed
|
||||
import io.legado.app.base.BaseActivity
|
||||
import io.legado.app.constant.PreferKey
|
||||
import io.legado.app.constant.Theme
|
||||
@@ -26,7 +27,7 @@ open class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
||||
if (intent.flags and Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT != 0) {
|
||||
finish()
|
||||
} else {
|
||||
binding.root.postDelayed({ startMainActivity() }, 600)
|
||||
binding.root.postDelayed(600) { startMainActivity() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.widget.Checkable
|
||||
import androidx.core.view.postDelayed
|
||||
import io.legado.app.R
|
||||
import io.legado.app.lib.theme.ThemeStore
|
||||
import io.legado.app.utils.dpToPx
|
||||
@@ -244,7 +245,7 @@ class SmoothCheckBox @JvmOverloads constructor(
|
||||
}
|
||||
// invalidate
|
||||
if (mDrewDistance < mLeftLineDistance + mRightLineDistance) {
|
||||
postDelayed({ this.postInvalidate() }, 10)
|
||||
postDelayed(10) { this.postInvalidate() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,10 +299,10 @@ class SmoothCheckBox @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
private fun drawTickDelayed() {
|
||||
postDelayed({
|
||||
postDelayed(mAnimDuration.toLong()) {
|
||||
mTickDrawing = true
|
||||
postInvalidate()
|
||||
}, mAnimDuration.toLong())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package io.legado.app.ui.widget.prefs
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.TextView
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import io.legado.app.R
|
||||
|
||||
class EditTextPreference(context: Context, attrs: AttributeSet) :
|
||||
androidx.preference.EditTextPreference(context, attrs) {
|
||||
|
||||
init {
|
||||
// isPersistent = true
|
||||
layoutResource = R.layout.view_preference
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PreferenceViewHolder) {
|
||||
Preference.bindView<TextView>(context, holder, icon, title, summary, null, null)
|
||||
super.onBindViewHolder(holder)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import android.widget.FrameLayout.LayoutParams
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import io.legado.app.R
|
||||
import io.legado.app.lib.theme.accentColor
|
||||
import io.legado.app.utils.ColorUtils
|
||||
import io.legado.app.utils.getCompatColor
|
||||
import io.legado.app.utils.invisible
|
||||
import io.legado.app.utils.visible
|
||||
@@ -87,8 +88,6 @@ class BadgeView @JvmOverloads constructor(
|
||||
setLayoutParams(layoutParams)
|
||||
}
|
||||
|
||||
// set default font
|
||||
setTextColor(Color.WHITE)
|
||||
//setTypeface(Typeface.DEFAULT_BOLD);
|
||||
setTextSize(TypedValue.COMPLEX_UNIT_SP, 11f)
|
||||
setPadding(dip2Px(5f), dip2Px(1f), dip2Px(5f), dip2Px(1f))
|
||||
@@ -106,6 +105,10 @@ class BadgeView @JvmOverloads constructor(
|
||||
minHeight = dip2Px(16f)
|
||||
}
|
||||
|
||||
override fun setBackgroundColor(color: Int) {
|
||||
setBackground(radius, color)
|
||||
}
|
||||
|
||||
fun setBackground(dipRadius: Float, badgeColor: Int) {
|
||||
val radius = dip2Px(dipRadius).toFloat()
|
||||
val radiusArray =
|
||||
@@ -118,10 +121,13 @@ class BadgeView @JvmOverloads constructor(
|
||||
val bgDrawable = ShapeDrawable(roundRect)
|
||||
bgDrawable.paint.color = badgeColor
|
||||
background = bgDrawable
|
||||
}
|
||||
|
||||
fun setBackground(badgeColor: Int) {
|
||||
setBackground(radius, badgeColor)
|
||||
setTextColor(
|
||||
if (ColorUtils.isColorLight(badgeColor)) {
|
||||
Color.BLACK
|
||||
} else {
|
||||
Color.WHITE
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,9 +148,9 @@ class BadgeView @JvmOverloads constructor(
|
||||
|
||||
fun setHighlight(highlight: Boolean) {
|
||||
if (highlight) {
|
||||
setBackground(context.accentColor)
|
||||
setBackgroundColor(context.accentColor)
|
||||
} else {
|
||||
setBackground(context.getCompatColor(R.color.darker_gray))
|
||||
setBackgroundColor(context.getCompatColor(R.color.darker_gray))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import android.graphics.Color
|
||||
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.FloatRange
|
||||
import java.util.*
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import kotlin.math.*
|
||||
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
object ColorUtils {
|
||||
|
||||
fun isColorLight(@ColorInt color: Int): Boolean {
|
||||
return ColorUtils.calculateLuminance(color) >= 0.5
|
||||
}
|
||||
|
||||
fun intToString(intColor: Int): String {
|
||||
return String.format("#%06X", 0xFFFFFF and intColor)
|
||||
}
|
||||
|
||||
|
||||
fun stripAlpha(@ColorInt color: Int): Int {
|
||||
return -0x1000000 or color
|
||||
}
|
||||
@@ -39,12 +41,6 @@ object ColorUtils {
|
||||
return shiftColor(color, 1.1f)
|
||||
}
|
||||
|
||||
fun isColorLight(@ColorInt color: Int): Boolean {
|
||||
val darkness =
|
||||
1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255
|
||||
return darkness < 0.4
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun invertColor(@ColorInt color: Int): Int {
|
||||
val r = 255 - Color.red(color)
|
||||
@@ -81,83 +77,6 @@ object ColorUtils {
|
||||
return Color.argb(a.toInt(), r.toInt(), g.toInt(), b.toInt())
|
||||
}
|
||||
|
||||
/**
|
||||
* 按条件的到随机颜色
|
||||
*
|
||||
* @param alpha 透明
|
||||
* @param lower 下边界
|
||||
* @param upper 上边界
|
||||
* @return 颜色值
|
||||
*/
|
||||
fun getRandomColor(alpha: Int, lower: Int, upper: Int): Int {
|
||||
return RandomColor(alpha, lower, upper).color
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取随机色
|
||||
*/
|
||||
fun getRandomColor(): Int {
|
||||
return RandomColor(255, 80, 200).color
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机颜色
|
||||
*/
|
||||
class RandomColor(alpha: Int, lower: Int, upper: Int) {
|
||||
private var alpha: Int = 0
|
||||
private var lower: Int = 0
|
||||
private var upper: Int = 0
|
||||
|
||||
//随机数是前闭 后开
|
||||
val color: Int
|
||||
get() {
|
||||
val red = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
val green = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
val blue = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
|
||||
return Color.argb(getAlpha(), red, green, blue)
|
||||
}
|
||||
|
||||
init {
|
||||
require(upper > lower) { "must be lower < upper" }
|
||||
setAlpha(alpha)
|
||||
setLower(lower)
|
||||
setUpper(upper)
|
||||
}
|
||||
|
||||
private fun getAlpha(): Int {
|
||||
return alpha
|
||||
}
|
||||
|
||||
private fun setAlpha(alpha: Int) {
|
||||
var alpha1 = alpha
|
||||
if (alpha1 > 255) alpha1 = 255
|
||||
if (alpha1 < 0) alpha1 = 0
|
||||
this.alpha = alpha1
|
||||
}
|
||||
|
||||
private fun getLower(): Int {
|
||||
return lower
|
||||
}
|
||||
|
||||
private fun setLower(lower: Int) {
|
||||
var lower1 = lower
|
||||
if (lower1 < 0) lower1 = 0
|
||||
this.lower = lower1
|
||||
}
|
||||
|
||||
private fun getUpper(): Int {
|
||||
return upper
|
||||
}
|
||||
|
||||
private fun setUpper(upper: Int) {
|
||||
var upper1 = upper
|
||||
if (upper1 > 255) upper1 = 255
|
||||
this.upper = upper1
|
||||
}
|
||||
}
|
||||
|
||||
fun argb(R: Int, G: Int, B: Int): Int {
|
||||
return argb(Byte.MAX_VALUE.toInt(), R, G, B)
|
||||
}
|
||||
@@ -177,72 +96,19 @@ object ColorUtils {
|
||||
+ (colorByteArr[2].toInt() and 0xFF shl 8) + (colorByteArr[3].toInt() and 0xFF))
|
||||
}
|
||||
|
||||
fun rgb2lab(R: Int, G: Int, B: Int): IntArray {
|
||||
val x: Float
|
||||
val y: Float
|
||||
val z: Float
|
||||
val fx: Float
|
||||
val fy: Float
|
||||
val fz: Float
|
||||
val xr: Float
|
||||
val yr: Float
|
||||
val zr: Float
|
||||
val eps = 216f / 24389f
|
||||
val k = 24389f / 27f
|
||||
val xr1 = 0.964221f // reference white D50
|
||||
val yr1 = 1.0f
|
||||
val zr1 = 0.825211f
|
||||
|
||||
// RGB to XYZ
|
||||
var r: Float = R / 255f //R 0..1
|
||||
var g: Float = G / 255f //G 0..1
|
||||
var b: Float = B / 255f //B 0..1
|
||||
|
||||
// assuming sRGB (D65)
|
||||
r = if (r <= 0.04045) r / 12 else ((r + 0.055) / 1.055).pow(2.4).toFloat()
|
||||
g = if (g <= 0.04045) g / 12 else ((g + 0.055) / 1.055).pow(2.4).toFloat()
|
||||
b = if (b <= 0.04045) b / 12 else ((b + 0.055) / 1.055).pow(2.4).toFloat()
|
||||
x = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b
|
||||
y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b
|
||||
z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b
|
||||
|
||||
// XYZ to Lab
|
||||
xr = x / xr1
|
||||
yr = y / yr1
|
||||
zr = z / zr1
|
||||
fx = if (xr > eps) xr.toDouble().pow(1 / 3.0)
|
||||
.toFloat() else ((k * xr + 16.0) / 116.0).toFloat()
|
||||
fy = if (yr > eps) yr.toDouble().pow(1 / 3.0)
|
||||
.toFloat() else ((k * yr + 16.0) / 116.0).toFloat()
|
||||
fz = if (zr > eps) zr.toDouble().pow(1 / 3.0)
|
||||
.toFloat() else ((k * zr + 16.0) / 116).toFloat()
|
||||
val ls: Float = 116 * fy - 16
|
||||
val `as`: Float = 500 * (fx - fy)
|
||||
val bs: Float = 200 * (fy - fz)
|
||||
val lab = IntArray(3)
|
||||
lab[0] = (2.55 * ls + .5).toInt()
|
||||
lab[1] = (`as` + .5).toInt()
|
||||
lab[2] = (bs + .5).toInt()
|
||||
return lab
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the difference between two RGB colors by converting them to the L*a*b scale and
|
||||
* comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
|
||||
*/
|
||||
fun getColorDifference(a: Int, b: Int): Double {
|
||||
val r1: Int = Color.red(a)
|
||||
val g1: Int = Color.green(a)
|
||||
val b1: Int = Color.blue(a)
|
||||
val r2: Int = Color.red(b)
|
||||
val g2: Int = Color.green(b)
|
||||
val b2: Int = Color.blue(b)
|
||||
val lab1 = rgb2lab(r1, g1, b1)
|
||||
val lab2 = rgb2lab(r2, g2, b2)
|
||||
val lab1 = DoubleArray(3)
|
||||
val lab2 = DoubleArray(3)
|
||||
ColorUtils.colorToLAB(a, lab1)
|
||||
ColorUtils.colorToLAB(b, lab2)
|
||||
return sqrt(
|
||||
(lab2[0] - lab1[0].toDouble())
|
||||
.pow(2.0) + (lab2[1] - lab1[1].toDouble())
|
||||
.pow(2.0) + (lab2[2] - lab1[2].toDouble())
|
||||
(lab2[0] - lab1[0])
|
||||
.pow(2.0) + (lab2[1] - lab1[1])
|
||||
.pow(2.0) + (lab2[2] - lab1[2])
|
||||
.pow(2.0)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -331,6 +331,7 @@ fun Context.openFileUri(uri: Uri, type: String? = null) {
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
val Context.isWifiConnect: Boolean
|
||||
@SuppressLint("MissingPermission")
|
||||
get() {
|
||||
val info = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI)
|
||||
return info?.isConnected == true
|
||||
@@ -338,7 +339,7 @@ val Context.isWifiConnect: Boolean
|
||||
|
||||
val Context.isPad: Boolean
|
||||
get() {
|
||||
return resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK >= Configuration.SCREENLAYOUT_SIZE_LARGE
|
||||
return (resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE
|
||||
}
|
||||
|
||||
val Context.channel: String
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import android.graphics.Color
|
||||
import java.util.*
|
||||
|
||||
@Suppress("unused")
|
||||
class RandomColor(alpha: Int, lower: Int, upper: Int) {
|
||||
|
||||
constructor() : this(255, 80, 200)
|
||||
|
||||
private var alpha: Int = 0
|
||||
private var lower: Int = 0
|
||||
private var upper: Int = 0
|
||||
|
||||
init {
|
||||
require(upper > lower) { "must be lower < upper" }
|
||||
setAlpha(alpha)
|
||||
setLower(lower)
|
||||
setUpper(upper)
|
||||
}
|
||||
|
||||
//随机数是前闭 后开
|
||||
fun build(): Int {
|
||||
val red = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
val green = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
val blue = getLower() + Random().nextInt(getUpper() - getLower() + 1)
|
||||
return Color.argb(getAlpha(), red, green, blue)
|
||||
}
|
||||
|
||||
private fun getAlpha(): Int {
|
||||
return alpha
|
||||
}
|
||||
|
||||
private fun setAlpha(alpha: Int) {
|
||||
var alpha1 = alpha
|
||||
if (alpha1 > 255) alpha1 = 255
|
||||
if (alpha1 < 0) alpha1 = 0
|
||||
this.alpha = alpha1
|
||||
}
|
||||
|
||||
private fun getLower(): Int {
|
||||
return lower
|
||||
}
|
||||
|
||||
private fun setLower(lower: Int) {
|
||||
var lower1 = lower
|
||||
if (lower1 < 0) lower1 = 0
|
||||
this.lower = lower1
|
||||
}
|
||||
|
||||
private fun getUpper(): Int {
|
||||
return upper
|
||||
}
|
||||
|
||||
private fun setUpper(upper: Int) {
|
||||
var upper1 = upper
|
||||
if (upper1 > 255) upper1 = 255
|
||||
this.upper = upper1
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package io.legado.app.utils
|
||||
|
||||
import androidx.core.os.postDelayed
|
||||
import io.legado.app.exception.RegexTimeoutException
|
||||
import io.legado.app.help.CrashHandler
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import splitties.init.appCtx
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
/**
|
||||
* 带有超时检测的正则替换
|
||||
@@ -19,23 +21,23 @@ suspend fun CharSequence.replace(regex: Regex, replacement: String, timeout: Lon
|
||||
val result = regex.replace(charSequence, replacement)
|
||||
block.resume(result)
|
||||
} catch (e: Exception) {
|
||||
block.cancel(e)
|
||||
block.resumeWithException(e)
|
||||
}
|
||||
}
|
||||
mainHandler.postDelayed({
|
||||
mainHandler.postDelayed(timeout) {
|
||||
if (thread.isAlive) {
|
||||
val timeoutMsg = "替换超时,3秒后还未结束将重启应用\n替换规则$regex\n替换内容:${this}"
|
||||
val exception = RegexTimeoutException(timeoutMsg)
|
||||
block.cancel(exception)
|
||||
appCtx.longToastOnUi(timeoutMsg)
|
||||
CrashHandler.saveCrashInfo2File(exception)
|
||||
mainHandler.postDelayed({
|
||||
mainHandler.postDelayed(3000) {
|
||||
if (thread.isAlive) {
|
||||
appCtx.restart()
|
||||
}
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
}, timeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ class HttpServer(port: Int) : NanoHTTPD(port) {
|
||||
"/saveBookSources" -> BookSourceController.saveSources(postData)
|
||||
"/deleteBookSources" -> BookSourceController.deleteSources(postData)
|
||||
"/saveBook" -> BookController.saveBook(postData)
|
||||
"/saveBookProgress" -> BookController.saveBookProgress(postData)
|
||||
"/addLocalBook" -> BookController.addLocalBook(session.parameters)
|
||||
"/saveReadConfig" -> BookController.saveWebReadConfig(postData)
|
||||
"/saveRssSource" -> RssSourceController.saveSource(postData)
|
||||
|
||||
@@ -33,6 +33,13 @@
|
||||
android:checked="true"
|
||||
android:text="@string/discovery" />
|
||||
|
||||
<io.legado.app.lib.theme.view.ThemeCheckBox
|
||||
android:id="@+id/cb_is_enable_cookie"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/auto_save_cookie" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -45,6 +45,13 @@
|
||||
android:text="@string/single_url"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
<io.legado.app.lib.theme.view.ThemeCheckBox
|
||||
android:id="@+id/cb_is_enable_cookie"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="@string/auto_save_cookie" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cb_file_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/primaryText"
|
||||
android:textSize="14sp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="TouchTargetSizeCheck" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Loaded 100 of 124 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user