@ -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 |
||||
|
||||
[](http://commitizen.github.io/cz-cli/) |
||||
|
||||
## 阅读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> |
||||
<string name="app_name">阅读.debug</string> |
||||
<string name="receiving_shared_label">阅读.debug·搜索</string> |
||||
<string name="app_name">legado·D</string> |
||||
<string name="receiving_shared_label">legado·D·search</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">閱讀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 |
||||
|
||||
import androidx.lifecycle.ViewModel |
||||
|
||||
abstract class VMBaseActivity<VM : ViewModel>(layoutID: Int, fullScreen: Boolean = true) : |
||||
BaseActivity(layoutID, fullScreen) { |
||||
import io.legado.app.constant.Theme |
||||
|
||||
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 |
||||
|
||||
|
@ -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 |
||||
|
||||
object BookType { |
||||
const val default = 0 |
||||
const val audio = 1 |
||||
const val default = 0 // 0 文本 |
||||
const val audio = 1 // 1 音频 |
||||
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]*?)\\}\\}") |
||||
} |