@ -0,0 +1,32 @@ |
|||||||
|
#更新fork |
||||||
|
name: update fork |
||||||
|
|
||||||
|
on: |
||||||
|
schedule: |
||||||
|
- cron: '0 16 * * *' #设置定时任务 |
||||||
|
|
||||||
|
jobs: |
||||||
|
build: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
if: ${{ github.event.repository.owner.id == github.event.sender.id && github.actor != 'gedoor' }} |
||||||
|
steps: |
||||||
|
- name: Checkout |
||||||
|
uses: actions/checkout@v2 |
||||||
|
with: |
||||||
|
fetch-depth: 0 |
||||||
|
- name: Install git |
||||||
|
run: | |
||||||
|
sudo apt-get update |
||||||
|
sudo apt-get -y install git |
||||||
|
- name: Set env |
||||||
|
run: | |
||||||
|
git config --global user.email "github-actions@github.com" |
||||||
|
git config --global user.name "github-actions" |
||||||
|
- name: Update fork |
||||||
|
run: | |
||||||
|
git remote add upstream https://github.com/gedoor/legado.git |
||||||
|
git remote -v |
||||||
|
git fetch upstream |
||||||
|
git checkout master |
||||||
|
git merge upstream/master |
||||||
|
git push origin master |
@ -0,0 +1,57 @@ |
|||||||
|
name: Android CI |
||||||
|
|
||||||
|
on: |
||||||
|
release: |
||||||
|
types: [published] |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- master |
||||||
|
# tags: |
||||||
|
# - '3.*' |
||||||
|
# pull_request: |
||||||
|
# branches: |
||||||
|
# - master |
||||||
|
# watch: |
||||||
|
# types: [started] |
||||||
|
# schedule: |
||||||
|
# - cron: '0 4 * * *' |
||||||
|
|
||||||
|
jobs: |
||||||
|
build: |
||||||
|
|
||||||
|
runs-on: ubuntu-latest |
||||||
|
|
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
- name: set up JDK 1.8 |
||||||
|
uses: actions/setup-java@v1 |
||||||
|
with: |
||||||
|
java-version: 1.8 |
||||||
|
- name: clear 18PlusList.txt |
||||||
|
run: | |
||||||
|
echo "清空18PlusList.txt" |
||||||
|
echo "">$GITHUB_WORKSPACE/app/src/main/assets/18PlusList.txt |
||||||
|
- name: release apk sign |
||||||
|
run: | |
||||||
|
echo "给apk增加签名" |
||||||
|
cp $GITHUB_WORKSPACE/.github/workflows/legado.jks $GITHUB_WORKSPACE/app/legado.jks |
||||||
|
sed '$a\RELEASE_STORE_FILE=./legado.jks' $GITHUB_WORKSPACE/gradle.properties -i |
||||||
|
sed '$a\RELEASE_KEY_ALIAS=legado' $GITHUB_WORKSPACE/gradle.properties -i |
||||||
|
sed '$a\RELEASE_STORE_PASSWORD=gedoor_legado' $GITHUB_WORKSPACE/gradle.properties -i |
||||||
|
sed '$a\RELEASE_KEY_PASSWORD=gedoor_legado' $GITHUB_WORKSPACE/gradle.properties -i |
||||||
|
- name: apk live together |
||||||
|
run: | |
||||||
|
echo "设置apk共存" |
||||||
|
sed "s/'.release'/'.releaseA'/" $GITHUB_WORKSPACE/app/build.gradle -i |
||||||
|
sed 's/.release/.releaseA/' $GITHUB_WORKSPACE/app/google-services.json -i |
||||||
|
- name: build with gradle |
||||||
|
run: | |
||||||
|
echo "开始进行release构建" |
||||||
|
chmod +x gradlew |
||||||
|
./gradlew assembleAppRelease |
||||||
|
- name : upload apk |
||||||
|
uses: actions/upload-artifact@master |
||||||
|
if: always() |
||||||
|
with: |
||||||
|
name: legado apk |
||||||
|
path: ${{ github.workspace }}/app/build/outputs/apk/app/release |
@ -0,0 +1,4 @@ |
|||||||
|
# 1.0.0 (2020-02-09) |
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,2 +1,21 @@ |
|||||||
# legado |
# legado |
||||||
|
|
||||||
|
[](http://commitizen.github.io/cz-cli/) |
||||||
|
|
||||||
## 阅读3.0 |
## 阅读3.0 |
||||||
|
* [书源规则](https://alanskycn.gitee.io/teachme/) |
||||||
|
* [更新日志](/app/src/main/assets/updateLog.md) |
||||||
|
* [帮助文档](/app/src/main/assets/help/help.md) |
||||||
|
|
||||||
|
 |
||||||
|
 |
||||||
|
 |
||||||
|
 |
||||||
|
 |
||||||
|
 |
||||||
|
|
||||||
|
### 阅读API |
||||||
|
阅读3.0 提供了2种方式的API:`Web方式`和`Content Provider方式`。您可以在[这里](api.md)根据需要自行调用。 |
||||||
|
|
||||||
|
## 免责声明 |
||||||
|
https://gedoor.github.io/MyBookshelf/disclaimer.html |
||||||
|
@ -0,0 +1,169 @@ |
|||||||
|
# 阅读API |
||||||
|
## 对于Web的配置 |
||||||
|
您需要先在设置中启用"Web 服务"。 |
||||||
|
## 使用 |
||||||
|
### Web |
||||||
|
以下说明假设您的操作在本机进行,且开放端口为1234。 |
||||||
|
如果您要从远程计算机访问[阅读](),请将`127.0.0.1`替换成手机IP。 |
||||||
|
#### 插入单个书源 |
||||||
|
``` |
||||||
|
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) |
||||||
|
|
||||||
|
#### 插入多个书源 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/saveSources |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求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/getSource?url=xxx |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定URL对应的书源信息。 |
||||||
|
|
||||||
|
#### 获取所有书源 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getSources |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书源。 |
||||||
|
|
||||||
|
#### 删除多个书源 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/deleteSources |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求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/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内的所有书籍。 |
||||||
|
|
||||||
|
#### 获取书籍章节列表 |
||||||
|
``` |
||||||
|
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`章节的文本内容。 |
||||||
|
|
||||||
|
### Content Provider |
||||||
|
* 需声明`io.legado.READ_WRITE`权限 |
||||||
|
* `providerHost`为`包名.readerProvider`, 如`io.legado.app.release.readerProvider`,不同包的地址不同,防止冲突安装失败 |
||||||
|
* 以下出现的`providerHost`请自行替换 |
||||||
|
#### 插入单个书源 |
||||||
|
``` |
||||||
|
URL = content://providerHost/source/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) |
||||||
|
|
||||||
|
#### 插入多个书源 |
||||||
|
``` |
||||||
|
URL = content://providerHost/sources/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),**为数组格式**。 |
||||||
|
|
||||||
|
#### 获取书源 |
||||||
|
``` |
||||||
|
URL = content://providerHost/source/query?url=xxx |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定URL对应的书源信息。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取所有书源 |
||||||
|
``` |
||||||
|
URL = content://providerHost/sources/query |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书源。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 删除多个书源 |
||||||
|
``` |
||||||
|
URL = content://providerHost/sources/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),**为数组格式**。 |
||||||
|
|
||||||
|
#### 插入书籍 |
||||||
|
``` |
||||||
|
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)。 |
||||||
|
|
||||||
|
#### 获取所有书籍 |
||||||
|
``` |
||||||
|
URL = content://providerHost/books/query |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书籍。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取书籍章节列表 |
||||||
|
``` |
||||||
|
URL = content://providerHost/book/chapter/query?url=xxx |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定图书的章节列表。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取书籍内容 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/book/content/query?url=xxx&index=1 |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定图书的第`index`章节的文本内容。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
@ -1,69 +0,0 @@ |
|||||||
{ |
|
||||||
"project_info": { |
|
||||||
"project_number": "453392274790", |
|
||||||
"firebase_url": "https://legado-fca69.firebaseio.com", |
|
||||||
"project_id": "legado-fca69", |
|
||||||
"storage_bucket": "legado-fca69.appspot.com" |
|
||||||
}, |
|
||||||
"client": [ |
|
||||||
{ |
|
||||||
"client_info": { |
|
||||||
"mobilesdk_app_id": "1:453392274790:android:1d2b1eefbe0e78cff624a7", |
|
||||||
"android_client_info": { |
|
||||||
"package_name": "io.legado.app" |
|
||||||
} |
|
||||||
}, |
|
||||||
"oauth_client": [ |
|
||||||
{ |
|
||||||
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
|
||||||
"client_type": 3 |
|
||||||
} |
|
||||||
], |
|
||||||
"api_key": [ |
|
||||||
{ |
|
||||||
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
|
||||||
} |
|
||||||
], |
|
||||||
"services": { |
|
||||||
"appinvite_service": { |
|
||||||
"other_platform_oauth_client": [ |
|
||||||
{ |
|
||||||
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
|
||||||
"client_type": 3 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
{ |
|
||||||
"client_info": { |
|
||||||
"mobilesdk_app_id": "1:453392274790:android:c4eac14b1410eec5f624a7", |
|
||||||
"android_client_info": { |
|
||||||
"package_name": "io.legado.app.debug" |
|
||||||
} |
|
||||||
}, |
|
||||||
"oauth_client": [ |
|
||||||
{ |
|
||||||
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
|
||||||
"client_type": 3 |
|
||||||
} |
|
||||||
], |
|
||||||
"api_key": [ |
|
||||||
{ |
|
||||||
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
|
||||||
} |
|
||||||
], |
|
||||||
"services": { |
|
||||||
"appinvite_service": { |
|
||||||
"other_platform_oauth_client": [ |
|
||||||
{ |
|
||||||
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
|
||||||
"client_type": 3 |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
], |
|
||||||
"configuration_version": "1" |
|
||||||
} |
|
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<string name="app_name">閲讀.D</string> |
||||||
|
<string name="receiving_shared_label">閲讀·D·搜索</string> |
||||||
|
</resources> |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
<string name="app_name">閲讀.D</string> |
||||||
|
<string name="receiving_shared_label">閲讀·D·搜尋</string> |
||||||
|
</resources> |
@ -0,0 +1,4 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">阅读·D</string> |
||||||
|
<string name="receiving_shared_label">阅读·D·搜索</string> |
||||||
|
</resources> |
@ -1,4 +1,4 @@ |
|||||||
<resources> |
<resources> |
||||||
<string name="app_name">阅读.debug</string> |
<string name="app_name">legado·D</string> |
||||||
<string name="receiving_shared_label">阅读.debug·搜索</string> |
<string name="receiving_shared_label">legado·D·search</string> |
||||||
</resources> |
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">阅读Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">閱讀Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">閱讀Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">legadoPro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,82 @@ |
|||||||
|
OGN5dS5jb20= |
||||||
|
c2cwMC54eXo= |
||||||
|
aXRyYWZmaWNuZXQuY29t |
||||||
|
eGlhb3FpYW5nNTIw |
||||||
|
MTIzeGlhb3FpYW5n |
||||||
|
eGlhb3FpYW5neHM= |
||||||
|
eGlhb3FpYW5nNTIw |
||||||
|
MzM1eHM= |
||||||
|
eGN4czk= |
||||||
|
eGN4czUyMA== |
||||||
|
c2h1YmFvYW4= |
||||||
|
c2h1YmFvd2FuZzEyMw== |
||||||
|
c2h1YmFvYW4= |
||||||
|
aGFpdGFuZzEyMw== |
||||||
|
eXV6aGFpd3VsYQ== |
||||||
|
cG8xOA== |
||||||
|
Ymwtbm92ZWw= |
||||||
|
NXRucw== |
||||||
|
c2hhb3NodWdl |
||||||
|
amluamlzaHV3dQ== |
||||||
|
NDJ3Zw== |
||||||
|
eWlxdXNodQ== |
||||||
|
c2h1YmFvd2FuZzEyMw== |
||||||
|
M2hlYmFv |
||||||
|
MzNoZWJhbw== |
||||||
|
bHVvcWl1enc= |
||||||
|
bXlzaHVnZQ== |
||||||
|
c3NzeHN3 |
||||||
|
eWl0ZQ== |
||||||
|
Y3Vpd2VpanV1 |
||||||
|
Y3Vpd2VpanV4cw== |
||||||
|
Y3Vpd2VpanV4 |
||||||
|
eGlhb3FpYW5nd3g= |
||||||
|
YXN6dw== |
||||||
|
YXN6dzY= |
||||||
|
c2FuaGFveHM= |
||||||
|
ODdzaHV3dQ== |
||||||
|
NDh3eA== |
||||||
|
bG9uZ3Rlbmcy |
||||||
|
NnF3eA== |
||||||
|
bG9uZ3Rlbmd4cw== |
||||||
|
aGF4ZHU= |
||||||
|
M3R3eA== |
||||||
|
aGF4d3g1 |
||||||
|
NjZsZXdlbg== |
||||||
|
eGJhbnpodQ== |
||||||
|
aGR5cA== |
||||||
|
ZHliejk= |
||||||
|
ZGl5aWJhbnpodTk= |
||||||
|
ZGl5aWJhbnpodQ== |
||||||
|
ZGl5aWJhbnpodTc= |
||||||
|
YnoyMjI= |
||||||
|
d29kZWFwaTAwMQ== |
||||||
|
dGFuZ3poZWthbg== |
||||||
|
YmF4aWFueHM= |
||||||
|
eGlhb3NodW9zaGVuemhhbg== |
||||||
|
ZGFtb2tl |
||||||
|
emh3ZW5wZw== |
||||||
|
eXV6aGFpZ2U= |
||||||
|
d21wOA== |
||||||
|
OXhpYW53ZW4= |
||||||
|
bmFucmVudmlw |
||||||
|
cmV5b28= |
||||||
|
eWZ4aWFvc2h1b2U= |
||||||
|
c2Fuaml1enc= |
||||||
|
N3Fpbmc3 |
||||||
|
cWR4aWFvc2h1bw== |
||||||
|
Y2hpbmVzZXpq |
||||||
|
MzlzaHViYW8= |
||||||
|
a3l4czU= |
||||||
|
NTZtcw== |
||||||
|
bml1c2hh |
||||||
|
bWt4czY= |
||||||
|
MjIyMjJ4cw== |
||||||
|
OTVkdXNodQ== |
||||||
|
YmFuemh1MjI= |
||||||
|
d3JsdHh0 |
||||||
|
dHVkb3V0eHQ= |
||||||
|
cm5neHM= |
||||||
|
OTl3ZW5rdQ== |
||||||
|
bGFvc2lqaXhz |
||||||
|
ZnVzaHV6aGFpMQ== |
Before Width: | Height: | Size: 173 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 39 KiB |
@ -0,0 +1,62 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"id": 1598233029304, |
||||||
|
"name": "度小美", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029305, |
||||||
|
"name": "度小宇", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=1&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029306, |
||||||
|
"name": "度逍遥", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5003&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029307, |
||||||
|
"name": "度丫丫", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=4&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029308, |
||||||
|
"name": "度小娇", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029309, |
||||||
|
"name": "度米朵", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029310, |
||||||
|
"name": "度博文", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029311, |
||||||
|
"name": "度小童", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029312, |
||||||
|
"name": "度小萌", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=111&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029313, |
||||||
|
"name": "百度骚男", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=11&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029314, |
||||||
|
"name": "百度评书", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=6&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": 1598233029315, |
||||||
|
"name": "百度主持", |
||||||
|
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=9&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio\"\n}" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,52 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"bgStr": "#FFFFFF", |
||||||
|
"bgStrNight": "#000000", |
||||||
|
"textColor": "#000000", |
||||||
|
"textColorNight": "#FFFFFF", |
||||||
|
"bgType": 0, |
||||||
|
"bgTypeNight": 0, |
||||||
|
"darkStatusIcon": true, |
||||||
|
"darkStatusIconNight": false |
||||||
|
}, |
||||||
|
{ |
||||||
|
"bgStr": "#DDC090", |
||||||
|
"bgStrNight": "#3C3F43", |
||||||
|
"textColor": "#3E3422", |
||||||
|
"textColorNight": "#DCDFE1", |
||||||
|
"bgType": 0, |
||||||
|
"bgTypeNight": 0, |
||||||
|
"darkStatusIcon": true, |
||||||
|
"darkStatusIconNight": false |
||||||
|
}, |
||||||
|
{ |
||||||
|
"bgStr": "#C2D8AA", |
||||||
|
"bgStrNight": "#3C3F43", |
||||||
|
"textColor": "#596C44", |
||||||
|
"textColorNight": "#88C16F", |
||||||
|
"bgType": 0, |
||||||
|
"bgTypeNight": 0, |
||||||
|
"darkStatusIcon": false, |
||||||
|
"darkStatusIconNight": false |
||||||
|
}, |
||||||
|
{ |
||||||
|
"bgStr": "#DBB8E2", |
||||||
|
"bgStrNight": "#3C3F43", |
||||||
|
"textColor": "#68516C", |
||||||
|
"textColorNight": "#F6AEAE", |
||||||
|
"bgType": 0, |
||||||
|
"bgTypeNight": 0, |
||||||
|
"darkStatusIcon": false, |
||||||
|
"darkStatusIconNight": false |
||||||
|
}, |
||||||
|
{ |
||||||
|
"bgStr": "#ABCEE0", |
||||||
|
"bgStrNight": "#3C3F43", |
||||||
|
"textColor": "#3D4C54", |
||||||
|
"textColorNight": "#90BFF5", |
||||||
|
"bgType": 0, |
||||||
|
"bgTypeNight": 0, |
||||||
|
"darkStatusIcon": false, |
||||||
|
"darkStatusIconNight": false |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,26 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"themeName": "典雅蓝", |
||||||
|
"isNightTheme": false, |
||||||
|
"primaryColor": "#03A9F4", |
||||||
|
"accentColor": "#AD1457", |
||||||
|
"backgroundColor": "#F5F5F5", |
||||||
|
"bottomBackground": "#EEEEEE" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"themeName": "黑白", |
||||||
|
"isNightTheme": true, |
||||||
|
"primaryColor": "#303030", |
||||||
|
"accentColor": "#E0E0E0", |
||||||
|
"backgroundColor": "#424242", |
||||||
|
"bottomBackground": "#424242" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"themeName": "A屏黑", |
||||||
|
"isNightTheme": true, |
||||||
|
"primaryColor": "#000000", |
||||||
|
"accentColor": "#FFFFFF", |
||||||
|
"backgroundColor": "#000000", |
||||||
|
"bottomBackground": "#000000" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,163 @@ |
|||||||
|
# 帮助文档 |
||||||
|
|
||||||
|
## **新人必读** |
||||||
|
|
||||||
|
【温馨提醒】 *更新前一定要做好备份,以免数据丢失!* |
||||||
|
|
||||||
|
1. 为什么第一次安装好之后什么东西都没有? |
||||||
|
* 阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号[开源阅读]()、QQ群、酷安评论里获取由书友制作分享的书源。 |
||||||
|
|
||||||
|
2. 正文出现缺字漏字、内容缺失、排版错乱等情况,如何处理? |
||||||
|
* 有可能是净化规则出现问题,先关闭替换净化并刷新,再观察是否正常。如果正常说明净化规则存在误杀,如果关闭后仍然出现相关问题,请点击源链接查看原文与正文是否相同,如果不同,再进行反馈。 |
||||||
|
|
||||||
|
## 书源相关 |
||||||
|
|
||||||
|
1. 如何导入本地书源文件? |
||||||
|
* 下载群文件里的书源文件(书源格式后缀有txt、json,其中json文件某些情况下无法导入,需要修改后缀为txt格式才可导入); |
||||||
|
* 打开阅读软件; |
||||||
|
* 我的 - 点击“书源管理”; |
||||||
|
* 点击右上角选择“本地导入”; |
||||||
|
* 左下角选择书源文件所在的路径; |
||||||
|
* 点击书源文件导入; |
||||||
|
* 导入后返回书源管理界面; |
||||||
|
* 新版qq下载路径:Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/ |
||||||
|
|
||||||
|
 |
||||||
|
|
||||||
|
2. 如何新建大佬发的单独书源? |
||||||
|
* 复制书源代码; |
||||||
|
* 打开阅读软件; |
||||||
|
* 我的 - 点击“书源管理”; |
||||||
|
* 右上角选择“新建书源”; |
||||||
|
* 进入新建书源后点击右上角“粘贴源”; |
||||||
|
* 粘贴书源完成后点击上方保存; |
||||||
|
* 本次新建单独书源操作完成。 |
||||||
|
* 注:如果书源有错误或者复制不全会显示格式错误,请重新复制。 |
||||||
|
|
||||||
|
3. 为什么导入2.0书源后无法阅读? |
||||||
|
* 部分2.0书源并不适用于3.0版本的阅读,建议导入后进行筛选。 |
||||||
|
|
||||||
|
4. 阅读2.0数据如何导入阅读3.0? |
||||||
|
* 先对阅读2.0的数据进行备份,然后进入阅读3.0,点击“我的”,选择“备份与恢复”,再点击“导入旧版本数据”。 |
||||||
|
|
||||||
|
5. 如何给朋友分享我的书源? |
||||||
|
* 打开阅读软件; |
||||||
|
* 点击备份; |
||||||
|
* 打开手机自带的文件管理; |
||||||
|
* 手机自带内存根目录找到YueDu3.0文件夹; |
||||||
|
* 找到myBookSource.json长按选择分享; |
||||||
|
* 选择微信分享或者QQ分享; |
||||||
|
* 选择你要分享的好友点击发送; |
||||||
|
* 好友接收后在手机自带内存根目录找到myBookSource.json文件(QQ 安卓10及以下版本在Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/,安卓11版本用户由于系统限制无法访问data目录,微信在Tencent/MicroMsg/Download); |
||||||
|
* 复制该文件到手机自带内存根目录找到YueDu3.0文件夹(如已有该文件请先删除该文件或者备份到其他地方再复制到文件夹); |
||||||
|
* 打开阅读软件点击恢复。 |
||||||
|
* 注:备份路径如已修改过请在修改后的路径下查找书源文件。 |
||||||
|
|
||||||
|
6. 效验书源显示失效就说明书源不能用了吗? |
||||||
|
* 效验书源只是测试书源,可以做个参考,失效了不代表书源不能用了。 |
||||||
|
|
||||||
|
7. 发现和正版书源能不能使用? |
||||||
|
* 发现和正版书源只能用来找书,看排行榜,不能用来看书,如需看书请切换书源。 |
||||||
|
|
||||||
|
8. 为什么书源这么多,发现里却只有一点点? |
||||||
|
* 书源想要在发现界面里显示需要在书源里添加发现规则,并不是所有书源都有发现规则。 |
||||||
|
|
||||||
|
## 本地书籍相关 |
||||||
|
1. 目前阅读支持哪些格式的本地书籍? |
||||||
|
* 目前支持TXT、EPUB格式(只支持显示EPUB里的文本内容,还不支持显示图片) |
||||||
|
|
||||||
|
2. 如何导入本地书籍? |
||||||
|
* 在书架页面点击右上角,选择“添加本地”,授予相关权限后即可导入本地书籍。也可在文件管理器中使用 **阅读** 打开相关书籍。 |
||||||
|
|
||||||
|
3. 导入TXT文件提示“LoadTocError”或“List is empty”是怎么回事? |
||||||
|
* 请先去应用详情中确认是否授予了阅读“读写手机存储”的权限。 |
||||||
|
* 自动识别目录失败,可能是相关目录规则未开启,请点击右上角的换源按钮手动更换目录规则。 |
||||||
|
* 如果尝试所有规则均无法识别,请在github上提交issue并附件相关txt文件,也可以发送邮件至i@qnmlgb.trade(标题:legado本地文件章节无法识别,内容对其具体情况进行简要说明,附件上传相关txt文件)。 |
||||||
|
|
||||||
|
4. 如何下载书籍到本地? |
||||||
|
* 把在线书籍加入到书架后,在书架页面点击右上角,选择“离线缓存”即可。 |
||||||
|
|
||||||
|
5. 为什么我打开本地的TXT文件,显示内容却是乱码? |
||||||
|
* 部分编码在阅读上会识别错误,建议先用文本编辑器转换为常用的UTF-8格式。 |
||||||
|
|
||||||
|
6. 阅读对部分把正文(如所有含引号的句子)识别成标题,如何解决? |
||||||
|
* 点击右上角更换目录规则即可。 |
||||||
|
|
||||||
|
## 书籍界面相关 |
||||||
|
|
||||||
|
1. 如何刷新书架? |
||||||
|
* 在书架界面下拉即可刷新。 |
||||||
|
|
||||||
|
2. 书架界面书籍右上角的红色或者灰色背景小数字代表什么? |
||||||
|
* 红色代表书籍有更新,灰色代表无更新,数字代表未读章节。 |
||||||
|
|
||||||
|
3. 如何查看书籍详情? |
||||||
|
* 长按书籍。 |
||||||
|
|
||||||
|
4. 如何对书架上的书进行删除、切换书架的操作? |
||||||
|
* 书籍详情页操作即可。 |
||||||
|
|
||||||
|
5. 如何禁止或允许某本书更新? |
||||||
|
* 书籍详情页,点击右上角 - “允许更新”。 |
||||||
|
|
||||||
|
6. 如何更换小说封面、名字、作者或简介? |
||||||
|
* 书籍详情页,点击右上角修改按钮。 |
||||||
|
|
||||||
|
7. 怎么使用自定义字体? |
||||||
|
* 阅读界面 - 字体-点击右上角选择字体文件路径。 |
||||||
|
|
||||||
|
8. 目前支持哪些格式的字体文件? |
||||||
|
* 目前支持ttf、otf格式。 |
||||||
|
|
||||||
|
9. 书籍经常“正在加载中”怎么办? |
||||||
|
* 在线书籍出现这个问题通常是由于源质量不好或不兼容引起的,可以换其它源多试试;本地书籍出现这个问题大概率是目录规则问题,手动切换规则可以解决。 |
||||||
|
|
||||||
|
10. 书籍内容只有标题,正文内容是路径怎么办? |
||||||
|
* 通常是缓存路径引起的,更换缓存路径即可。 |
||||||
|
|
||||||
|
11. 看书时如遇到“目录为空”、“加载失败”和长串英文等情况怎么办? |
||||||
|
* 在线书籍一般是书源问题,切换或更新书源即可。本地书籍请尝试手动更换目录规则。 |
||||||
|
|
||||||
|
## 替换净化相关 |
||||||
|
1. 替换净化是什么? |
||||||
|
* 替换净化可以去除书籍内容里的广告、错别字、屏蔽词等。 |
||||||
|
|
||||||
|
2. 如何自己填写净化替换规则? |
||||||
|
* 第一行:替换规则名称 - 根据自己需求对替换净化规则进行命名; |
||||||
|
* 第二行:分组 - 净化规则的分组组别; |
||||||
|
* 第三行:替换规则 - 填写需要被替换的内容; |
||||||
|
* 第四行:替换为 - 填写想替换成的内容(如不填则默认表示删除第二行里填写的内容); |
||||||
|
* 第五行:替换范围,选填书名或者源名 - 填写此替换净化规则需要对哪本书籍或者哪个书源生效(如不填则对所有书籍和书源生效)。 |
||||||
|
* 注:如常规去除方法去除不掉,则需要勾选“使用正则表达式”,同时第二行里的替换规则也需要按照正则表达式来填写(正则表达式填写方法可自行百度学习)。 |
||||||
|
|
||||||
|
|
||||||
|
## 备份相关 |
||||||
|
|
||||||
|
1. 云备份在哪? |
||||||
|
* 我的 - 备份与恢复 - WebDav设置。 |
||||||
|
|
||||||
|
2. 如何操作进行云备份? |
||||||
|
* 侧栏设置,WebDav设置; |
||||||
|
* 正确填写WebDAV 服务器地址、WebDAV 账号、WebDAV 密码;(要获得这三项的信息,需要注册一个坚果云账号,如果直接在手机上注册,坚果云会让你下载app,过程比较麻烦,为了一步到位,最好是在电脑上打开这个注册链接:https://www.jianguoyun.com/d/signup ;注册后,进入坚果云;点击右上角账户名处选择 “账户信息”,然后选择“安全选项”;在“安全选项” 中找到“第三方应用管理”,并选择“添加应用”,输入名称如“阅读”后,会生成密码,选择完成;其中 https://dav.jianguoyun.com/dav/ 就是填入“WebDAV 服务器地址”的内容,“使用情况”后面的邮箱地址就是你的“WebDAV 账号”,点击显示密码后得到的密码就是你的“WebDAV 密码”。) |
||||||
|
* 无需操作,APP默认每天自动云备份一次。 |
||||||
|
|
||||||
|
3. 关于云备份的相关说明 |
||||||
|
* 在正确设置好云备份的情况下,APP默认每天自动云备份一次,当日多次手动云备份会对当日的旧云备份文件进行覆盖,并不会覆盖之前及之后不同日期的备份文件,每天所自动云备份的文件会按照日期进行命名。 |
||||||
|
|
||||||
|
4. 本地备份和云备份都能备份哪些东西? |
||||||
|
* 书架、看书进度、搜索记录、书源、替换、APP设置等都会备份,基本涵盖所有内容。 |
||||||
|
|
||||||
|
5. 出现某些未知bug怎么办? |
||||||
|
* 清除软件数据试试看,不行再进行反馈。 |
||||||
|
|
||||||
|
|
||||||
|
## 其他 |
||||||
|
1. 如何听书? |
||||||
|
* 可以使用手机自带的朗读引擎,也可使用第三方如谷歌、小米等朗读引擎。 |
||||||
|
* 【具体操作:安装-系统设置-其他高级设置-辅助功能-TTS输出-选择安装的朗读引擎(不同品牌手机的操作方法及步骤也不同,视情况而定)。】 |
||||||
|
|
||||||
|
2. 如何设置屏幕方向、屏幕显示时长、显示/隐藏状态栏、显示/隐藏导航栏、音量键翻页、长按选择文本、点击总是翻下一页、自定义翻页案件? |
||||||
|
* 阅读界面,设置(可上划,下面还有其他设置)。 |
||||||
|
|
||||||
|
3. 搜索的时候感觉手机卡顿,如何解决? |
||||||
|
* 我的 - 其他设置 - “更新和搜索线程数”调低。 |
@ -0,0 +1,15 @@ |
|||||||
|
# 在线朗读规则说明 |
||||||
|
|
||||||
|
* 在线朗读规则为url规则,同书源url |
||||||
|
* js参数 |
||||||
|
~~~ |
||||||
|
speakText //朗读文本 |
||||||
|
speakSpeed //朗读速度,0-45 |
||||||
|
~~~ |
||||||
|
* 例: |
||||||
|
~~~ |
||||||
|
http://tts.baidu.com/text2audio,{ |
||||||
|
"method": "POST", |
||||||
|
"body": "tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{String((speakSpeed + 5) / 10 + 4)}}&per=5003&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=1&vol=5&pit=5&_res_tag_=audio" |
||||||
|
} |
||||||
|
~~~ |
@ -1,72 +0,0 @@ |
|||||||
[ |
|
||||||
{ |
|
||||||
"bgStr": "羊皮纸2.jpg", |
|
||||||
"bgType": 1, |
|
||||||
"darkStatusIcon": true, |
|
||||||
"textColor": "#5E432E", |
|
||||||
"textSize": 22, |
|
||||||
"letterSpacing": 0, |
|
||||||
"lineSpacingExtra": 10, |
|
||||||
"lineSpacingMultiplier": 1.2, |
|
||||||
"paddingLeft": 16, |
|
||||||
"paddingRight": 16, |
|
||||||
"paddingTop": 0, |
|
||||||
"paddingBottom": 0 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"bgStr": "新羊皮纸.jpg", |
|
||||||
"bgType": 1, |
|
||||||
"darkStatusIcon": true, |
|
||||||
"textColor": "#5E432E", |
|
||||||
"textSize": 22, |
|
||||||
"letterSpacing": 0, |
|
||||||
"lineSpacingExtra": 10, |
|
||||||
"lineSpacingMultiplier": 1.2, |
|
||||||
"paddingLeft": 16, |
|
||||||
"paddingRight": 16, |
|
||||||
"paddingTop": 0, |
|
||||||
"paddingBottom": 0 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"bgStr": "#015A86", |
|
||||||
"bgType": 0, |
|
||||||
"darkStatusIcon": false, |
|
||||||
"textColor": "#FFFFFF", |
|
||||||
"textSize": 22, |
|
||||||
"letterSpacing": 0, |
|
||||||
"lineSpacingExtra": 10, |
|
||||||
"lineSpacingMultiplier": 1.2, |
|
||||||
"paddingLeft": 16, |
|
||||||
"paddingRight": 16, |
|
||||||
"paddingTop": 0, |
|
||||||
"paddingBottom": 0 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"bgStr": "宁静夜色", |
|
||||||
"bgType": 1, |
|
||||||
"darkStatusIcon": false, |
|
||||||
"textColor": "#adadad", |
|
||||||
"textSize": 22, |
|
||||||
"letterSpacing": 0, |
|
||||||
"lineSpacingExtra": 10, |
|
||||||
"lineSpacingMultiplier": 1.2, |
|
||||||
"paddingLeft": 16, |
|
||||||
"paddingRight": 16, |
|
||||||
"paddingTop": 0, |
|
||||||
"paddingBottom": 0 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"bgStr": "#000000", |
|
||||||
"bgType": 0, |
|
||||||
"darkStatusIcon": false, |
|
||||||
"textColor": "#adadad", |
|
||||||
"textSize": 22, |
|
||||||
"letterSpacing": 0, |
|
||||||
"lineSpacingExtra": 10, |
|
||||||
"lineSpacingMultiplier": 1.2, |
|
||||||
"paddingLeft": 16, |
|
||||||
"paddingRight": 16, |
|
||||||
"paddingTop": 0, |
|
||||||
"paddingBottom": 0 |
|
||||||
} |
|
||||||
] |
|
@ -1,38 +0,0 @@ |
|||||||
[ |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则1", |
|
||||||
"rule": "^(.{0,8})(第)([0-9零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10})([章节卷集部篇回场])(.{0,30})$", |
|
||||||
"serialNumber": 0 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则2", |
|
||||||
"rule": "^([0-9]{1,5})([\\,\\.,-])(.{1,20})$", |
|
||||||
"serialNumber": 1 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则3", |
|
||||||
"rule": "^(\\s{0,4})([\\(【《]?(卷)?)([0-9零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10})([\\.:: \f\t])(.{0,30})$", |
|
||||||
"serialNumber": 2 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则4", |
|
||||||
"rule": "^(\\s{0,4})([\\((【《])(.{0,30})([\\))】》])(\\s{0,2})$", |
|
||||||
"serialNumber": 3 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则5", |
|
||||||
"rule": "^(\\s{0,4})(正文)(.{0,20})$", |
|
||||||
"serialNumber": 4 |
|
||||||
}, |
|
||||||
{ |
|
||||||
"enable": true, |
|
||||||
"name": "默认正则6", |
|
||||||
"rule": "^(.{0,4})(Chapter|chapter)(\\s{0,4})([0-9]{1,4})(.{0,30})$", |
|
||||||
"serialNumber": 5 |
|
||||||
} |
|
||||||
] |
|
@ -1,5 +1,213 @@ |
|||||||
## 本软件为开源软件,没有上架Google Play,请不要在任何地方购买! |
# 更新日志 |
||||||
### 关注公众号[开源阅读软件]点击广告可支持作者! |
* 关注公众号 **[开源阅读]()** 菜单•软件下载 提前享受新版本。 |
||||||
### 捐赠里点击红包搜索码可开启高级功能! |
* 关注合作公众号 **[小说拾遗]()** 获取好看的小说。 |
||||||
## 更新日志 |
* 旧版数据导入教程:先在旧版阅读(2.x)中进行备份,然后在新版阅读(3.x)【我的】->【备份与恢复】,选择【导入旧版本数据】。 |
||||||
|
|
||||||
|
**2020/11/03** |
||||||
|
* 详情页菜单添加拷贝URL |
||||||
|
* 解决一些书名太长缓存报错的bug |
||||||
|
|
||||||
|
**2020/11/01** |
||||||
|
* 导入本地添加智能扫描,菜单-智能扫描,扫描当前文件夹包括子文件夹下所有文件 |
||||||
|
|
||||||
|
**2020/10/30** |
||||||
|
* 修复bug |
||||||
|
* 优化Android 11文件选择,本地导入 |
||||||
|
|
||||||
|
**2020/10/28** |
||||||
|
* 修复SDK 30使用TTS问题 |
||||||
|
|
||||||
|
**2020/10/27** |
||||||
|
* 点击书籍分组可显示书籍数量 |
||||||
|
* 升级到SDK30 |
||||||
|
* 修复8.0不显示默认背景图片的bug |
||||||
|
* 添加排版命名 |
||||||
|
|
||||||
|
**2020/10/24** |
||||||
|
* 修复选择错误的bug |
||||||
|
* 修复长图最后一张不能滚动的bug |
||||||
|
* js添加java.getCookie(sourceUrl:String, key:String? = null)来获取登录后的cookie by [AndyBernie](https://github.com/AndyBernie) |
||||||
|
``` |
||||||
|
java.getCookie("http://baidu.com", null) => userid=1234;pwd=adbcd |
||||||
|
java.getCookie("http://baidu.com", "userid") => 1234 |
||||||
|
``` |
||||||
|
* 修复简繁转换没有处理标题 |
||||||
|
* 每本书可以单独设置翻页动画,在菜单里 |
||||||
|
* 添加重新分段功能,针对每本书,在菜单里,分段代码来自[tumuyan](https://github.com/tumuyan) |
||||||
|
|
||||||
|
**2020/10/21** |
||||||
|
* 默认分组无书籍时自动隐藏 |
||||||
|
* 自定义翻页按键支持多个按键 |
||||||
|
|
||||||
|
**2020/10/19** |
||||||
|
* 优化分组管理 |
||||||
|
* 修复预下载没有保存的bug |
||||||
|
|
||||||
|
**2020/10/18** |
||||||
|
* 优化分组管理,默认分组可以重命名了 |
||||||
|
* 修复书架空白的bug,是constraintlayout库新版本的bug |
||||||
|
* 修复分组和崩溃bug |
||||||
|
|
||||||
|
**2020/10/16** |
||||||
|
* 修复排版导入背景失败bug |
||||||
|
* 修改默认度逍遥per为5003,需要重新导入默认 |
||||||
|
* 优化规则解析 |
||||||
|
|
||||||
|
**2020/10/14** |
||||||
|
* 优化替换规则编辑界面 |
||||||
|
* 修复网格书架间距变大bug |
||||||
|
* 其它一些优化,bug修复 |
||||||
|
|
||||||
|
**2020/10/13** |
||||||
|
* 更新android studio 到 4.1 |
||||||
|
* 书架整理增加滑动选择 |
||||||
|
|
||||||
|
**2020/10/12** |
||||||
|
* 优化预下载,防止同时下载太多卡顿 |
||||||
|
|
||||||
|
**2020/10/11** |
||||||
|
* 优化书源校验 |
||||||
|
* 语言切换bug修复 by [h11128](https://github.com/h11128) |
||||||
|
|
||||||
|
**2020/10/07** |
||||||
|
* 更新时预下载10章 |
||||||
|
* 支持更多分组 |
||||||
|
* url添加js参数,解析url时执行,可在访问url时处理url,例 |
||||||
|
``` |
||||||
|
https://www.baidu.com,{"js":"java.headerMap.put('xxx', 'yyy')"} |
||||||
|
https://www.baidu.com,{"js":"java.url=java.url+'yyyy'"} |
||||||
|
``` |
||||||
|
* 修复bug |
||||||
|
|
||||||
|
**2020/10/02** |
||||||
|
* 优化规则解析 |
||||||
|
* 优化正文搜索 |
||||||
|
* 翻页动画跟随背景 |
||||||
|
* 双击发现折叠发现,再次双击滚动至顶端 |
||||||
|
* 修复bug |
||||||
|
|
||||||
|
**2020/09/29** |
||||||
|
* 增加了几个方法用于处理文件 by [Celeter](https://github.com/Celeter) |
||||||
|
``` |
||||||
|
//文件下载,content为十六进制字符串,url用于生成文件名,返回文件路径 |
||||||
|
downloadFile(content: String, url: String): String |
||||||
|
//文件解压,zipPath为压缩文件路径,返回解压路径 |
||||||
|
unzipFile(zipPath: String): String |
||||||
|
//文件夹内所有文件读取 |
||||||
|
getTxtInFolder(unzipPath: String): String |
||||||
|
``` |
||||||
|
* 增加type字段,返回16进制字符串,例:`https://www.baidu.com,{"type":"zip"}` |
||||||
|
* 底部操作栏阴影跟随设置调节 |
||||||
|
|
||||||
|
**2020/09/24** |
||||||
|
* 修复规则解析bug |
||||||
|
|
||||||
|
**2020/09/21** |
||||||
|
* 修复规则解析bug |
||||||
|
* 换源时无最新章节信息时可加载详情页来获取(默认关闭) |
||||||
|
|
||||||
|
**2020/09/20** |
||||||
|
* 优化正文搜索 |
||||||
|
* 阅读界面信息添加书名 |
||||||
|
|
||||||
|
**2020/09/18** |
||||||
|
* 解决正文替换{{title}}问题 |
||||||
|
* 修复共用布局配置不能读取的问题 |
||||||
|
* 添加自定义源分组功能 by KKL369 |
||||||
|
* 解决跨进程调用ReaderProvider出现CursorIndexOutOfBoundsException问题 |
||||||
|
|
||||||
|
**2020/09/17** |
||||||
|
* 优化正文搜索文字颜色 |
||||||
|
* 优化书源校验 by KKL369 |
||||||
|
* 缓存导出到webDav by 10bits |
||||||
|
* 导入的字体在字体选择界面显示 |
||||||
|
|
||||||
|
**2020/09/15** |
||||||
|
* 修复导入排版字体重复报错的bug |
||||||
|
* 添加正文搜索 by [h11128](https://github.com/h11128) |
||||||
|
|
||||||
|
**2020/09/12** |
||||||
|
* web看书同步最新章 |
||||||
|
* web写源增加图片样式等规则 |
||||||
|
* 正文规则可以使用@get:{title}获取目录标题,js里使用title |
||||||
|
|
||||||
|
**2020/09/11** |
||||||
|
* 修复一些bug |
||||||
|
* 背景配置自由添加 |
||||||
|
|
||||||
|
**2020/09/10** |
||||||
|
* 修复自动换源的bug |
||||||
|
* 修复保存主题的bug |
||||||
|
* 书源排序,分享,注释优化 by [h11128](https://github.com/h11128) |
||||||
|
|
||||||
|
**2020/09/09** |
||||||
|
* 修复主题导入导出bug |
||||||
|
* 优化分屏模式状态栏 |
||||||
|
* 书源基本属性增加“书源注释” |
||||||
|
|
||||||
|
**2020/09/08** |
||||||
|
* 页眉页脚跟随背景 |
||||||
|
* 主题导入导出 |
||||||
|
|
||||||
|
**2020/09/07** |
||||||
|
* 订阅源和替换规则添加滑动选择 |
||||||
|
* 修复排版配置导入导出 |
||||||
|
* 订阅界面添加下载文件功能 |
||||||
|
|
||||||
|
**2020/09/06** |
||||||
|
* 优化翻页 |
||||||
|
* EInk模式独立背景 |
||||||
|
* 阅读排版配置导入导出,包括背景和字体,支持网络导入 |
||||||
|
|
||||||
|
**2020/09/03** |
||||||
|
* 修复替换中的回车消失的bug |
||||||
|
* 所有内容恢复htmlFormat, 在想其它办法解决丢失一些内容的问题 |
||||||
|
* 图片(漫画)支持导出 |
||||||
|
|
||||||
|
**2020/09/02** |
||||||
|
* 搜索url支持put,get,js里使用java.put,java.get |
||||||
|
|
||||||
|
* 正文合并后替换规则支持所有规则写法,包括js |
||||||
|
|
||||||
|
**2020/09/01** |
||||||
|
* 导入书源列表添加全不选 |
||||||
|
* 详情页菜单添加清理缓存,清理当前书籍缓存 |
||||||
|
* 修复滑动选择,选择数量不更新的bug |
||||||
|
* 字体跟随背景,每个背景对应一个字体 |
||||||
|
* 优化图片下载 |
||||||
|
|
||||||
|
**功能介绍** |
||||||
|
* 书源调试 |
||||||
|
- 调试搜索>>输入关键字,如:`系统` |
||||||
|
- 调试发现>>输入发现URL,如:`月票榜::https://www.qidian.com/rank/yuepiao?page={{page}}` |
||||||
|
- 调试详情页>>输入详情页URL,如:`https://m.qidian.com/book/1015609210` |
||||||
|
- 调试目录页>>输入目录页URL,如:`++https://www.zhaishuyuan.com/read/30394` |
||||||
|
- 调试正文页>>输入正文页URL,如:`--https://www.zhaishuyuan.com/chapter/30394/20940996` |
||||||
|
* 修改订阅中自动添加style的情景 |
||||||
|
订阅源的内容规则中存在`<style>`或`style=`时,直接显示内容规则的原始内容 |
||||||
|
* 请求头,支持http代理,socks4 socks5代理设置 by [10bits](https://github.com/10bits) |
||||||
|
``` |
||||||
|
socks5代理 |
||||||
|
{ |
||||||
|
"proxy":"socks5://127.0.0.1:1080" |
||||||
|
} |
||||||
|
http代理 |
||||||
|
{ |
||||||
|
"proxy":"http://127.0.0.1:1080" |
||||||
|
} |
||||||
|
支持代理服务器验证 |
||||||
|
{ |
||||||
|
"proxy":"socks5://127.0.0.1:1080@用户名@密码" |
||||||
|
} |
||||||
|
注意:这些请求头是无意义的,会被忽略掉 |
||||||
|
``` |
||||||
|
* 对于搜索重定向的源,可以使用此方法获得重定向后的url |
||||||
|
``` |
||||||
|
<js> |
||||||
|
var url='https://www.yooread.net/e/search/index.php,'+JSON.stringify({ |
||||||
|
"method":"POST", |
||||||
|
"body":"show=title&tempid=1&keyboard="+key |
||||||
|
}); |
||||||
|
String(java.connect(url).raw().request().url()) |
||||||
|
</js> |
||||||
|
``` |
@ -0,0 +1 @@ |
|||||||
|
#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;color:#2c3e50;margin:0;height:100%} |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 4.6 KiB |
After Width: | Height: | Size: 799 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 5.8 KiB |
@ -0,0 +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"><!--[if IE]><link rel="icon" href="favicon.ico" /><![endif]--><title>Legado Bookshelf</title><link href=css/about.dbe575e1.css rel=prefetch><link href=css/detail.ef664f74.css rel=prefetch><link href=js/about.b239b102.js rel=prefetch><link href=js/about~detail.1caf6ef5.js rel=prefetch><link href=js/detail.06210052.js rel=prefetch><link href=css/app.e4c919b7.css rel=preload as=style><link href=css/chunk-vendors.ad4ff18f.css rel=preload as=style><link href=js/app.f319fc97.js rel=preload as=script><link href=js/chunk-vendors.8dd9045a.js rel=preload as=script><link href=css/chunk-vendors.ad4ff18f.css rel=stylesheet><link href=css/app.e4c919b7.css rel=stylesheet><link rel=icon type=image/png sizes=32x32 href=img/icons/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=img/icons/favicon-16x16.png><link rel=manifest href=manifest.json><meta name=theme-color content=#4DBA87><meta name=apple-mobile-web-app-capable content=no><meta name=apple-mobile-web-app-status-bar-style content=default><meta name=apple-mobile-web-app-title content=yd-web-tool><link rel=apple-touch-icon href=img/icons/apple-touch-icon-152x152.png><link rel=mask-icon href=img/icons/safari-pinned-tab.svg color=#4DBA87><meta name=msapplication-TileImage content=img/icons/msapplication-icon-144x144.png><meta name=msapplication-TileColor content=#000000></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.8dd9045a.js></script><script src=js/app.f319fc97.js></script></body></html> |
@ -0,0 +1 @@ |
|||||||
|
{"name":"yd-web-tool","short_name":"yd-web-tool","theme_color":"#4DBA87","icons":[{"src":"./img/icons/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"./img/icons/android-chrome-512x512.png","sizes":"512x512","type":"image/png"},{"src":"./img/icons/android-chrome-maskable-192x192.png","sizes":"192x192","type":"image/png","purpose":"maskable"},{"src":"./img/icons/android-chrome-maskable-512x512.png","sizes":"512x512","type":"image/png","purpose":"maskable"}],"start_url":".","display":"standalone","background_color":"#000000"} |
@ -0,0 +1,74 @@ |
|||||||
|
self.__precacheManifest = (self.__precacheManifest || []).concat([ |
||||||
|
{ |
||||||
|
"revision": "1f198e66ea99b77b82a1", |
||||||
|
"url": "css/about.dbe575e1.css" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "e82f63018b8756547377", |
||||||
|
"url": "css/app.e4c919b7.css" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "3e91096748e0f4d6bb89", |
||||||
|
"url": "css/chunk-vendors.ad4ff18f.css" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "f2d5bf5a45e7429367f8", |
||||||
|
"url": "css/detail.ef664f74.css" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "535877f50039c0cb49a6196a5b7517cd", |
||||||
|
"url": "fonts/element-icons.535877f5.woff" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "732389ded34cb9c52dd88271f1345af9", |
||||||
|
"url": "fonts/element-icons.732389de.ttf" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "f9a3fb0e145017e166dd4d91d9280cc4", |
||||||
|
"url": "fonts/iconfont.f9a3fb0e.woff" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "f39ecc1a1d2a1eff3aca8aadd818bb61", |
||||||
|
"url": "fonts/popfont.f39ecc1a.ttf" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "6c094b6d4ae9404dbed273c41b06fae8", |
||||||
|
"url": "fonts/shelffont.6c094b6d.ttf" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "b5c48bc1e1fe73212a31be704875b71f", |
||||||
|
"url": "img/noCover.b5c48bc1.jpeg" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "48e76635babe1b6abdaface8af25dd98", |
||||||
|
"url": "index.html" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "1f198e66ea99b77b82a1", |
||||||
|
"url": "js/about.b239b102.js" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "2c81bd893f3a92f018d8", |
||||||
|
"url": "js/about~detail.1caf6ef5.js" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "e82f63018b8756547377", |
||||||
|
"url": "js/app.f319fc97.js" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "3e91096748e0f4d6bb89", |
||||||
|
"url": "js/chunk-vendors.8dd9045a.js" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "f2d5bf5a45e7429367f8", |
||||||
|
"url": "js/detail.06210052.js" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "b46d04eb43bc31ca0f9f95121646440d", |
||||||
|
"url": "manifest.json" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"revision": "b6216d61c03e6ce0c9aea6ca7808f7ca", |
||||||
|
"url": "robots.txt" |
||||||
|
} |
||||||
|
]); |
@ -0,0 +1,2 @@ |
|||||||
|
User-agent: * |
||||||
|
Disallow: |
@ -0,0 +1,34 @@ |
|||||||
|
/** |
||||||
|
* Welcome to your Workbox-powered service worker! |
||||||
|
* |
||||||
|
* You'll need to register this file in your web app and you should |
||||||
|
* disable HTTP caching for this file too. |
||||||
|
* See https://goo.gl/nhQhGp
|
||||||
|
* |
||||||
|
* The rest of the code is auto-generated. Please don't update this file |
||||||
|
* directly; instead, make changes to your Workbox build configuration |
||||||
|
* and re-run your build process. |
||||||
|
* See https://goo.gl/2aRDsh
|
||||||
|
*/ |
||||||
|
|
||||||
|
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); |
||||||
|
|
||||||
|
importScripts( |
||||||
|
"precache-manifest.64ecbb9cbd290bcd22476b715a2e6c05.js" |
||||||
|
); |
||||||
|
|
||||||
|
workbox.core.setCacheNameDetails({prefix: "yd-web-tool"}); |
||||||
|
|
||||||
|
self.addEventListener('message', (event) => { |
||||||
|
if (event.data && event.data.type === 'SKIP_WAITING') { |
||||||
|
self.skipWaiting(); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
/** |
||||||
|
* The workboxSW.precacheAndRoute() method efficiently caches and responds to |
||||||
|
* requests for URLs in the manifest. |
||||||
|
* See https://goo.gl/S9QRab
|
||||||
|
*/ |
||||||
|
self.__precacheManifest = [].concat(self.__precacheManifest || []); |
||||||
|
workbox.precaching.precacheAndRoute(self.__precacheManifest, {}); |
@ -0,0 +1,12 @@ |
|||||||
|
# 文件结构介绍 |
||||||
|
|
||||||
|
* base 基类 |
||||||
|
* constant 常量 |
||||||
|
* data 数据 |
||||||
|
* help 帮助 |
||||||
|
* lib 库 |
||||||
|
* model 解析 |
||||||
|
* receiver 广播侦听 |
||||||
|
* service 服务 |
||||||
|
* ui 界面 |
||||||
|
* web web服务 |
@ -0,0 +1,124 @@ |
|||||||
|
/* |
||||||
|
* Copyright (C) 2020 w568w |
||||||
|
*/ |
||||||
|
package io.legado.app.api |
||||||
|
|
||||||
|
import android.content.ContentProvider |
||||||
|
import android.content.ContentValues |
||||||
|
import android.content.UriMatcher |
||||||
|
import android.database.Cursor |
||||||
|
import android.database.MatrixCursor |
||||||
|
import android.net.Uri |
||||||
|
import com.google.gson.Gson |
||||||
|
import io.legado.app.api.controller.BookshelfController |
||||||
|
import io.legado.app.api.controller.SourceController |
||||||
|
import io.legado.app.web.utils.ReturnData |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
/** |
||||||
|
* Export book data to other app. |
||||||
|
*/ |
||||||
|
class ReaderProvider : ContentProvider() { |
||||||
|
private enum class RequestCode { |
||||||
|
SaveSource, SaveSources, SaveBook, DeleteSources, GetSource, GetSources, GetBookshelf, GetChapterList, GetBookContent |
||||||
|
} |
||||||
|
|
||||||
|
private val postBodyKey = "json" |
||||||
|
private val sMatcher by lazy { |
||||||
|
UriMatcher(UriMatcher.NO_MATCH).apply { |
||||||
|
"${context?.applicationInfo?.packageName}.readerProvider".also { authority -> |
||||||
|
addURI(authority, "source/insert", RequestCode.SaveSource.ordinal) |
||||||
|
addURI(authority, "sources/insert", RequestCode.SaveSources.ordinal) |
||||||
|
addURI(authority, "book/insert", RequestCode.SaveBook.ordinal) |
||||||
|
addURI(authority, "sources/delete", RequestCode.DeleteSources.ordinal) |
||||||
|
addURI(authority, "source/query", RequestCode.GetSource.ordinal) |
||||||
|
addURI(authority, "sources/query", RequestCode.GetSources.ordinal) |
||||||
|
addURI(authority, "books/query", RequestCode.GetBookshelf.ordinal) |
||||||
|
addURI(authority, "book/chapter/query", RequestCode.GetChapterList.ordinal) |
||||||
|
addURI(authority, "book/content/query", RequestCode.GetBookContent.ordinal) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onCreate() = false |
||||||
|
|
||||||
|
override fun delete( |
||||||
|
uri: Uri, |
||||||
|
selection: String?, |
||||||
|
selectionArgs: Array<String>? |
||||||
|
): Int { |
||||||
|
if (sMatcher.match(uri) < 0) return -1 |
||||||
|
when (RequestCode.values()[sMatcher.match(uri)]) { |
||||||
|
RequestCode.DeleteSources -> SourceController.deleteSources(selection) |
||||||
|
else -> throw IllegalStateException( |
||||||
|
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name |
||||||
|
) |
||||||
|
} |
||||||
|
return 0 |
||||||
|
} |
||||||
|
|
||||||
|
override fun getType(uri: Uri) = throw UnsupportedOperationException("Not yet implemented") |
||||||
|
|
||||||
|
override fun insert(uri: Uri, values: ContentValues?): Uri? { |
||||||
|
if (sMatcher.match(uri) < 0) return null |
||||||
|
when (RequestCode.values()[sMatcher.match(uri)]) { |
||||||
|
RequestCode.SaveSource -> values?.let { |
||||||
|
SourceController.saveSource(values.getAsString(postBodyKey)) |
||||||
|
} |
||||||
|
RequestCode.SaveBook -> values?.let { |
||||||
|
BookshelfController.saveBook(values.getAsString(postBodyKey)) |
||||||
|
} |
||||||
|
RequestCode.SaveSources -> values?.let { |
||||||
|
SourceController.saveSources(values.getAsString(postBodyKey)) |
||||||
|
} |
||||||
|
else -> throw IllegalStateException( |
||||||
|
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name |
||||||
|
) |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
override fun query( |
||||||
|
uri: Uri, projection: Array<String>?, selection: String?, |
||||||
|
selectionArgs: Array<String>?, sortOrder: String? |
||||||
|
): Cursor? { |
||||||
|
val map: MutableMap<String, ArrayList<String>> = HashMap() |
||||||
|
uri.getQueryParameter("url")?.let { |
||||||
|
map["url"] = arrayListOf(it) |
||||||
|
} |
||||||
|
uri.getQueryParameter("index")?.let { |
||||||
|
map["index"] = arrayListOf(it) |
||||||
|
} |
||||||
|
return if (sMatcher.match(uri) < 0) null else when (RequestCode.values()[sMatcher.match(uri)]) { |
||||||
|
RequestCode.GetSource -> SimpleCursor(SourceController.getSource(map)) |
||||||
|
RequestCode.GetSources -> SimpleCursor(SourceController.sources) |
||||||
|
RequestCode.GetBookshelf -> SimpleCursor(BookshelfController.bookshelf) |
||||||
|
RequestCode.GetBookContent -> SimpleCursor(BookshelfController.getBookContent(map)) |
||||||
|
RequestCode.GetChapterList -> SimpleCursor(BookshelfController.getChapterList(map)) |
||||||
|
else -> throw IllegalStateException( |
||||||
|
"Unexpected value: " + RequestCode.values()[sMatcher.match(uri)].name |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun update( |
||||||
|
uri: Uri, values: ContentValues?, selection: String?, |
||||||
|
selectionArgs: Array<String>? |
||||||
|
) = throw UnsupportedOperationException("Not yet implemented") |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Simple inner class to deliver json callback data. |
||||||
|
* |
||||||
|
* Only getString() makes sense. |
||||||
|
*/ |
||||||
|
private class SimpleCursor(data: ReturnData?) : MatrixCursor(arrayOf("result"), 1) { |
||||||
|
|
||||||
|
private val mData: String = Gson().toJson(data) |
||||||
|
|
||||||
|
init { |
||||||
|
addRow(arrayOf(mData)) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,106 @@ |
|||||||
|
package io.legado.app.api.controller |
||||||
|
|
||||||
|
import io.legado.app.App |
||||||
|
import io.legado.app.constant.PreferKey |
||||||
|
import io.legado.app.data.entities.Book |
||||||
|
import io.legado.app.help.BookHelp |
||||||
|
import io.legado.app.model.webBook.WebBook |
||||||
|
import io.legado.app.service.help.ReadBook |
||||||
|
import io.legado.app.utils.GSON |
||||||
|
import io.legado.app.utils.fromJsonObject |
||||||
|
import io.legado.app.utils.getPrefInt |
||||||
|
import io.legado.app.web.utils.ReturnData |
||||||
|
import kotlinx.coroutines.runBlocking |
||||||
|
|
||||||
|
object BookshelfController { |
||||||
|
|
||||||
|
val bookshelf: ReturnData |
||||||
|
get() { |
||||||
|
val books = App.db.bookDao().all |
||||||
|
val returnData = ReturnData() |
||||||
|
return if (books.isEmpty()) { |
||||||
|
returnData.setErrorMsg("还没有添加小说") |
||||||
|
} else { |
||||||
|
val data = when (App.INSTANCE.getPrefInt(PreferKey.bookshelfSort)) { |
||||||
|
1 -> books.sortedByDescending { it.latestChapterTime } |
||||||
|
2 -> books.sortedBy { it.name } |
||||||
|
3 -> books.sortedBy { it.order } |
||||||
|
else -> books.sortedByDescending { it.durChapterTime } |
||||||
|
} |
||||||
|
returnData.setData(data) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun getChapterList(parameters: Map<String, List<String>>): ReturnData { |
||||||
|
val bookUrl = parameters["url"]?.getOrNull(0) |
||||||
|
val returnData = ReturnData() |
||||||
|
if (bookUrl.isNullOrEmpty()) { |
||||||
|
return returnData.setErrorMsg("参数url不能为空,请指定书籍地址") |
||||||
|
} |
||||||
|
val chapterList = App.db.bookChapterDao().getChapterList(bookUrl) |
||||||
|
return returnData.setData(chapterList) |
||||||
|
} |
||||||
|
|
||||||
|
fun getBookContent(parameters: Map<String, List<String>>): ReturnData { |
||||||
|
val bookUrl = parameters["url"]?.getOrNull(0) |
||||||
|
val index = parameters["index"]?.getOrNull(0)?.toInt() |
||||||
|
val returnData = ReturnData() |
||||||
|
if (bookUrl.isNullOrEmpty()) { |
||||||
|
return returnData.setErrorMsg("参数url不能为空,请指定书籍地址") |
||||||
|
} |
||||||
|
if (index == null) { |
||||||
|
return returnData.setErrorMsg("参数index不能为空, 请指定目录序号") |
||||||
|
} |
||||||
|
val book = App.db.bookDao().getBook(bookUrl) |
||||||
|
val chapter = App.db.bookChapterDao().getChapter(bookUrl, index) |
||||||
|
if (book == null || chapter == null) { |
||||||
|
returnData.setErrorMsg("未找到") |
||||||
|
} else { |
||||||
|
val content: String? = BookHelp.getContent(book, chapter) |
||||||
|
if (content != null) { |
||||||
|
saveBookReadIndex(book, index) |
||||||
|
returnData.setData(content) |
||||||
|
} else { |
||||||
|
App.db.bookSourceDao().getBookSource(book.origin)?.let { source -> |
||||||
|
runBlocking { |
||||||
|
WebBook(source).getContentSuspend(book, chapter) |
||||||
|
}.let { |
||||||
|
saveBookReadIndex(book, index) |
||||||
|
returnData.setData(it) |
||||||
|
} |
||||||
|
} ?: returnData.setErrorMsg("未找到书源") |
||||||
|
} |
||||||
|
} |
||||||
|
return returnData |
||||||
|
} |
||||||
|
|
||||||
|
fun saveBook(postData: String?): ReturnData { |
||||||
|
val book = GSON.fromJsonObject<Book>(postData) |
||||||
|
val returnData = ReturnData() |
||||||
|
if (book != null) { |
||||||
|
App.db.bookDao().insert(book) |
||||||
|
if (ReadBook.book?.bookUrl == book.bookUrl) { |
||||||
|
ReadBook.book = book |
||||||
|
ReadBook.durChapterIndex = book.durChapterIndex |
||||||
|
} |
||||||
|
return returnData.setData("") |
||||||
|
} |
||||||
|
return returnData.setErrorMsg("格式不对") |
||||||
|
} |
||||||
|
|
||||||
|
private fun saveBookReadIndex(book: Book, index: Int) { |
||||||
|
if (index > book.durChapterIndex) { |
||||||
|
book.durChapterIndex = index |
||||||
|
book.durChapterTime = System.currentTimeMillis() |
||||||
|
App.db.bookChapterDao().getChapter(book.bookUrl, index)?.let { |
||||||
|
book.durChapterTitle = it.title |
||||||
|
} |
||||||
|
App.db.bookDao().update(book) |
||||||
|
if (ReadBook.book?.bookUrl == book.bookUrl) { |
||||||
|
ReadBook.book = book |
||||||
|
ReadBook.durChapterIndex = index |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package io.legado.app.base |
||||||
|
|
||||||
|
import android.os.Bundle |
||||||
|
import android.view.View |
||||||
|
import androidx.fragment.app.DialogFragment |
||||||
|
import androidx.fragment.app.FragmentManager |
||||||
|
import io.legado.app.help.coroutine.Coroutine |
||||||
|
import io.legado.app.lib.theme.ThemeStore |
||||||
|
import kotlinx.coroutines.CoroutineScope |
||||||
|
import kotlinx.coroutines.Dispatchers |
||||||
|
import kotlinx.coroutines.Job |
||||||
|
import kotlin.coroutines.CoroutineContext |
||||||
|
|
||||||
|
|
||||||
|
abstract class BaseDialogFragment : DialogFragment(), CoroutineScope { |
||||||
|
override val coroutineContext: CoroutineContext |
||||||
|
get() = job + Dispatchers.Main |
||||||
|
private lateinit var job: Job |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
job = Job() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
||||||
|
super.onViewCreated(view, savedInstanceState) |
||||||
|
view.setBackgroundColor(ThemeStore.backgroundColor()) |
||||||
|
onFragmentCreated(view, savedInstanceState) |
||||||
|
observeLiveBus() |
||||||
|
} |
||||||
|
|
||||||
|
abstract fun onFragmentCreated(view: View, savedInstanceState: Bundle?) |
||||||
|
|
||||||
|
override fun show(manager: FragmentManager, tag: String?) { |
||||||
|
try { |
||||||
|
//在每个add事务前增加一个remove事务,防止连续的add |
||||||
|
manager.beginTransaction().remove(this).commit() |
||||||
|
super.show(manager, tag) |
||||||
|
} catch (e: Exception) { |
||||||
|
//同一实例使用不同的tag会异常,这里捕获一下 |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroy() { |
||||||
|
super.onDestroy() |
||||||
|
job.cancel() |
||||||
|
} |
||||||
|
|
||||||
|
fun <T> execute( |
||||||
|
scope: CoroutineScope = this, |
||||||
|
context: CoroutineContext = Dispatchers.IO, |
||||||
|
block: suspend CoroutineScope.() -> T |
||||||
|
) = Coroutine.async(scope, context) { block() } |
||||||
|
|
||||||
|
open fun observeLiveBus() { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package io.legado.app.base |
||||||
|
|
||||||
|
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 |
||||||
|
|
||||||
|
abstract class BasePreferenceFragment : PreferenceFragmentCompat() { |
||||||
|
|
||||||
|
private val dialogFragmentTag = "androidx.preference.PreferenceFragment.DIALOG" |
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi") |
||||||
|
override fun onDisplayPreferenceDialog(preference: Preference) { |
||||||
|
|
||||||
|
var handled = false |
||||||
|
if (callbackFragment is OnPreferenceDisplayDialogCallback) { |
||||||
|
handled = |
||||||
|
(callbackFragment as OnPreferenceDisplayDialogCallback) |
||||||
|
.onPreferenceDisplayDialog(this, preference) |
||||||
|
} |
||||||
|
if (!handled && activity is OnPreferenceDisplayDialogCallback) { |
||||||
|
handled = (activity as OnPreferenceDisplayDialogCallback) |
||||||
|
.onPreferenceDisplayDialog(this, preference) |
||||||
|
} |
||||||
|
|
||||||
|
if (handled) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// check if dialog is already showing |
||||||
|
if (parentFragmentManager.findFragmentByTag(dialogFragmentTag) != null) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
val f: DialogFragment = when (preference) { |
||||||
|
is EditTextPreference -> { |
||||||
|
EditTextPreferenceDialog.newInstance(preference.getKey()) |
||||||
|
} |
||||||
|
is ListPreference -> { |
||||||
|
ListPreferenceDialog.newInstance(preference.getKey()) |
||||||
|
} |
||||||
|
is MultiSelectListPreference -> { |
||||||
|
MultiSelectListPreferenceDialog.newInstance(preference.getKey()) |
||||||
|
} |
||||||
|
else -> { |
||||||
|
throw IllegalArgumentException( |
||||||
|
"Cannot display dialog for an unknown Preference type: " |
||||||
|
+ preference.javaClass.simpleName |
||||||
|
+ ". Make sure to implement onPreferenceDisplayDialog() to handle " |
||||||
|
+ "displaying a custom dialog for this Preference." |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
f.setTargetFragment(this, 0) |
||||||
|
f.show(parentFragmentManager, dialogFragmentTag) |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -1 +1 @@ |
|||||||
## 基类 |
# 基类 |
@ -1,9 +1,14 @@ |
|||||||
package io.legado.app.base |
package io.legado.app.base |
||||||
|
|
||||||
import androidx.lifecycle.ViewModel |
import androidx.lifecycle.ViewModel |
||||||
|
import io.legado.app.constant.Theme |
||||||
abstract class VMBaseActivity<VM : ViewModel>(layoutID: Int, fullScreen: Boolean = true) : |
|
||||||
BaseActivity(layoutID, fullScreen) { |
abstract class VMBaseActivity<VM : ViewModel>( |
||||||
|
layoutID: Int, |
||||||
|
fullScreen: Boolean = true, |
||||||
|
theme: Theme = Theme.Auto, |
||||||
|
toolBarTheme: Theme = Theme.Auto |
||||||
|
) : BaseActivity(layoutID, fullScreen, theme, toolBarTheme) { |
||||||
|
|
||||||
protected abstract val viewModel: VM |
protected abstract val viewModel: VM |
||||||
|
|
||||||
|
@ -0,0 +1,17 @@ |
|||||||
|
package io.legado.app.constant |
||||||
|
|
||||||
|
import java.util.regex.Pattern |
||||||
|
|
||||||
|
@Suppress("RegExpRedundantEscape") |
||||||
|
object AppPattern { |
||||||
|
val JS_PATTERN: Pattern = |
||||||
|
Pattern.compile("(<js>[\\w\\W]*?</js>|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) |
||||||
|
val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") |
||||||
|
val imgPattern: Pattern = |
||||||
|
Pattern.compile("<img .*?src.*?=.*?\"(.*?(?:,\\{.*\\})?)\".*?>", Pattern.CASE_INSENSITIVE) |
||||||
|
|
||||||
|
val nameRegex = Regex("\\s+作\\s*者.*") |
||||||
|
val authorRegex = Regex(".*?作\\s*?者[::]") |
||||||
|
val fileNameRegex = Regex("[\\\\/:*?\"<>|.]") |
||||||
|
val splitGroupRegex = Regex("[,;,;]") |
||||||
|
} |
@ -1,7 +1,7 @@ |
|||||||
package io.legado.app.constant |
package io.legado.app.constant |
||||||
|
|
||||||
object BookType { |
object BookType { |
||||||
const val default = 0 |
const val default = 0 // 0 文本 |
||||||
const val audio = 1 |
const val audio = 1 // 1 音频 |
||||||
const val local = "loc_book" |
const val local = "loc_book" |
||||||
} |
} |
@ -1,16 +0,0 @@ |
|||||||
package io.legado.app.constant |
|
||||||
|
|
||||||
object Bus { |
|
||||||
const val RECREATE = "RECREATE" |
|
||||||
const val UP_BOOK = "sourceDebugLog" |
|
||||||
const val ALOUD_STATE = "aloud_state" |
|
||||||
const val TTS_START = "ttsStart" |
|
||||||
const val TTS_TURN_PAGE = "ttsTurnPage" |
|
||||||
const val TTS_DS = "ttsDs" |
|
||||||
const val BATTERY_CHANGED = "batteryChanged" |
|
||||||
const val TIME_CHANGED = "timeChanged" |
|
||||||
const val READ_ALOUD_BUTTON = "readAloudButton" |
|
||||||
const val UP_CONFIG = "upConfig" |
|
||||||
const val OPEN_CHAPTER = "openChapter" |
|
||||||
const val REPLACE = "replace" |
|
||||||
} |
|
@ -0,0 +1,26 @@ |
|||||||
|
package io.legado.app.constant |
||||||
|
|
||||||
|
object EventBus { |
||||||
|
const val MEDIA_BUTTON = "mediaButton" |
||||||
|
const val RECREATE = "RECREATE" |
||||||
|
const val UP_BOOK = "upBookToc" |
||||||
|
const val ALOUD_STATE = "aloud_state" |
||||||
|
const val TTS_PROGRESS = "ttsStart" |
||||||
|
const val TTS_DS = "ttsDs" |
||||||
|
const val BATTERY_CHANGED = "batteryChanged" |
||||||
|
const val TIME_CHANGED = "timeChanged" |
||||||
|
const val UP_CONFIG = "upConfig" |
||||||
|
const val OPEN_CHAPTER = "openChapter" |
||||||
|
const val AUDIO_SUB_TITLE = "audioSubTitle" |
||||||
|
const val AUDIO_STATE = "audioState" |
||||||
|
const val AUDIO_PROGRESS = "audioProgress" |
||||||
|
const val AUDIO_SIZE = "audioSize" |
||||||
|
const val AUDIO_SPEED = "audioSpeed" |
||||||
|
const val SHOW_RSS = "showRss" |
||||||
|
const val WEB_SERVICE = "webService" |
||||||
|
const val UP_DOWNLOAD = "upDownload" |
||||||
|
const val SAVE_CONTENT = "saveContent" |
||||||
|
const val CHECK_SOURCE = "checkSource" |
||||||
|
const val CHECK_SOURCE_DONE = "checkSourceDone" |
||||||
|
const val REPLACE_RULE_SAVE = "replaceRuleSave" |
||||||
|
} |
@ -1,8 +0,0 @@ |
|||||||
package io.legado.app.constant |
|
||||||
|
|
||||||
import java.util.regex.Pattern |
|
||||||
|
|
||||||
object Pattern { |
|
||||||
val JS_PATTERN: Pattern = Pattern.compile("(<js>[\\w\\W]*?</js>|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE) |
|
||||||
val EXP_PATTERN: Pattern = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}") |
|
||||||
} |
|