Merge pull request #5 from gedoor/master

Sync repo with gedoor/legado
pull/1209/head
桜庭咲く 3 years ago committed by GitHub
commit 795dce9006
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      .github/ISSUE_TEMPLATE/01-bugReport.md
  2. 19
      .github/ISSUE_TEMPLATE/02-featureRequest.md
  3. 99
      .github/scripts/lzy_web.py
  4. 107
      .github/workflows/legado.yml
  5. 57
      README.md
  6. 18
      api.md
  7. 169
      app/build.gradle
  8. BIN
      app/cronetlib/cronet_api.jar
  9. BIN
      app/cronetlib/cronet_impl_common_java.jar
  10. BIN
      app/cronetlib/cronet_impl_native_java.jar
  11. BIN
      app/cronetlib/cronet_impl_platform_java.jar
  12. BIN
      app/cronetlib/src/cronet_api-src.jar
  13. BIN
      app/cronetlib/src/cronet_impl_common_java-src.jar
  14. BIN
      app/cronetlib/src/cronet_impl_native_java-src.jar
  15. BIN
      app/cronetlib/src/cronet_impl_platform_java-src.jar
  16. 38
      app/google-services.json
  17. 10
      app/proguard-rules.pro
  18. 5
      app/src/debug/res/values-zh-rHK/strings.xml
  19. 5
      app/src/debug/res/values-zh-rTW/strings.xml
  20. 6
      app/src/google/res/values-zh-rTW/strings.xml
  21. 194
      app/src/main/AndroidManifest.xml
  22. 202
      app/src/main/assets/18PlusList.txt
  23. 237
      app/src/main/assets/defaultData/httpTTS.json
  24. 107
      app/src/main/assets/defaultData/readConfig.json
  25. 30
      app/src/main/assets/defaultData/rssSources.json
  26. 0
      app/src/main/assets/defaultData/themeConfig.json
  27. 30
      app/src/main/assets/defaultData/txtTocRule.json
  28. 16
      app/src/main/assets/epub/chapter.html
  29. 21
      app/src/main/assets/epub/cover.html
  30. 267
      app/src/main/assets/epub/fonts.css
  31. 11
      app/src/main/assets/epub/intro.html
  32. BIN
      app/src/main/assets/epub/logo.png
  33. 551
      app/src/main/assets/epub/main.css
  34. 0
      app/src/main/assets/font/number.ttf
  35. 129
      app/src/main/assets/help.md
  36. 25
      app/src/main/assets/help/SourceMBookHelp.md
  37. 21
      app/src/main/assets/help/SourceMRssHelp.md
  38. 190
      app/src/main/assets/help/appHelp.md
  39. 22
      app/src/main/assets/help/debugHelp.md
  40. 15
      app/src/main/assets/help/httpTTSHelp.md
  41. 58
      app/src/main/assets/help/readMenuHelp.md
  42. 226
      app/src/main/assets/help/regexHelp.md
  43. 6
      app/src/main/assets/help/replaceRuleHelp.md
  44. 177
      app/src/main/assets/help/ruleHelp.md
  45. 19
      app/src/main/assets/help/webDavHelp.md
  46. 62
      app/src/main/assets/httpTTS.json
  47. 52
      app/src/main/assets/readConfig.json
  48. 1016
      app/src/main/assets/updateLog.md
  49. BIN
      app/src/main/assets/web/__MACOSX/._assets
  50. BIN
      app/src/main/assets/web/__MACOSX/._images
  51. BIN
      app/src/main/assets/web/__MACOSX/._index.html
  52. BIN
      app/src/main/assets/web/__MACOSX/assets/._.DS_Store
  53. BIN
      app/src/main/assets/web/__MACOSX/assets/._css
  54. BIN
      app/src/main/assets/web/__MACOSX/assets/._js
  55. BIN
      app/src/main/assets/web/__MACOSX/assets/css/._.DS_Store
  56. BIN
      app/src/main/assets/web/__MACOSX/assets/js/._.DS_Store
  57. BIN
      app/src/main/assets/web/__MACOSX/assets/js/._dist.js
  58. 3953
      app/src/main/assets/web/assets/css/main.css
  59. 8
      app/src/main/assets/web/assets/js/dist.js
  60. 150
      app/src/main/assets/web/bookSource/index.css
  61. 401
      app/src/main/assets/web/bookSource/index.html
  62. 60
      app/src/main/assets/web/bookSource/index.js
  63. 176
      app/src/main/assets/web/bookshelf.css
  64. 39
      app/src/main/assets/web/bookshelf.html
  65. 203
      app/src/main/assets/web/bookshelf.js
  66. 2
      app/src/main/assets/web/bookshelf/css/about.b9bb4fe0.css
  67. 0
      app/src/main/assets/web/bookshelf/css/app.e4c919b7.css
  68. 1
      app/src/main/assets/web/bookshelf/css/chunk-vendors.8a465a1d.css
  69. 1
      app/src/main/assets/web/bookshelf/css/detail.e03dc50b.css
  70. 0
      app/src/main/assets/web/bookshelf/favicon.ico
  71. 0
      app/src/main/assets/web/bookshelf/fonts/element-icons.535877f5.woff
  72. 0
      app/src/main/assets/web/bookshelf/fonts/element-icons.732389de.ttf
  73. 0
      app/src/main/assets/web/bookshelf/fonts/iconfont.f9a3fb0e.woff
  74. 0
      app/src/main/assets/web/bookshelf/fonts/popfont.f39ecc1a.ttf
  75. 0
      app/src/main/assets/web/bookshelf/fonts/shelffont.6c094b6d.ttf
  76. 0
      app/src/main/assets/web/bookshelf/img/icons/android-chrome-192x192.png
  77. 0
      app/src/main/assets/web/bookshelf/img/icons/android-chrome-512x512.png
  78. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon-120x120.png
  79. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon-152x152.png
  80. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon-180x180.png
  81. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon-60x60.png
  82. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon-76x76.png
  83. 0
      app/src/main/assets/web/bookshelf/img/icons/apple-touch-icon.png
  84. 0
      app/src/main/assets/web/bookshelf/img/icons/favicon-16x16.png
  85. 0
      app/src/main/assets/web/bookshelf/img/icons/favicon-32x32.png
  86. 0
      app/src/main/assets/web/bookshelf/img/icons/msapplication-icon-144x144.png
  87. 0
      app/src/main/assets/web/bookshelf/img/icons/mstile-150x150.png
  88. 0
      app/src/main/assets/web/bookshelf/img/icons/safari-pinned-tab.svg
  89. 43
      app/src/main/assets/web/bookshelf/index.html
  90. 1
      app/src/main/assets/web/bookshelf/js/about.9f8f9ac0.js
  91. 1
      app/src/main/assets/web/bookshelf/js/about~detail.8270a871.js
  92. 1
      app/src/main/assets/web/bookshelf/js/app.e84ee963.js
  93. 33
      app/src/main/assets/web/bookshelf/js/chunk-vendors.3ef7796f.js
  94. 1
      app/src/main/assets/web/bookshelf/js/detail.4e6a53a9.js
  95. 0
      app/src/main/assets/web/bookshelf/manifest.json
  96. 70
      app/src/main/assets/web/bookshelf/precache-manifest.5ae9ceec57e7f0f3cc808807b7fe5f32.js
  97. 2
      app/src/main/assets/web/bookshelf/robots.txt
  98. 2
      app/src/main/assets/web/bookshelf/service-worker.js
  99. BIN
      app/src/main/assets/web/images/bg.jpg
  100. 148
      app/src/main/assets/web/index.css
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,52 @@
---
name: "[BUG] 问题提交模板"
about: 请从符号">"后面开始填写内容,填写内容可以参考 https://github.com/gedoor/legado/issues/505                    
title: "[BUG] "
labels: 'BUG'
assignees: ''
---
### 机型(如Redmi K30 Pro)
>
### 安卓版本(如Android 7.1.1)
>
### 阅读Legdao版本(我的-关于-版本,如3.20.112220)
>
### 网络环境(移动,联通,电信,移动宽带,联通宽带,电信宽带,等等..)
>
### 问题描述(简要描述发生的问题)
>
### 使用书源(填写URL或者JSON)
>
```json
```
### 复现步骤(详细描述导致问题产生的操作步骤,如果能稳定复现)
>
### 日志提交(问题截图或者日志)
>

@ -0,0 +1,19 @@
---
name: "[FeatureRequest] 功能请求模板"
about: 提交你希望能够在阅读中增加的功能
title: "[Feature Request] "
labels: '需求'
assignees: ''
---
### 功能描述(请清晰的、详细的描述你想要的功能)
>
### 期望实现方式(阅读应该如何实现该功能)
>
### 附加信息(其他的与功能相关的附加信息)
>
### 效果演示(可以手绘一些草图,或者提供可借鉴的图片)
>

@ -0,0 +1,99 @@
import requests, os, datetime, sys
# Cookie 中 phpdisk_info 的值
cookie_phpdisk_info = os.environ.get('phpdisk_info')
# Cookie 中 ylogin 的值
cookie_ylogin = os.environ.get('ylogin')
# 请求头
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.72 Safari/537.36 Edg/89.0.774.45',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Referer': 'https://pc.woozooo.com/account.php?action=login'
}
# 小饼干
cookie = {
'ylogin': cookie_ylogin,
'phpdisk_info': cookie_phpdisk_info
}
# 日志打印
def log(msg):
utc_time = datetime.datetime.utcnow()
china_time = utc_time + datetime.timedelta(hours=8)
print(f"[{china_time.strftime('%Y.%m.%d %H:%M:%S')}] {msg}")
# 检查是否已登录
def login_by_cookie():
url_account = "https://pc.woozooo.com/account.php"
if cookie['phpdisk_info'] is None:
log('ERROR: 请指定 Cookie 中 phpdisk_info 的值!')
return False
if cookie['ylogin'] is None:
log('ERROR: 请指定 Cookie 中 ylogin 的值!')
return False
res = requests.get(url_account, headers=headers, cookies=cookie, verify=True)
if '网盘用户登录' in res.text:
log('ERROR: 登录失败,请更新Cookie')
return False
else:
log('登录成功')
return True
# 上传文件
def upload_file(file_dir, folder_id):
file_name = os.path.basename(file_dir)
url_upload = "https://up.woozooo.com/fileup.php"
headers['Referer'] = f'https://up.woozooo.com/mydisk.php?item=files&action=index&u={cookie_ylogin}'
post_data = {
"task": "1",
"folder_id": folder_id,
"id": "WU_FILE_0",
"name": file_name,
}
files = {'upload_file': (file_name, open(file_dir, "rb"), 'application/octet-stream')}
res = requests.post(url_upload, data=post_data, files=files, headers=headers, cookies=cookie, timeout=120,
verify=True).json()
log(f"{file_dir} -> {res['info']}")
return res['zt'] == 1
# 上传文件夹内的文件
def upload_folder(folder_dir, folder_id):
file_list = os.listdir(folder_dir)
for file in file_list:
path = os.path.join(folder_dir, file)
if os.path.isfile(path):
upload_file(path, folder_id)
else:
upload_folder(path, folder_id)
# 上传
def upload(dir, folder_id):
if dir is None:
log('ERROR: 请指定上传的文件路径')
return
if folder_id is None:
log('ERROR: 请指定蓝奏云的文件夹id')
return
if os.path.isfile(dir):
upload_file(dir, str(folder_id))
else:
upload_folder(dir, str(folder_id))
if __name__ == '__main__':
argv = sys.argv[1:]
if len(argv) != 2:
log('ERROR: 参数错误,请以这种格式重新尝试\npython lzy_web.py 需上传的路径 蓝奏云文件夹id')
# 需上传的路径
upload_path = argv[0]
# 蓝奏云文件夹id
lzy_folder_id = argv[1]
if login_by_cookie():
upload(upload_path, lzy_folder_id)

@ -1,15 +1,10 @@
name: Android CI
on:
on:
release:
types: [published]
push:
branches:
- master
tags:
- '3.*'
pull_request:
branches:
branches:
- master
# watch:
# types: [started]
@ -18,40 +13,68 @@ on:
jobs:
build:
runs-on: ubuntu-latest
env:
# 登录蓝奏云后在控制台运行document.cookie
ylogin: ${{ secrets.LANZOU_ID }}
phpdisk_info: ${{ secrets.LANZOU_PSD }}
# 蓝奏云里的文件夹ID(阅读3测试版:2670621)
LANZOU_FOLDER_ID: '2670621'
# 是否上传到artifact
UPLOAD_ARTIFACT: 'true'
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
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-legado-${{ hashFiles('**/updateLog.md') }}-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-legado-${{ hashFiles('**/updateLog.md') }}-
- 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 --build-cache --parallel
- name: Upload App To Artifact
if: ${{ env.UPLOAD_ARTIFACT != 'false' }}
uses: actions/upload-artifact@v2
with:
name: legado apk
path: ${{ github.workspace }}/app/build/outputs/apk/app/release/*.apk
- name: Upload App To Lanzou
if: ${{ env.ylogin }}
run: |
path="$GITHUB_WORKSPACE/app/build/outputs/apk/app/release"
files=$(ls $path)
for f in $files
do
if [[ $f == *"apk" ]]; then
file=$f
echo "[$(date -u -d '+8 hour' '+%Y.%m.%d %H:%M:%S')] 文件:$file"
break
fi
done
python3 $GITHUB_WORKSPACE/.github/scripts/lzy_web.py "$path/$file" "$LANZOU_FOLDER_ID"
echo "[$(date -u -d '+8 hour' '+%Y.%m.%d %H:%M:%S')] 分享链接: https://kunfei.lanzoux.com/b0f810h4b"

@ -1,11 +1,55 @@
# legado
<div>
<img width="192" height="192" align="left" src="https://github.com/gedoor/legado/raw/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png" alt="legado"/>
<h1>Legado</h1>
<br>
<p>阅读3.0, 阅读是一款可以自定义来源阅读网络内容的工具,为广大网络文学爱好者提供一种方便、快捷舒适的试读体验。</p>
</div>
[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
[![Build Action](https://github.com/gedoor/legado/workflows/Android%20CI/badge.svg)](https://github.com/gedoor/legado/actions)
[![Downloads](https://img.shields.io/github/downloads/gedoor/legado/total.svg)](https://github.com/gedoor/legado/releases/latest)
[![GitHub issues](https://img.shields.io/github/issues/gedoor/legado)](https://github.com/gedoor/legado/issues)
[![GitHub contributors](https://img.shields.io/github/contributors/gedoor/legado)](https://github.com/gedoor/legado/graphs/contributors)
## 阅读3.0
* 书源规则 https://celeter.github.io
* 更新日志 [updateLog.md](/app/src/main/assets/updateLog.md)
* [书源规则](https://alanskycn.gitee.io/teachme)
* [更新日志](/app/src/main/assets/updateLog.md)
* [帮助文档](/app/src/main/assets/help/appHelp.md)
* [web端](https://github.com/celetor/web-yuedu3)
## 下载
<a href="https://play.google.com/store/apps/details?id=io.legado.play.release"><img width="200px" alt="Google Play" src="https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png"/></a> or <a href="https://www.coolapk.com/apk/io.legado.app.release"><img width="100px" height="100px" alt="CoolApk" src="https://github.com/Celeter/build/raw/master/.github/scripts/coolapk.png"/></a> or [Releases](https://github.com/gedoor/legado/releases/latest)
## 阅读API
* 阅读3.0 提供了2种方式的API:`Web方式`和`Content Provider方式`。您可以在[这里](api.md)根据需要自行调用。
* 可通过url唤起阅读进行一键导入,url格式: legado://import/{path}?src={url}
* path类型: bookSource,rssSource,replaceRule,textTocRule,httpTTS,theme,readConfig
* path类型解释: 书源,订阅源,替换规则,本地txt小说目录规则,在线朗读引擎,主题,阅读排版
## 感谢
```
org.jsoup:jsoup
cn.wanghaomiao:JsoupXpath
com.jayway.jsonpath:json-path
com.github.gedoor:rhino-android
com.squareup.okhttp3:okhttp
com.ljx.rxhttp:rxhttp
com.github.bumptech.glide:glide
org.nanohttpd:nanohttpd
org.nanohttpd:nanohttpd-websocket
cn.bingoogolapple:bga-qrcode-zxing
com.jaredrummler:colorpicker
org.apache.commons:commons-text
io.noties.markwon:core
io.noties.markwon:image-glide
com.hankcs:hanlp
com.positiondev.epublib:epublib-core
```
## 免责声明
https://gedoor.github.io/MyBookshelf/disclaimer.html
## 界面
![image](https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B1.jpg)
![image](https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B2.jpg)
![image](https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B3.jpg)
@ -13,8 +57,5 @@
![image](https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B5.jpg)
![image](https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B6.jpg)
### 阅读API
阅读3.0 提供了2种方式的API:`Web方式`和`Content Provider方式`。您可以在[这里](api.md)根据需要自行调用。
## 免责声明
https://gedoor.github.io/MyBookshelf/disclaimer.html
## 其它
其它网友做的IOS版本: https://github.com/kaich/Yuedu

@ -4,7 +4,7 @@
## 使用
### Web
以下说明假设您的操作在本机进行,且开放端口为1234。
如果您要从远程计算机访问[阅读],请将`127.0.0.1`替换成手机IP。
如果您要从远程计算机访问[阅读](),请将`127.0.0.1`替换成手机IP。
#### 插入单个书源
```
URL = http://127.0.0.1:1234/saveSource
@ -74,13 +74,18 @@ Method = GET
获取指定图书的章节列表。
#### 获取书籍内容
```
URL = http://127.0.0.1:1234/getBookContent?url=xxx&index=1
Method = GET
```
获取指定图书的第`index`章节的文本内容。
#### 获取封面
```
URL = http://127.0.0.1:1234/cover?path=xxxxx
Method = GET
```
获取指定图书的第`index`章节的文本内容。
### Content Provider
* 需声明`io.legado.READ_WRITE`权限
@ -164,6 +169,11 @@ Method = query
URL = content://providerHost/book/content/query?url=xxx&index=1
Method = query
```
获取指定图书的第`index`章节的文本内容。
用`Cursor.getString(0)`取出返回结果。
#### 获取封面
```
URL = content://providerHost/book/cover/query?path=xxxx
Method = query
```

@ -1,13 +1,8 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'de.timfreiheit.resourceplaceholders'
apply plugin: 'io.fabric'
androidExtensions {
experimental = true
}
static def releaseTime() {
return new Date().format("yy.MMddHH", TimeZone.getTimeZone("GMT+8"))
@ -18,7 +13,7 @@ def version = "3." + releaseTime()
def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim())
android {
compileSdkVersion 29
compileSdkVersion 30
signingConfigs {
if (project.hasProperty("RELEASE_STORE_FILE")) {
myConfig {
@ -34,15 +29,16 @@ android {
defaultConfig {
applicationId "io.legado.app"
minSdkVersion 21
targetSdkVersion 29
targetSdkVersion 30
versionCode gitCommits
versionName version
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
project.ext.set("archivesBaseName", name + "_" + version)
multiDexEnabled true
javaCompileOptions {
annotationProcessorOptions {
arguments = [
arguments += [
"room.incremental" : "true",
"room.expandProjection": "true",
"room.schemaLocation" : "$projectDir/schemas".toString()
@ -50,6 +46,9 @@ android {
}
}
}
buildFeatures {
viewBinding true
}
buildTypes {
release {
if (project.hasProperty("RELEASE_STORE_FILE")) {
@ -86,17 +85,29 @@ android {
applicationId "io.legado.play"
manifestPlaceholders = [APP_CHANNEL_VALUE: "google"]
}
cronet {
dimension "mode"
applicationId "io.legado.cronet"
manifestPlaceholders = [APP_CHANNEL_VALUE: "cronet"]
ndk {
abiFilters 'arm64-v8a','armeabi-v7a','x86_64','x86'
}
}
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
// Sets Java compatibility to Java 11
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "1.8"
jvmTarget = "11"
}
buildToolsVersion '30.0.3'
tasks.withType(JavaCompile) {
//options.compilerArgs << "-Xlint:unchecked"
}
}
@ -111,102 +122,98 @@ kapt {
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.10'
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation "com.android.support:multidex:1.0.3"
coreLibraryDesugaring('com.android.tools:desugar_jdk_libs:1.1.5')
testImplementation('junit:junit:4.13.2')
androidTestImplementation('androidx.test:runner:1.4.0')
androidTestImplementation('androidx.test.espresso:espresso-core:3.4.0')
implementation('androidx.multidex:multidex:2.0.1')
//kotlin
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
//fireBase
implementation 'com.google.firebase:firebase-core:17.5.0'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
//
def coroutines_version = '1.5.1'
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version")
//androidX
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.media:media:1.1.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'com.google.android:flexbox:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation('androidx.appcompat:appcompat:1.3.1')
implementation('androidx.core:core-ktx:1.6.0')
implementation("androidx.activity:activity-ktx:1.3.0")
implementation("androidx.fragment:fragment-ktx:1.3.6")
implementation('androidx.preference:preference-ktx:1.1.1')
implementation('androidx.constraintlayout:constraintlayout:2.0.4')
implementation('androidx.swiperefreshlayout:swiperefreshlayout:1.1.0')
implementation('androidx.viewpager2:viewpager2:1.0.0')
implementation('com.google.android.material:material:1.4.0')
implementation('com.google.android.flexbox:flexbox:3.0.0')
implementation('com.google.code.gson:gson:2.8.7')
implementation('androidx.webkit:webkit:1.4.0')
//media
def media2_version = "1.1.3"
implementation("androidx.media2:media2-session:$media2_version")
implementation("androidx.media:media:1.4.0")
//implementation "androidx.media2:media2-player:$media2_version"
//implementation 'com.google.android.exoplayer:exoplayer:2.13.0'
//Splitties
def splitties_version = '2.1.1'
implementation("com.louiscad.splitties:splitties-appctx:$splitties_version")
implementation("com.louiscad.splitties:splitties-systemservices:$splitties_version")
implementation("com.louiscad.splitties:splitties-views:$splitties_version")
//lifecycle
def lifecycle_version = '2.2.0'
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
def lifecycle_version = '2.3.1'
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version")
//room
def room_version = '2.2.5'
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
testImplementation "androidx.room:room-testing:2.2.5"
//paging
implementation 'androidx.paging:paging-runtime-ktx:2.1.2'
//anko
def anko_version = '0.10.8'
implementation "org.jetbrains.anko:anko-sdk27:$anko_version"
implementation "org.jetbrains.anko:anko-sdk27-listeners:$anko_version"
def room_version = '2.3.0'
implementation("androidx.room:room-runtime:$room_version")
implementation("androidx.room:room-ktx:$room_version")
kapt("androidx.room:room-compiler:$room_version")
testImplementation("androidx.room:room-testing:$room_version")
//liveEventBus
implementation 'com.jeremyliao:live-event-bus-x:1.5.7'
//
def coroutines_version = '1.3.7'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation('io.github.jeremyliao:live-event-bus-x:1.8.0')
//
implementation 'org.jsoup:jsoup:1.13.1'
implementation 'cn.wanghaomiao:JsoupXpath:2.3.2'
implementation 'com.jayway.jsonpath:json-path:2.4.0'
implementation('org.jsoup:jsoup:1.14.1')
implementation('com.jayway.jsonpath:json-path:2.6.0')
implementation('cn.wanghaomiao:JsoupXpath:2.5.0')
implementation(project(path: ':epublib'))
//JS rhino
implementation 'com.github.gedoor:rhino-android:1.4'
implementation('com.github.gedoor:rhino-android:1.6')
//
//noinspection GradleDependency
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
implementation('com.squareup.okhttp3:okhttp:4.9.1')
compileOnly(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))
cronetImplementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar']))
//Glide
implementation 'com.github.bumptech.glide:glide:4.11.0'
implementation('com.github.bumptech.glide:glide:4.12.0')
//webServer
implementation 'org.nanohttpd:nanohttpd:2.3.1'
implementation 'org.nanohttpd:nanohttpd-websocket:2.3.1'
implementation('org.nanohttpd:nanohttpd:2.3.1')
implementation('org.nanohttpd:nanohttpd-websocket:2.3.1')
implementation('org.nanohttpd:nanohttpd-apache-fileupload:2.3.1')
//
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
implementation('com.github.jenly1314:zxing-lite:2.1.0')
//
implementation 'com.jaredrummler:colorpicker:1.1.0'
implementation('com.jaredrummler:colorpicker:1.1.0')
//apache
implementation 'org.apache.commons:commons-lang3:3.11'
implementation 'org.apache.commons:commons-text:1.8'
implementation('org.apache.commons:commons-text:1.9')
//MarkDown
implementation 'ru.noties.markwon:core:3.1.0'
def markwonVersion = "4.6.2"
implementation("io.noties.markwon:core:$markwonVersion")
implementation("io.noties.markwon:image-glide:$markwonVersion")
implementation("io.noties.markwon:ext-tables:$markwonVersion")
implementation("io.noties.markwon:html:$markwonVersion")
//
implementation 'com.hankcs:hanlp:portable-1.7.8'
//epub
implementation('com.positiondev.epublib:epublib-core:3.1') {
exclude group: 'org.slf4j'
exclude group: 'xmlpull'
}
implementation('com.github.liuyueyi.quick-chinese-transfer:quick-transfer-core:0.2.1')
//E-Ink
//implementation 'fadeapp.widgets:scrollless-recyclerView:1.0.2'
}
apply plugin: 'com.google.gms.google-services'

Binary file not shown.

@ -8,9 +8,9 @@
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:1d2b1eefbe0e78cff624a7",
"mobilesdk_app_id": "1:453392274790:android:c4eac14b1410eec5f624a7",
"android_client_info": {
"package_name": "io.legado.app"
"package_name": "io.legado.app.debug"
}
},
"oauth_client": [
@ -37,12 +37,20 @@
},
{
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:c4eac14b1410eec5f624a7",
"mobilesdk_app_id": "1:453392274790:android:c1481c1c3d3f51eff624a7",
"android_client_info": {
"package_name": "io.legado.app.debug"
"package_name": "io.legado.app.release"
}
},
"oauth_client": [
{
"client_id": "453392274790-trrgennt5njr1lhil1sgtf0ogcgd38fo.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.legado.app.release",
"certificate_hash": "fd67dba87b7b761631266f19ddde249054aac5c1"
}
},
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
@ -66,12 +74,20 @@
},
{
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:c1481c1c3d3f51eff624a7",
"mobilesdk_app_id": "1:453392274790:android:b891abd2331577dff624a7",
"android_client_info": {
"package_name": "io.legado.app.release"
"package_name": "io.legado.play.release"
}
},
"oauth_client": [
{
"client_id": "453392274790-f8sjn6ohs72rg1dvp0pdvk42nkq54p0k.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.legado.play.release",
"certificate_hash": "00819ace9891386e535967cbafd6a88f3797bd5b"
}
},
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3
@ -97,10 +113,18 @@
"client_info": {
"mobilesdk_app_id": "1:453392274790:android:b891abd2331577dff624a7",
"android_client_info": {
"package_name": "io.legado.play.release"
"package_name": "io.legado.play.debug"
}
},
"oauth_client": [
{
"client_id": "453392274790-f8sjn6ohs72rg1dvp0pdvk42nkq54p0k.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "io.legado.play.debug",
"certificate_hash": "00819ace9891386e535967cbafd6a88f3797bd5b"
}
},
{
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com",
"client_type": 3

@ -54,6 +54,8 @@
# Android开发中一些需要保留的公共部分
#
#############################################
# 屏蔽错误Unresolved class name
#noinspection ShrinkerUnresolvedReference
# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆
# 因为这些子类都有可能被外部调用
@ -66,7 +68,6 @@
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
# 保留androidx下的所有类及其内部类
-keep class androidx.** {*;}
@ -221,3 +222,10 @@
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Keep all of Cronet API as it's used by the Cronet module.
-keep public class org.chromium.net.* {
!private *;
*;
}

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">閲讀.D</string>
<string name="receiving_shared_label">閲讀·D·搜索</string>
</resources>

@ -1,5 +0,0 @@
<?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,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">閱讀Pro</string>
</resources>

@ -3,11 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
package="io.legado.app">
<uses-permission
android:name="android.permission.MANAGE_DOCUMENTS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@ -18,6 +13,12 @@
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
tools:ignore="ScopedStorage" />
<application
android:name=".App"
@ -30,7 +31,9 @@
android:theme="@style/AppTheme.Light"
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute">
<!-- 主入口 -->
<activity android:name=".ui.welcome.WelcomeActivity">
<activity
android:name=".ui.welcome.WelcomeActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -46,6 +49,7 @@
<activity
android:name=".ui.welcome.Launcher1"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher1">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -62,6 +66,7 @@
<activity
android:name=".ui.welcome.Launcher2"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -78,6 +83,7 @@
<activity
android:name=".ui.welcome.Launcher3"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher3">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -94,6 +100,7 @@
<activity
android:name=".ui.welcome.Launcher4"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher4">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -110,6 +117,7 @@
<activity
android:name=".ui.welcome.Launcher5"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher5">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -126,6 +134,7 @@
<activity
android:name=".ui.welcome.Launcher6"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/launcher6">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -147,7 +156,16 @@
<activity
android:name=".ui.book.read.ReadBookActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask" />
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="com.samsung.android.support.REMOTE_ACTION" />
</intent-filter>
<meta-data
android:name="com.samsung.android.support.REMOTE_ACTION"
android:resource="@xml/spen_remote_actions" />
</activity>
<!-- 书籍详情页 -->
<activity
android:name=".ui.book.info.BookInfoActivity"
@ -158,16 +176,20 @@
android:launchMode="singleTask" />
<!-- 音频播放界面 -->
<activity
android:name=".ui.audio.AudioPlayActivity"
android:name="io.legado.app.ui.book.audio.AudioPlayActivity"
android:launchMode="singleTask" />
<!-- 授权界面 -->
<activity
android:name=".help.permission.PermissionActivity"
android:name="io.legado.app.lib.permission.PermissionActivity"
android:theme="@style/Activity.Permission" />
<!-- 二维码扫描 -->
<activity
android:name=".ui.qrcode.QrCodeActivity"
android:launchMode="singleTask" />
<!-- 规则订阅 -->
<activity
android:name=".ui.rss.subscription.RuleSubActivity"
android:launchMode="singleTask" />
<!-- 书源编辑 -->
<activity
android:name=".ui.book.source.edit.BookSourceEditActivity"
@ -180,6 +202,12 @@
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize|stateHidden" />
<!-- 书源编辑 -->
<activity
android:name=".ui.replace.edit.ReplaceEditActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize|stateHidden" />
<!-- 配置界面 -->
<activity
android:name=".ui.config.ConfigActivity"
@ -187,39 +215,50 @@
<!-- 搜索界面 -->
<activity
android:name=".ui.book.search.SearchActivity"
android:launchMode="singleTask" />
android:launchMode="standard" />
<!-- 关于界面 -->
<activity
android:name=".ui.about.AboutActivity"
android:launchMode="singleTask" />
android:launchMode="singleTask"
android:screenOrientation="behind" />
<!-- 捐赠界面 -->
<activity
android:name=".ui.about.DonateActivity"
android:launchMode="singleTask" />
android:launchMode="singleTask"
android:screenOrientation="behind" />
<!-- 书源管理 -->
<activity
android:name=".ui.book.source.manage.BookSourceActivity"
android:launchMode="singleTop" />
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 订阅源管理 -->
<activity
android:name=".ui.rss.source.manage.RssSourceActivity"
android:launchMode="singleTop" />
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 替换规则界面 -->
<activity
android:name=".ui.replacerule.ReplaceRuleActivity"
android:launchMode="singleTop">
</activity>
android:name=".ui.replace.ReplaceRuleActivity"
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 书籍管理 -->
<activity
android:name=".ui.book.arrange.ArrangeBookActivity"
android:launchMode="singleTop" />
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 书源调试 -->
<activity
android:name=".ui.book.source.debug.BookSourceDebugActivity"
android:launchMode="singleTop" />
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 目录 -->
<activity
android:name=".ui.book.chapterlist.ChapterListActivity"
android:name=".ui.book.toc.TocActivity"
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- 正文搜索 -->
<activity
android:name=".ui.book.searchContent.SearchContentActivity"
android:launchMode="singleTop"
android:screenOrientation="behind" />
<!-- RSS条目 -->
@ -248,13 +287,13 @@
<activity
android:name=".ui.rss.favorites.RssFavoritesActivity"
android:launchMode="singleTop" />
<!-- 下载界面 -->
<!-- 缓存界面 -->
<activity
android:name=".ui.book.download.DownloadActivity"
android:name=".ui.book.cache.CacheActivity"
android:launchMode="singleTop" />
<!-- 书源登录 -->
<activity
android:name=".ui.login.SourceLogin"
android:name=".ui.login.SourceLoginActivity"
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true" />
<!-- 阅读记录 -->
@ -262,10 +301,18 @@
android:name=".ui.about.ReadRecordActivity"
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true" />
<!-- 选择文件 -->
<activity
android:name=".ui.document.FilePickerActivity"
android:configChanges="orientation|screenSize"
android:hardwareAccelerated="true"
android:theme="@style/AppTheme.Transparent" />
<!-- 文字处理 -->
<activity
android:name=".receiver.SharedReceiverActivity"
android:label="@string/receiving_shared_label">
android:exported="true"
android:label="@string/receiving_shared_label"
android:theme="@style/AppTheme.Transparent">
<intent-filter>
<action android:name="android.intent.action.PROCESS_TEXT" />
@ -281,10 +328,11 @@
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<!-- 导入书源 -->
<!-- 一键导入 -->
<activity
android:name=".ui.association.ImportBookSourceActivity"
android:name=".ui.association.OnLineImportActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:exported="true"
android:theme="@style/AppTheme.Transparent">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@ -292,74 +340,86 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="booksource"
android:scheme="yuedu" />
<data android:scheme="legado" />
<data android:scheme="yuedu" />
</intent-filter>
</activity>
<!-- 导入订阅源 -->
<!-- 打开文件 -->
<activity
android:name=".ui.association.ImportRssSourceActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:name=".ui.association.FileAssociationActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/AppTheme.Transparent">
<!-- VIEW (Open with) action -->
<!-- Works when an app knows the media type of a file, e.g. Gmail or Chrome. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="rsssource"
android:scheme="yuedu" />
<data android:scheme="app" />
<data android:scheme="content" />
<data android:scheme="file" />
<!-- text -->
<data android:mimeType="text/plain" />
<!-- json -->
<data android:mimeType="application/json" />
<!-- EPUB -->
<data android:mimeType="application/epub+zip" />
</intent-filter>
</activity>
<!-- 导入替换规则 -->
<activity
android:name=".ui.association.ImportReplaceRuleActivity"
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:theme="@style/AppTheme.Transparent">
<!-- Works when an app doesn't know the media type, e.g. Dropbox -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="replace"
android:scheme="yuedu" />
</intent-filter>
</activity>
<!-- 打开文件 -->
<activity
android:name=".ui.association.FileAssociationActivity"
android:theme="@style/AppTheme.Transparent"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:host="*" />
<data android:scheme="file" />
<data android:scheme="app" />
<data android:scheme="content" />
<data android:mimeType="text/plain" />
<data android:mimeType="application/json" />
<data android:mimeType="application/epub" />
<data android:scheme="file" />
<!-- This media type is necessary, otherwise it won't match on the file extension -->
<data android:mimeType="*/*" />
<!--TXT-->
<data android:pathPattern=".*\\.txt" />
<data android:pathPattern=".*\\.TXT" />
<!--JSON-->
<data android:pathPattern=".*\\.json" />
<data android:pathPattern=".*\\.JSON" />
<!-- EPUB -->
<data android:pathPattern=".*\\.epub" />
<data android:pathPattern=".*\\.EPUB" />
</intent-filter>
</activity>
<service android:name=".service.CheckSourceService" />
<service android:name=".service.DownloadService" />
<service android:name=".service.CacheBookService" />
<service android:name=".service.WebService" />
<service
android:name=".service.WebTileService"
android:label="legado Web Service"
android:icon="@drawable/ic_web_service_noti"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:exported="true">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
</service>
<service android:name=".service.TTSReadAloudService" />
<service android:name=".service.HttpReadAloudService" />
<service android:name=".service.AudioPlayService" />
<service android:name=".service.DownloadService" />
<receiver android:name=".receiver.MediaButtonReceiver">
<receiver
android:name=".receiver.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
<provider
android:name=".api.ReaderProvider"
android:authorities="${applicationId}.readerProvider"
@ -381,4 +441,14 @@
android:value="${APP_CHANNEL_VALUE}" />
</application>
<queries>
<intent>
<action android:name="android.intent.action.TTS_SERVICE" />
</intent>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
</queries>
</manifest>

@ -80,3 +80,205 @@ cm5neHM=
OTl3ZW5rdQ==
bGFvc2lqaXhz
ZnVzaHV6aGFpMQ==
cG8xOA==
czUyMTc=
c2FuaGFveHM=
NTJrc2h1
NDhyeA==
ZWNub3ZlbA==
bGllaHVvenc=
eGlhb3FpYW5nd3g=
NTJrc2h1
NDh3eA==
NTJrc2h1
MDB1aQ==
MDFieg==
c2h1YmFvMQ==
ZG54aWFvc2h1b2E=
am5zaHViYQ==
MThzaHV3dQ==
bGV4cw==
MzM1eHM=
dXB1
ZnVndW9kdQ==
ODB0eHQ=
YWFyZWFk
eWlkdWR1MQ==
YmFuemh1d2FuZw==
cWloYW9xaWhhbw==
OHhpYW54cw==
amluamlzaHV3dQ==
d21wOA==
ZXl1c2h1d3U=
NTB4c2Y=
aGF4d3g1
cG93YW5qdWFu
d2luMTBjaXR5
eWV5ZXhzdw==
bXlzaHVnZQ==
eGlhbmd0eHN3
Y3Vpd2VpanV4
MzY2eHN3
aHVheXVld2Vua3U=
eW91ZGlhbmxlbg==
c291Nzg=
bGFucm91Mg==
cXFib29r
eW91d3V4cw==
cnVpbGlzYWxl
MzY1bXd3
ZnV3ZW5o
bGVzYmw=
YXd1Ym9vaw==
bGl5dXhpYW5nMjAyMA==
OTJwb3Bv
ZnVzaHV0dWFu
ODhkYW5tZWk=
ZG14cw==
eXVsaW56aGFueWU=
M2hlYmFv
eGd1YWd1YXhz
ZGl5aWJhbnpodTY=
aXJlYWR4cw==
c2h1YmFvOTY=
ZGl5aWJhbnpodTU1NQ==
c2Fuaml1enc=
N3Fpbmc3
NjZsZXdlbg==
a3l4czU=
MjIyMjJ4cw==
c2hhb3NodWdl
amlsaW41NQ==
bWt4czY=
amluc2h1bG91
eGlhbndhbmdz
eWlkdWR1
cWR0eHQ=
MTZib29rMQ==
am1zaHV3dQ==
MzY2eHN3
ZHliejk=
c2hvdWRhOA==
ZnlxMTg=
eWlzaHVn
eXV6aGFpd3VsYQ==
MTFiYW56aHU=
MTIzeGlhb3FpYW5n
ZGl5aWJhbnpodTk=
ZGl5aWJhbnpodQ==
MzY2eHN3
ODdzaHV3dQ==
NnF3eA==
emhlbmh1bnhpYW9zaHVv
bG9uZ3Rlbmc1Mg==
eGlueGluZ3hpYW5nemhpZmE=
ZHliejk=
ZHVvemhla2Fu
MTIzeGlhb3FpYW5n
MzM1eHM=
am1zaHV3dQ==
c2hhb3NodWdl
bGF3ZW54cw==
cnVzaHV3dQ==
MzY2eHN3
NTB4c2Y=
bGV3ZW41NQ==
aGFpdGFuZzEyMw==
aGViYW81MjA=
bHVvcWl1enc=
c3NzeHN3
c2h1c2h1d3V4cw==
cm5neHM=
cWR4aWFvc2h1bw==
dHl1ZQ==
Y2hlNDM=
bG9uZ3Rlbmcy
amZ5eHNo
aGV0dTI=
bGFvc2lqaXhz
bG9uZ3Rlbmd4cw==
bGllaHVvenc=
c2h1YmFvYW4=
eHNodW9zaHVv
NTIxZGFubWVp
YmFuemh1MjI=
cWtzaHU=
eWZ4aWFvc2h1b2U=
a3lnc28=
c2h1bG91YmE=
NXRucw==
N3Fpbmc3
bWlhb2R1NQ==
eXVzaHV3ZW4=
YWFyZWFk
cXRzaHU=
MTdzaHV3dQ==
c2h1YmFvMnM=
YnowMDE=
ZGFtb2dl
MTMxdGI=
aXhpYW9z
bXlzaHVnZQ==
OXhpYW53ZW4=
ZHVvemhla2Fu
MTIwdw==
c2h1c2h1d3U1MjA=
c2h1YmFvMnM=
YWd4c3c=
OTR4c3c=
cG8xOA==
eWFvY2hpeHM=
eGlhb3FpYW5neHM=
Ym9va2Js
c2Fuaml1eHM=
d29kZXNodWJhbw==
em9uZ2NhaXhpYW9zaHVvMg==
OWI4OTEzOTRkZjVi
MThub3ZlbA==
YWFib29r
YjF0eHQ=
eXVjYWl6dw==
Yzl0eHQ=
ZGl5aWJhbnpodTU1NQ==
MzBtYw==
eGlueXVzaHV3dQ==
c2h1YmFvd2FuZzEyMw==
YWd4cw==
YmlxdWdlbmw=
c2hpcWlzaHV3dQ==
c2lsdWtl
ZGl5aWJhbnpodTg=
ZGl5aWJhbnpodTk=
aGV0dW54cw==
OTl3ZW5rdQ==
aGFpdGFuZ3NodXd1
OTd5ZA==
eXV6aGFpd3UxMQ==
Y3Vpd2VpanV4cw==
Y2JpcXU=
NTIxZGFubWVp
c2h1YmFvMzM=
c2FuaGFvMQ==
dGlhbm1lbmd3ZW5rdQ==
eXVzaHV3dTUyMA==
c2h1YmFvMjIy
c2h1YmFvd2FuZzEyMw==
eXVib29r
Y2JpcXU=
MWxld2Vu
MTV4c3c=
eG5jd3h3
c2h1YmFvd2FuZzEyMw==
c2FuaGFveHM=
eXV3YW5nc2hl
YmlxdXRz
bGFtZWl4cw==
eGJhbnpodQ==
cWR4aWFvc2h1bw==
bWh0bGE=
OTl3ZW5rdQ==
eGlhb3FpYW5nNTIw
dGlhbm1lbmd3ZW5rdQ==
YWlmdXNodQ==
bWlhb2R1NQ==
bWlmZW5neHM=

@ -0,0 +1,237 @@
[
{
"id": -100,
"name": "0",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4127&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=11&vol=5&aue=6&pit=3&_res_tag_=audio\"\n}"
},
{
"id": -99,
"name": "zaixianai.cn",
"url": "<js>\nlet url='https://www.zaixianai.cn/voiceCompose';\n\nlet ua=\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36\";\n\nlet doc=java.get(url,{\"User-Agent\":ua});\nlet cookie=String(doc.header(\"set-cookie\")).match(/laravel_session=[^\\n]+/)[0];\nlet token=String(doc.body()).match(/token=\"([^\"]+)/)[1];\n\nurl='https://www.zaixianai.cn/Api_getVoice,'+JSON.stringify({\n\"method\": \"POST\",\n\"body\": \"content=\" + java.encodeURI(speakText) + \"&volume=50&speech_rate=0&voice=Aixia&_token=\"+token,\n\"headers\": {\n\"User-Agent\": ua,\n\"cookie\": cookie\n}\n});\n\nlet res=java.ajax(url);\n\n'https://www.zaixianai.cn/voice/'+JSON.parse(res).data.file_name+','+JSON.stringify({\n\"headers\": {\n\"User-Agent\": ua,\n\"accept\": \"*/*\",\n\"referer\": \"https://www.zaixianai.cn/voiceCompose\",\n\"cookie\": cookie,\n\"accept-encoding\": \"identity;q=1, *;q=0\"\n}\n})\n</js>"
},
{
"id": -98,
"name": "台湾女声",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4007&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -1,
"name": "度丫丫",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -2,
"name": "度博文①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -3,
"name": "度博文②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -4,
"name": "度博文③",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5106&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -97,
"name": "度小乔",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=1117&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=3&_res_tag_=audio\"\n}"
},
{
"id": -5,
"name": "度小娇",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -6,
"name": "度小宇",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=2&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -7,
"name": "度小童",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -96,
"name": "度小童",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=110&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -95,
"name": "度小粤",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=cte&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -8,
"name": "度小美",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=0&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -94,
"name": "度小芳",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4125&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -9,
"name": "度小萌",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=111&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -93,
"name": "度小贤",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4115&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"}"
},
{
"id": -92,
"name": "度小雯",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5100&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -10,
"name": "度小鹿①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4118&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -12,
"name": "度小鹿②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4119&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -11,
"name": "度小鹿③",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5118&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -91,
"name": "度灵儿",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5105&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -13,
"name": "度米朵①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -14,
"name": "度米朵②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4103&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -15,
"name": "度逍遥-基础",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=3&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -16,
"name": "度逍遥-精品①",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4003&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -17,
"name": "度逍遥-精品②",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5003&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -18,
"name": "情感女声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4105&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -19,
"name": "情感男声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4115&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -20,
"name": "标准女声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4100&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -90,
"name": "标准女声-基础",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=100&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -21,
"name": "标准男声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4121&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160=&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -89,
"name": "温柔女声",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4126&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -88,
"name": "甜美女声①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=1200&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=&rate=32=5&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -24,
"name": "甜美女声②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4117&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -25,
"name": "甜美女声③",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5117&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -22,
"name": "电台女声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5120&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=&rate=32=5&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -23,
"name": "电台男声",
"url": "http://tsn.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5121&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -26,
"name": "百度主持",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=9&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -87,
"name": "百度主持",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4127&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=11&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -86,
"name": "百度解说①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4123&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=12&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -85,
"name": "百度解说②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4128&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=12&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -84,
"name": "百度解说③",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4129&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=12&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -27,
"name": "百度评书①",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=6&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=301&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -28,
"name": "百度评书②",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=4114&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -83,
"name": "萝莉少女音",
"url": "http://tts.baidu.com/text2audio,{\n \"method\": \"POST\",\n \"body\": \"tex={{java.encodeURI(java.encodeURI(speakText))}}&spd={{(speakSpeed + 5) / 10 + 4}}&per=5201&cuid=baidu_speech_demo&idx=1&cod=2&lan=zh&ctp=1&pdt=160&vol=5&aue=6&pit=5&_res_tag_=audio\"\n}"
},
{
"id": -29,
"name": "阿里云语音",
"url": "<js>/*播音人Aiting可改其他https://cdn.jsdelivr.net/gh/Celeter/build/.github/scripts/speaker.json,详见https://ai.aliyun.com/nls/tts*/;eval(''+java.ajax('https://cdn.jsdelivr.net/gh/Celeter/build/.github/scripts/ttsDemo.js'));ttsDemo(speakText,speakSpeed,'Aiting')</js>"
}
]

@ -0,0 +1,107 @@
[
{
"bgStr": "#ffc0edc6",
"bgStrEInk": "#FFFFFF",
"bgStrNight": "#000000",
"bgType": 0,
"bgTypeEInk": 0,
"bgTypeNight": 0,
"darkStatusIcon": true,
"darkStatusIconEInk": true,
"darkStatusIconNight": false,
"footerMode": 0,
"footerPaddingBottom": 10,
"footerPaddingLeft": 13,
"footerPaddingRight": 17,
"footerPaddingTop": 0,
"headerMode": 0,
"headerPaddingBottom": 0,
"headerPaddingLeft": 19,
"headerPaddingRight": 16,
"headerPaddingTop": 10,
"letterSpacing": 0,
"lineSpacingExtra": 10,
"name": "微信读书",
"paddingBottom": 4,
"paddingLeft": 22,
"paddingRight": 22,
"paddingTop": 5,
"pageAnim": 3,
"pageAnimEInk": 3,
"paragraphIndent": "  ",
"paragraphSpacing": 6,
"showFooterLine": true,
"showHeaderLine": true,
"textBold": 0,
"textColor": "#ff0b0b0b",
"textColorEInk": "#000000",
"textColorNight": "#ADADAD",
"textSize": 24,
"tipColor": -10461088,
"tipFooterLeft": 7,
"tipFooterMiddle": 0,
"tipFooterRight": 6,
"tipHeaderLeft": 1,
"tipHeaderMiddle": 0,
"tipHeaderRight": 2,
"titleBottomSpacing": 0,
"titleMode": 0,
"titleSize": 4,
"titleTopSpacing": 0
},
{
"name": "预设1",
"bgStr": "#FFFFFF",
"bgStrNight": "#000000",
"textColor": "#000000",
"textColorNight": "#FFFFFF",
"bgType": 0,
"bgTypeNight": 0,
"darkStatusIcon": true,
"darkStatusIconNight": false
},
{
"name": "预设2",
"bgStr": "#DDC090",
"bgStrNight": "#3C3F43",
"textColor": "#3E3422",
"textColorNight": "#DCDFE1",
"bgType": 0,
"bgTypeNight": 0,
"darkStatusIcon": true,
"darkStatusIconNight": false
},
{
"name": "预设3",
"bgStr": "#C2D8AA",
"bgStrNight": "#3C3F43",
"textColor": "#596C44",
"textColorNight": "#88C16F",
"bgType": 0,
"bgTypeNight": 0,
"darkStatusIcon": false,
"darkStatusIconNight": false
},
{
"name": "预设4",
"bgStr": "#DBB8E2",
"bgStrNight": "#3C3F43",
"textColor": "#68516C",
"textColorNight": "#F6AEAE",
"bgType": 0,
"bgTypeNight": 0,
"darkStatusIcon": false,
"darkStatusIconNight": false
},
{
"name": "预设5",
"bgStr": "#ABCEE0",
"bgStrNight": "#3C3F43",
"textColor": "#3D4C54",
"textColorNight": "#90BFF5",
"bgType": 0,
"bgTypeNight": 0,
"darkStatusIcon": false,
"darkStatusIconNight": false
}
]

@ -0,0 +1,30 @@
[
{
"customOrder": 1,
"enableJs": true,
"enabled": true,
"singleUrl": true,
"sourceIcon": "http:\/\/ku.mumuceo.com\/static\/images\/applogo\/yuedu.png",
"sourceName": "使用说明",
"sourceUrl": "https://www.yuque.com/legado"
},
{
"customOrder": 2,
"enableJs": true,
"enabled": true,
"singleUrl": true,
"sourceIcon": "http:\/\/mmbiz.qpic.cn\/mmbiz_png\/hpfMV8hEuL2eS6vnCxvTzoOiaCAibV6exBzJWq9xMic9xDg3YXAick87tsfafic0icRwkQ5ibV0bJ84JtSuxhPuEDVquA\/0?wx_fmt=png",
"sourceName": "小说拾遗",
"sourceUrl": "snssdk1128:\/\/user\/profile\/562564899806367"
},
{
"customOrder": 3,
"enableJs": true,
"enabled": true,
"loadWithBaseUrl": false,
"singleUrl": true,
"sourceIcon": "https://Cloud.miaogongzi.net/images/icon.png",
"sourceName": "Meow云",
"sourceUrl": "https://pan.miaogongzi.net"
}
]

@ -2,50 +2,50 @@
{
"id": -1,
"enable": true,
"name": "目录",
"rule": "^[  \\t]{0,4}(?:序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|篇(?!张))).{0,30}$",
"name": "目录(去空白)",
"rule": "(?<=[ \\s])(?:序章|序言|卷首语|扉页|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|篇(?!张))).{0,30}$",
"serialNumber": 0
},
{
"id": -2,
"enable": true,
"name": "目录(去空白)",
"rule": "(?<=[ \\s])(?:序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|篇(?!张))).{0,30}$",
"name": "目录",
"rule": "^[  \\t]{0,4}(?:序章|序言|卷首语|扉页|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|篇(?!张))).{0,30}$",
"serialNumber": 1
},
{
"id": -3,
"enable": false,
"name": "目录(匹配简介)",
"rule": "(?<=[ \\s])(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"rule": "(?<=[ \\s])(?:(?:内容|文章)?简介|文案|前言|序章|序言|卷首语|扉页|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"serialNumber": 2
},
{
"id": -4,
"enable": false,
"name": "目录(古典、轻小说备用)",
"rule": "^[  \\t]{0,4}(?:序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|回(?![合来事去])|场(?![和合比电是])|篇(?!张))).{0,30}$",
"rule": "^[  \\t]{0,4}(?:序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|第?\\s{0,4}[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]+?\\s{0,4}(?:章|节(?!课)|卷|集(?![合和])|部(?![分赛游])|回(?![合来事去])|场(?![和合比电是])|话|篇(?!张))).{0,30}$",
"serialNumber": 3
},
{
"id": -5,
"enable": false,
"name": "数字(纯数字标题)",
"rule": "(?<=[ \\s])\\d+[  \\t]{0,4}$",
"rule": "(?<=[ \\s])\\d+\\.?[  \\t]{0,4}$",
"serialNumber": 4
},
{
"id": -6,
"enable": true,
"name": "数字 分隔符 标题名称",
"rule": "^[  \\t]{0,4}\\d{1,5}[,., 、_—\\-].{1,30}$",
"rule": "^[  \\t]{0,4}\\d{1,5}[::,., 、_—\\-].{1,30}$",
"serialNumber": 5
},
{
"id": -7,
"enable": true,
"name": "大写数字 分隔符 标题名称",
"rule": "^[  \\t]{0,4}[零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}[ 、_—\\-].{1,30}$",
"rule": "^[  \\t]{0,4}(?:序章|序言|卷首语|扉页|楔子|正文(?!完|结)|终章|后记|尾声|番外|[零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})[ 、_—\\-].{1,30}$",
"serialNumber": 6
},
{
@ -73,7 +73,7 @@
"id": -11,
"enable": true,
"name": "特殊符号 序号 标题",
"rule": "(?<=[\\s ])[【〔〖「『〈[\\[](?:第|[Cc]hapter)[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节].{0,20}$",
"rule": "(?<=[\\s ])[【〔〖「『〈[\\[](?:第|[Cc]hapter)[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,10}[章节].{0,20}$",
"serialNumber": 10
},
{
@ -94,7 +94,7 @@
"id": -14,
"enable": true,
"name": "章/卷 序号 标题",
"rule": "^[ \\t ]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|楔子|正文(?!完|结)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})[  ]{0,4}.{0,30}$",
"rule": "^[ \\t ]{0,4}(?:(?:内容|文章)?简介|文案|前言|序章|序言|卷首语|扉页|楔子|正文(?!完|结)|终章|后记|尾声|番外|[卷章][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8})[  ]{0,4}.{0,30}$",
"serialNumber": 13
},
{
@ -108,21 +108,21 @@
"id": -16,
"enable":false,
"name": "双标题(前向)",
"rule": "(?m)(?<=[ \\t ]{0,4})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$(?=[\\s ]{0,8}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章)",
"rule": "(?m)(?<=[ \\t ]{0,4})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$(?=[\\s ]{0,8}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章)",
"serialNumber": 15
},
{
"id": -17,
"enable":false,
"name": "双标题(后向)",
"rule": "(?m)(?<=[ \\t ]{0,4}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$[\\s ]{0,8})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$",
"rule": "(?m)(?<=[ \\t ]{0,4}第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$[\\s ]{0,8})第[\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}章.{0,30}$",
"serialNumber": 16
},
{
"id":-18,
"enable": true,
"name": "标题 特殊符号 序号",
"rule": "^.{1,20}[((][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}[))][  \t]{0,4}$",
"rule": "^.{1,20}[((][\\d零一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟]{1,8}[))][  \t]{0,4}$",
"serialNumber": 17
}
]
]

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Chapter</title>
<link href="../Styles/fonts.css" type="text/css" rel="stylesheet"/>
<link href="../Styles/main.css" type="text/css" rel="stylesheet"/>
</head>
<body>
<!--<div class="logo">
<img alt="" class="logo" src="../Images/logo.png"/>
</div>-->
<h2 class="head">{title}</h2>
{content}
</body>
</html>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Cover</title>
<style type="text/css">
.pic {
margin: 50% 30% 0 30%;
padding: 2px 2px;
border: 1px solid #f5f5dc;
background-color: rgba(250,250,250, 0);
border-radius: 1px;
}
</style>
</head>
<body style="text-align: center;">
<div class="pic"><img src="../Images/cover.jpg" style="width: 100%; height: auto;"/></div>
<h1 style="margin-top: 5%; font-size: 110%;">{name}</h1>
<div class="author" style="margin-top: 0;"><b>{author}</b> <span style="font-size: smaller;">/ 著</span></div>
</body>
</html>

@ -0,0 +1,267 @@
@charset "utf-8";
/*---常用---*/
@font-face {
font-family: "zw";
src:
local("宋体"),local("明体"),local("明朝"),
local("Songti"),local("Songti SC"),local("Songti TC"), /*iOS6+iBooks3*/
local("Song S"),local("Song T"),local("STBShusong"),local("TBMincho"),local("HYMyeongJo"), /*Kindle Paperwihite*/
local("DK-SONGTI"),
url(../Fonts/zw.ttf),
url(res:///opt/sony/ebook/FONT/zw.ttf),
url(res:///Data/FONT/zw.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/zw.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/zw.ttf),
url(res:///ebook/fonts/zw.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/zw.ttf),
url(res:///../../media/mmcblk0p1/fonts/zw.ttf),
url(file:///mnt/us/DK_System/system/fonts/zw.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/zw.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/zw.ttf),
url(res:///system/fonts/zw.ttf),
url(res:///system/media/sdcard/fonts/zw.ttf),
url(res:///media/fonts/zw.ttf),
url(res:///sdcard/fonts/zw.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/zw.ttf),
url(res:///media/flash/fonts/zw.ttf),
url(res:///media/sd/fonts/zw.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/zw.ttf),
url(res:///../fonts/zw.ttf),
url(../../../../../zw.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/zw.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/zw.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/zw.ttf);
/*ADE1,8, 2.0 Windows Path*/;
}
@font-face {
font-family: "fs";
src:
local("amasis30"),local("仿宋"),local("仿宋_GB2312"),
local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"), /*iOS6+iBooks3*/
local("DK-FANGSONG"),
url(../Fonts/fs.ttf),
url(res:///opt/sony/ebook/FONT/fs.ttf),
url(res:///Data/FONT/fs.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/fs.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/fs.ttf),
url(res:///ebook/fonts/fs.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/fs.ttf),
url(res:///../../media/mmcblk0p1/fonts/fs.ttf),
url(file:///mnt/us/DK_System/system/fonts/fs.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/fs.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/fs.ttf),
url(res:///system/fonts/fs.ttf),
url(res:///system/media/sdcard/fonts/fs.ttf),
url(res:///media/fonts/fs.ttf),
url(res:///sdcard/fonts/fs.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/fs.ttf),
url(res:///media/flash/fonts/fs.ttf),
url(res:///media/sd/fonts/fs.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/fs.ttf),
url(res:///../fonts/fs.ttf),
url(../../../../../fs.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/fs.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/fs.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/fs.ttf);
/*ADE1,8, 2.0 Windows Path*/;
}
@font-face {
font-family: "kt";
src:
local("Caecilia"),local("楷体"),local("楷体_GB2312"),
local("Kaiti"),local("Kaiti SC"),local("Kaiti TC"), /*iOS6+iBooks3*/
local("MKai PRC"),local("MKaiGB18030C-Medium"),local("MKaiGB18030C-Bold"), /*Kindle Paperwihite*/
local("DK-KAITI"),
url(../Fonts/kt.ttf),
url(res:///opt/sony/ebook/FONT/kt.ttf),
url(res:///Data/FONT/kt.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/kt.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/kt.ttf),
url(res:///ebook/fonts/kt.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/kt.ttf),
url(res:///../../media/mmcblk0p1/fonts/kt.ttf),
url(file:///mnt/us/DK_System/system/fonts/kt.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/kt.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/kt.ttf),
url(res:///system/fonts/kt.ttf),
url(res:///system/media/sdcard/fonts/kt.ttf),
url(res:///media/fonts/kt.ttf),
url(res:///sdcard/fonts/kt.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/kt.ttf),
url(res:///media/flash/fonts/kt.ttf),
url(res:///media/sd/fonts/kt.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/kt.ttf),
url(res:///../fonts/kt.ttf),
url(../../../../../kt.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/kt.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/kt.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/kt.ttf);
/*ADE1,8, 2.0 Windows Path*/;
}
@font-face {
font-family: "ht";
src:
local("黑体"),local("微软雅黑"),
local("Heiti"),local("Heiti SC"),local("Heiti TC"), /*iOS6+iBooks3*/
local("MYing Hei S"),local("MYing Hei T"),local("TBGothic"), /*Kindle Paperwihite*/
local("DK-HEITI"),
url(../Fonts/ht.ttf),
url(res:///opt/sony/ebook/FONT/ht.ttf),
url(res:///Data/FONT/ht.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/ht.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/ht.ttf),
url(res:///ebook/fonts/ht.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/ht.ttf),
url(res:///../../media/mmcblk0p1/fonts/ht.ttf),
url(file:///mnt/us/DK_System/system/fonts/ht.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/ht.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/ht.ttf),
url(res:///system/fonts/ht.ttf),
url(res:///system/media/sdcard/fonts/ht.ttf),
url(res:///media/fonts/ht.ttf),
url(res:///sdcard/fonts/ht.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/ht.ttf),
url(res:///media/flash/fonts/ht.ttf),
url(res:///media/sd/fonts/ht.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/ht.ttf),
url(res:///../fonts/ht.ttf),
url(../../../../../ht.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/ht.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/ht.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/ht.ttf);
/*ADE1,8, 2.0 Windows Path*/;
}
@font-face {
font-family:"h1";
src:
local("方正兰亭特黑长_GBK"),local("方正兰亭特黑长简体"),local("方正兰亭特黑长繁体"),
local("LantingTeheichang"),
local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"),
local("DK-HEITI"),
url(../Fonts/h1.ttf),
url(res:///opt/sony/ebook/FONT/h1.ttf),
url(res:///Data/FONT/h1.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/h1.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/h1.ttf),
url(res:///ebook/fonts/h1.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/h1.ttf),
url(res:///../../media/mmcblk0p1/fonts/h1.ttf),
url(file:///mnt/us/DK_System/system/fonts/h1.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/h1.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/h1.ttf),
url(res:///system/fonts/h1.ttf),
url(res:///system/media/sdcard/fonts/h1.ttf),
url(res:///media/fonts/h1.ttf),
url(res:///sdcard/fonts/h1.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/h1.ttf),
url(res:///media/flash/fonts/h1.ttf),
url(res:///media/sd/fonts/h1.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/h1.ttf),
url(res:///../fonts/h1.ttf),
url(../../../../../h1.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/h1.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/h1.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/h1.ttf); /*ADE1,8, 2.0 Windows Path*/
}
@font-face {
font-family:"h2";
src:
local("方正大标宋_GBK"),local("方正大标宋简体"),local("方正大标宋繁体"),
local("Dabiaosong"),
local("Heiti"),local("Heiti SC"),local("Heiti TC"),
local("DK-XIAOBIAOSONG"),
url(../Fonts/h2.ttf),
url(res:///opt/sony/ebook/FONT/h2.ttf),
url(res:///Data/FONT/h2.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/h2.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/h2.ttf),
url(res:///ebook/fonts/h2.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/h2.ttf),
url(res:///../../media/mmcblk0p1/fonts/h2.ttf),
url(file:///mnt/us/DK_System/system/fonts/h2.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/h2.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/h2.ttf),
url(res:///system/fonts/h2.ttf),
url(res:///system/media/sdcard/fonts/h2.ttf),
url(res:///media/fonts/h2.ttf),
url(res:///sdcard/fonts/h2.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/h2.ttf),
url(res:///media/flash/fonts/h2.ttf),
url(res:///media/sd/fonts/h2.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/h2.ttf),
url(res:///../fonts/h2.ttf),
url(../../../../../h2.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/h2.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/h2.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/h2.ttf); /*ADE1,8, 2.0 Windows Path*/
}
@font-face {
font-family:"h3";
src:
local("方正华隶_GBK"),local("方正行黑简体"),local("方正行黑繁体"),
local("Yuanti"),local("Yuanti SC"),local("Yuanti TC"),
local("DK-FANGSONG"),
url(../Fonts/h3.ttf),
url(res:///opt/sony/ebook/FONT/h3.ttf),
url(res:///Data/FONT/h3.ttf),
url(res:///opt/sony/ebook/FONT/tt0011m_.ttf),
url(res:///ebook/fonts/../../mnt/sdcard/fonts/h3.ttf),
url(res:///ebook/fonts/../../mnt/extsd/fonts/h3.ttf),
url(res:///ebook/fonts/h3.ttf),
url(res:///ebook/fonts/DroidSansFallback.ttf),
url(res:///fonts/ttf/h3.ttf),
url(res:///../../media/mmcblk0p1/fonts/h3.ttf),
url(file:///mnt/us/DK_System/system/fonts/h3.ttf), /*Duokan Old Path*/
url(file:///mnt/us/DK_System/xKindle/res/userfonts/h3.ttf), /*Duokan 2012 Path*/
url(res:///abook/fonts/h3.ttf),
url(res:///system/fonts/h3.ttf),
url(res:///system/media/sdcard/fonts/h3.ttf),
url(res:///media/fonts/h3.ttf),
url(res:///sdcard/fonts/h3.ttf),
url(res:///system/fonts/DroidSansFallback.ttf),
url(res:///mnt/MOVIFAT/font/h3.ttf),
url(res:///media/flash/fonts/h3.ttf),
url(res:///media/sd/fonts/h3.ttf),
url(res:///opt/onyx/arm/lib/fonts/AdobeHeitiStd-Regular.otf),
url(res:///../../fonts/h3.ttf),
url(res:///../fonts/h3.ttf),
url(../../../../../h3.ttf), /*EpubReaderI*/
url(res:///mnt/sdcard/fonts/h3.ttf), /*Nook for Android: fonts in TF Card*/
url(res:///fonts/h3.ttf), /*ADE1,8, 2.0 Program Path*/
url(res:///../../../../Windows/fonts/h3.ttf); /*ADE1,8, 2.0 Windows Path*/
}
@font-face {
font-family:"luohua";
src:local("汉仪落花体"),
url("../Fonts/hylh.ttf");
}

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN">
<head>
<title>Intro</title>
<link href="../Styles/fonts.css" type="text/css" rel="stylesheet" />
<link href="../Styles/main.css" type="text/css" rel="stylesheet" />
</head>
<body>
<h1 class="head" style="margin-bottom:2em;">内容简介</h1>{intro}</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

@ -0,0 +1,551 @@
@charset "utf-8";
@import url("../Styles/fonts.css");
body {
padding: 0%;
margin-top: 0%;
margin-bottom: 0%;
margin-left: 0.5%;
margin-right: 0.5%;
line-height: 130%;
text-align: justify;
font-family: "DK-SONGTI","st","宋体","zw",sans-serif;
}
p {
text-align: justify;
text-indent: 2em;
line-height: 130%;
margin-right: 0.5%;
margin-left: 0.5%;
font-family: "DK-SONGTI","st","宋体","zw",sans-serif;
}
p.kaiti {
font-family: "DK-KAITI","kt","楷体","zw",serif;
}
p.fangsong {
font-family: "DK-FANGSONG","fs","仿宋","zw",serif;
}
span.xinli {
font-family: "DK-KAITI","kt","楷体","zw",serif;
color: #4e753f;
}
/** 英文斜体字 **/
span.english{
font-style: italic;
}
div {
margin: 0px;
padding: 0px;
line-height: 120%;
text-align: justify;
font-family: "zw";
}
div.foot {
text-indent: 2em;
margin: 30% 5% 0 5%;
padding: 8px 0;
}
p.foot {
font-family: "DK-KAITI","kt","楷体","zw",serif;
}
/*扉页*/
.booksubtitle {
padding: 10px 0 0px 0;
text-indent: 0em;
font-size: 75%;
font-family: "ht";
}
.booktitle {
padding: 9% 0 0 0;
font-size: 1.3em;
font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG";
font-weight: normal;
text-indent: 0em;
color: #000;
text-align: center;
line-height: 1.6;
}
.booktitle0 {
font-size: 1.2em;
font-family: "fs";
text-indent: 0em;
text-align: center;
line-height: 1.8;
}
.booktitle1 {
padding: 0 0 0 0;
font-size: 0.85em;
font-family: "fs";
text-indent: 0em;
text-align: center;
line-height: 1.6;
}
.bookauthor {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
padding: 5% 5px 0px 5px;
text-indent: 0em;
text-align: center;
color: #000;
font-size: 90%;
line-height: 1.3;
}
.booktranslator {
padding: 1% 5px 0px 5px;
text-indent: 0em;
text-align: center;
font-size: 85%;
line-height: 1.3;
}
.bookpub {
font-family: "DK-KAITI","kt","楷体","楷体_gb2312";
padding: 30% 5px 5px 5px;
text-indent: 0em;
color: #000;
text-align: center;
font-size: 80%;
}
/*标题页*/
body.head {
background-repeat:no-repeat no-repeat;
background-size:160px 229px;
background-position:bottom right;
background-attachment:fixed;
}
body.xhead {
background-color: #FDF5E6;
}
h1.head {
font-family: "DK-HEITI",黑体,sans-serif;
font-size: 1.2em;
font-weight: bold;
color: #311a02;
text-indent: 0em;
font-weight: normal;
duokan-text-indent: 0em;
padding: auto;
text-align: center;
margin-top: -8em;
}
div.head {
border: solid 2px #ffffff;
padding: 2px;
margin: 2em auto 0.7em auto;
text-align: center;
width: 1em;
}
h1.head b {
font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG";
font-weight: bold;
font-size: 1.2em;
text-align: center;
text-indent: 0em;
duokan-text-indent: 0em;
color: #311a02;
margin: 0.5em auto;
line-height: 140%;
}
div.back {
text-align: center;
text-indent: 0em;
duokan-text-indent: 0em;
margin: 4em auto;
}
img.back {
width: 70%;
}
img.back2 {
width: 40%;
margin: 2em 0 0 0;
}
/*正文*/
/**楷体引文**/
.titou {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
}
.yinwen {
font-family: "DK-KAITI","kt","楷体","zw",serif;
margin-left: 2em;
text-indent: 0em;
}
.nicename {
font-family: "DK-HEITI",黑体,sans-serif;
font-weight: bold;
font-size: 0.9em;
}
body.head3 {
background-color: #a7bdcc;
color: #354f66;
}
body.head4 {
background-color: #bfd19b;
color: #4e753f;
}
h2.head {
font-family: "小标宋";
text-align: left;
font-weight: bold;
font-size: 1.1em;
margin: -3em 2em 2em 0;
color: #3f83e8;
line-height: 140%;
}
h2.head span {
font-family: "仿宋";
font-size: 0.7em;
background-color: #3f83e8;
border-radius: 9px;
padding: 4px;
color: #fff;
}
div.logo {
margin: -2em 0% 0 0;
text-align: right;
}
img.logo {
width: 40%;
}
.imgl {
/*图片居右*/
margin: -8.8em 1em 4em 0em;
width: 80%;
text-align: right;
}
h1.head {
line-height:130%;
font-size:1.4em;
text-align: center;
color: #BA2213;
font-weight: bold;
margin-top: 2em;
margin-bottom: 1em;
font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG";
}
h3 {
font-family: "DK-HEITI",黑体,sans-serif;
font-size: 1.1em;
margin: 1em 0;
border-left: 1.2em solid #00a1e9;
line-height: 120%;
padding-left: 3px;
color: #00a1e9;
}
h4 {
font-family: "DK-HEITI",黑体,sans-serif;
font-size: 1.1em;
text-align: center;
margin: 1em 0;
line-height: 120%;
color: #000;
}
h1.post {
font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG";
text-align: center;
font-size: 1.3em;
color: #026fca;
margin: 3em auto 2em auto;
}
.banquan {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
text-align: left;
color: #000;
font-size:1.1em;
margin-bottom:1em;
text-indent: 1em;
duokan-text-indent: 1em;
}
p.post {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
}
p.zy {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
margin: 1em 0 0 1em;
padding: 5px 0px 5px 10px;
text-indent: 0em;
border-left: 5px solid #a9b5c1;
}
.sign {
font-family: "DK-KAITI","kt","楷体","zw",serif;
margin: 1em 2px 0 auto;
text-align: right;
font-size: 0.8em;
text-indent: 0em;
duokan-text-indent: 0em;
}
.mark {
font-family: "DK-HEITI",黑体,sans-serif;
font-size: 0.9em;
color: #fff;
text-indent: 0em;
duokan-text-indent: 0em;
background-color: maroon;
text-align: center;
padding: 0px;
margin: 2em 30%;
}
/*出版社*/
.chubanshe img{
width:106px;
height:28px;
}
.chubanshe {
margin-top:20px;
}
.cr {
font-size:0.9em;
}
/*多看画廊*/
div.duokan-image-single {
text-align: center;
margin: 0.5em auto; /*插图盒子上下外边距为0.5em,左右设置auto是为了水平居中这个盒子*/
}
img.picture-80 {
margin: 0; /*清除img元素的外边距*/
width: 80%; /*预览窗口的宽度*/
box-shadow: 3px 3px 10px #bfbfbf; /*给图片添加阴影效果*/
}
p.duokan-image-maintitle {
margin: 1em 0 0; /*图片说明的段间距*/
font-family: "楷体"; /*图片说明使用的字体*/
font-size: 0.9em; /*字体大小*/
text-indent: 0; /*首行缩进为零,当你使用单标签p来指定首行缩进为2em时,记得在需要居中的文本中清除缩进,因为样式是叠加的*/
text-align: center; /*图片说明水平居中*/
color: #a52a2a; /*字体颜色*/
line-height: 1.25em; /*行高,防止有很长的图片说明*/
}
/*制作说明页*/
body.description {
background-image: url(../Images/001.png);
background-position: bottom center;
background-repeat: no-repeat;
background-size: cover;
padding: 25% 10% 0;
font-size: 0.9em;
}
div.description-body {
width: 55%;
padding: 2em 1.3em;
border-radius: 0.5em;
font-size: 0.9em;
border-style: solid;
border-color: #393939;
border-width: 0.3em;
border-radius: 5em;
background-color: #5a5a5a;
box-shadow: 2px 2px 3px #828281;
}
h1.description-title {
text-align: center;
font-family: "黑体";
font-size: 1.2em;
margin: 0 0 1em 0;
color: #FF9;
text-shadow: 1px 1px 0 black;
}
p.description-text {
color: #f9ddd2;
font-family: "准圆";
margin: 0;
text-align: justify;
text-indent: 0;
duokan-text-indent: 0;
}
hr.description-hr {
margin: 0.5em -1em;
border-style: dotted;
border-color: #9C9;
border-width: 0.05em 0 0 0;
}
p.tips {
text-align: justify;
text-indent: 0;
duokan-text-indent: 0;
font-family: "楷体";
font-size: 0.7em;
color: #FFC;
margin: 0;
}
/*版本说明页*/
.ver {
font-family: "DK-CODE","DK-XIHEITI",细黑体,"xihei",sans-serif;
font-weight: bold;
font-size: 100%;
color: #000;
margin: 1em 0 1em 0;
text-align: center;
}
.vertitle {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
font-size: 100%;
text-indent: 0em;
text-align: left;
duokan-text-indent: 0em;
}
.vertxt {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
line-height: 100%;
font-size: 85%;
text-indent: 0em;
text-align: left;
duokan-text-indent: 0em;
}
.verchar {
font-family: "DK-KAITI","kt","楷体","楷体_gb2312";
text-align: left;
text-indent: 1em;
duokan-text-indent: 1em;
margin-bottom: 1em;
margin-top: 1em;
}
.vernote {
font-family: "DK-FANGSONG",仿宋,"fs","fangsong",sans-serif;
font-size: 75%;
color: #686d70;
text-indent: 0em;
text-align: left;
duokan-text-indent: 0em;
padding-bottom: 15px;
}
.line {
border: dotted #A2906A;
border-width: 1px 0 0 0;
}
.entry {
margin-left: 18px;
font-size: 83%;
color: #8fe0a3;
text-indent: 0em;
duokan-text-indent: 0em;
}
/*版权信息*/
.vol {
text-indent: 0em;
text-align: center;
padding: 0.8em;
margin: 0 auto 3px auto;
color: #000;
font-family: "方正小标宋_GBK","DK-XIAOBIAOSONG";
font-size: 130%;
text-shadow: none;
}
.cp {
font-family: "DK-CODE","DK-XIHEITI",细黑体,"xihei",sans-serif;
color: #412938;
font-size: 70%;
text-align: left;
text-indent: 0em;
duokan-text-indent: 0em;
}
.xchar {
font-family: "DK-KAITI","kt","楷体","楷体_gb2312";
text-indent: 0em;
duokan-text-indent: 0em;
}
/*多看弹注*/
sup img {
line-height: 100%;
width: auto;
height: 1.0em;
margin: 0em;
padding: 0em;
vertical-align: text-top;
}
ol {
margin-bottom:0;
padding:0 auto;
list-style-type: decimal;
}
.hr {
width:50%;
margin:2em 0 0 0.5em;
padding:0;
height:2px;
background-color: #F3221D;
}
.duokan-footnote-content{
padding:0 auto;
text-align: left;
}
.duokan-footnote-item {
font-family:"DK-XIHEITI",细黑体,"xihei",sans-serif;
text-align: left;
font-size: 80%;
line-height: 100%;
clear: both;
color:#000;
list-style-type:decimal;
}
li.duokan-footnote-item a {
font-family:"DK-HEITI";
text-align: left;
}
a{
text-decoration: none;
color: #222;
}
a:hover {background: #81caf9}
a:active {background: yellow}
.duokan-image-maintitle {
font-family:"DK-HEITI",黑体,"hei",sans-serif;
text-align: center;
text-indent: 0em;
duokan-text-indent: 0em;
font-size:90%;
color: #1F4150;
margin-top: 1em;
}
.duokan-image-subtitle {
font-family:"DK-XIHEITI",细黑体,"xihei",sans-serif;
text-align: center;
text-indent: 0em;
duokan-text-indent: 0em;
font-size:70%;
color: #3A3348;
margin-top: 1em;
}

@ -1,129 +0,0 @@
## 常见问题
1.为什么第一次安装好之后什么东西都没有?
* 因为阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号[开源阅读]()、QQ群、酷安评论里获取由书友制作分享的书源。
2.如何导入本地书源文件?
* 下载群文件里的书源文件(书源格式后缀有txt、json,其中json文件某些情况下无法导入,需要修改后缀为txt格式才可导入);
* 打开阅读软件;
* 我的 - 点击“书源管理”;
* 点击右上角选择“本地导入”;
* 左下角选择书源文件所在的路径;
* 点击书源文件导入;
* 导入后返回书源管理界面;
* 新版qq下载路径:Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/
3.如何新建大佬发的单独书源?
* 复制书源代码;
* 打开阅读软件;
* 我的 - 点击“书源管理”;
* 右上角选择“新建书源”;
* 进入新建书源后点击右上角“粘贴源”;
* 粘贴书源完成后点击上方保存;
* 本次新建单独书源操作完成。
* 注:如果书源有错误或者复制不全会显示格式错误,请重新复制。
4.为什么导入2.0书源后看不了书?
* 2.0部分书源并不适用3.0,建议导入后进行筛选。
5.阅读2.0数据如何导入阅读3.0?
* 先对阅读2.0的数据进行备份,然后进入阅读3.0,点击“我的”,选择“备份与恢复”,再点击“导入旧版本数据”。
6.如何给朋友分享我的书源?
* 打开阅读软件;
* 点击备份;
* 打开手机自带的文件管理;
* 手机自带内存根目录找到YueDu3.0文件夹;
* 找到myBookSource.json长按选择分享;
* 选择微信分享或者QQ分享;
* 选择你要分享的好友点击发送;
* 好友接收后在手机自带内存根目录找到myBookSource.json文件(QQ在tencent--QQfile_recv微信在Tencent--MicroMsg--Download);
* 复制该文件到手机自带内存根目录找到YueDu3.0文件夹(如已有该文件请先删除该文件或者备份到其他地方再复制到文件夹);
* 打开阅读软件点击恢复。
* 注:备份路径如已修改过请在修改后的路径下查找书源文件。
7.目前阅读支持哪些格式的本地书籍?
* 目前支持TXT、EPUB格式(只支持显示EPUB里的文本内容,还不支持显示图片)。
8.如何刷新书架?
* 在书架界面下拉即可刷新。
9.书架界面书籍右上角的红色或者灰色背景小数字代表什么?
* 红色代表书籍有更新,灰色代表无更新,数字代表未读章节。
10.如何查看书籍详情?
* 长按书籍。
11.如何对书架上的书进行删除、切换书架的操作?
* 书籍详情页操作即可。
12.如何禁止或允许某本书更新?
* 书籍详情页,点击右上角 - “允许更新”。
13.如何更换小说封面、名字、作者或简介?
* 书籍详情页,点击右上角修改按钮。
14.怎么使用自定义字体?
* 阅读界面 - 字体-点击右上角选择字体文件路径。
15.目前支持哪些格式的字体文件?
* 目前支持ttf、otf格式。
16.书籍经常“正在加载中”怎么办?
* 在线书籍出现这个问题通常是由于源质量不好或不兼容引起的,可以换其它源多试试;本地书籍出现这个问题大概率是目录规则问题,手动切换规则可以解决。
17.书籍内容只有标题,正文内容是路径怎么办?
* 通常是缓存路径引起的,更换缓存路径即可。
18.效验书源显示失效就说明书源不能用了吗?
* 效验书源只是测试书源,可以做个参考,失效了不代表书源不能用了。
19.发现和正版书源能不能使用?
* 发现和正版书源只能用来找书,看排行榜,不能用来看书,如需看书请切换书源。
20.替换净化是什么?
* 替换净化可以去除书籍内容里的广告、错别字、屏蔽词等。
21.如何自己填写净化替换规则?
* 第一行:替换规则名称 - 根据自己需求对替换净化规则进行命名;
* 第二行:分组 - 净化规则的分组组别;
* 第三行:替换规则 - 填写需要被替换的内容;
* 第四行:替换为 - 填写想替换成的内容(如不填则默认表示删除第二行里填写的内容);
* 第五行:替换范围,选填书名或者源名 - 填写此替换净化规则需要对哪本书籍或者哪个书源生效(如不填则对所有书籍和书源生效)。
* 注:如常规去除方法去除不掉,则需要勾选“使用正则表达式”,同时第二行里的替换规则也需要按照正则表达式来填写(正则表达式填写方法可自行百度学习)。
22.如何听书?
* 可以使用手机自带的朗读引擎,也可使用第三方如谷歌、小米等朗读引擎。
* 【具体操作:安装-系统设置-其他高级设置-辅助功能-TTS输出-选择安装的朗读引擎(不同品牌手机的操作方法及步骤也不同,视情况而定)。】
23.如何设置屏幕方向、屏幕显示时长、显示/隐藏状态栏、显示/隐藏导航栏、音量键翻页、长按选择文本、点击总是翻下一页、自定义翻页案件?
* 阅读界面,设置(可上划,下面还有其他设置)。
24.搜索的时候感觉手机卡顿,如何解决?
* 我的 - 其他设置 - “更新和搜索线程数”调低。
25.更新前有什么注意事项?
* 要做好备份。
26.看书时如遇到“目录为空”、“加载失败”和长串英文等情况怎么办?
* 一般是书源问题,切换书源即可。
27.为什么书源这么多,发现里却只有一点点?
* 书源想要在发现界面里显示需要在书源里添加发现规则,并不是所有书源都有发现规则。
28.云备份在哪?
* 我的 - 备份与恢复 - WebDav设置。
29.如何操作进行云备份?
* 侧栏设置,WebDav设置;
* 正确填写WebDAV 服务器地址、WebDAV 账号、WebDAV 密码;(要获得这三项的信息,需要注册一个坚果云账号,如果直接在手机上注册,坚果云会让你下载app,过程比较麻烦,为了一步到位,最好是在电脑上打开这个注册链接:https://www.jianguoyun.com/d/signup;注册后,进入坚果云;点击右上角账户名处选择 “账户信息”,然后选择“安全选项”;在“安全选项” 中找到“第三方应用管理”,并选择“添加应用”,输入名称如“阅读”后,会生成密码,选择完成;其中https://dav.jianguoyun.com/dav/就是填入“WebDAV 服务器地址”的内容,“使用情况”后面的邮箱地址就是你的“WebDAV 账号”,点击显示密码后得到的密码就是你的“WebDAV 密码”。)
* 无需操作,APP默认每天自动云备份一次。
30.关于云备份的相关说明
* 在正确设置好云备份的情况下,APP默认每天自动云备份一次,当日多次手动云备份会对当日的旧云备份文件进行覆盖,并不会覆盖之前及之后不同日期的备份文件,每天所自动云备份的文件会按照日期进行命名。
31.本地备份和云备份都能备份哪些东西?
* 书架、看书进度、搜索记录、书源、替换、APP设置等都会备份,基本涵盖所有内容。
32.出现某些未知bug怎么办?
* 清除软件数据试试看,不行再进行反馈。

@ -0,0 +1,25 @@
# 书源管理界面帮助
* 书源右上角标志
* 绿点表示书源有发现,且启用了发现
* 红点表示书源有发现,但是未启用
* 没有标志表示此书源没有发现
* 右上角有分组菜单,可以按分组筛选书源
* 右上角更多菜单里包含
* 新建书源
* 本地导入
* 网络导入
* 二维码导入
* 分享选中源
* 选择源的更多操作在右下角的菜单里面,操作都是针对选择的书源
* 启用所选
* 禁用所选
* 添加分组
* 移除分组
* 启用发现
* 禁用发现
* 置顶所选
* 置底所选
* 导出所选
* 校验所选
* 校验失败的书源分组会加上"失效",选择"失效"分组即可批量操作

@ -0,0 +1,21 @@
# 订阅源管理界面帮助
* 订阅源可以通过规则订阅一些网络内容
* 书源右上角标志
* 绿点表示书源有发现,且启用了发现
* 红点表示书源有发现,但是未启用
* 没有标志表示此书源没有发现
* 右上角有分组菜单,可以按分组筛选书源
* 右上角更多菜单里包含
* 新建订阅源
* 本地导入
* 网络导入
* 二维码导入
* 分享选中源
* 选择源的更多操作在右下角的菜单里面,操作都是针对选择的书源
* 启用所选
* 禁用所选
* 置顶所选
* 置底所选
* 导出所选
* 校验失败的书源分组会加上"失效",选择"失效"分组即可批量操作

@ -0,0 +1,190 @@
# 帮助文档
## **新人必读**
【温馨提醒】 *本帮助可以在我的-右上角帮助按钮再次打开,更新前一定要做好备份,以免数据丢失!*
1. 为什么第一次安装好之后什么东西都没有?
* 阅读只是一个转码工具,不提供内容,第一次安装app,需要自己手动导入书源,可以从公众号 **[开源阅读]**、QQ群、酷安评论里获取由书友制作分享的书源。
2. 正文出现缺字漏字、内容缺失、排版错乱等情况,如何处理?
* 有可能是净化规则出现问题,先关闭替换净化并刷新,再观察是否正常。如果正常说明净化规则存在误杀,如果关闭后仍然出现相关问题,请点击源链接查看原文与正文是否相同,如果不同,再进行反馈。
3. 漫画源看书显示乱码,如何解决?
* 异次元和阅读是两个不同的软件,**两个软件的源并不通用**,请导入阅读的支持的漫画源!
## 书源相关
1. 如何导入本地书源文件?
* 下载群文件里的书源文件(书源格式后缀有txt、json,其中json文件某些情况下无法导入,需要修改后缀为txt格式才可导入);
* 打开阅读软件;
* 我的 - 点击“书源管理”;
* 点击右上角选择“本地导入”;
* 左下角选择书源文件所在的路径;
* 点击书源文件导入;
* 导入后返回书源管理界面;
* 新版qq下载路径:Android/data/com.tencent.mobileqq/Tencent/QQfile_recv/
![QQ导入书源](https://cdn.jsdelivr.net/gh/gedoor/gedoor.github.io@master/images/importSource.jpg)
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格式
2. 如何导入本地书籍?
* 在书架页面点击右上角,选择“添加本地”,授予相关权限后即可导入本地书籍。也可在文件管理器中使用 **阅读** 打开相关书籍。
3. 导入TXT文件提示“LoadTocError”或“List is empty”是怎么回事?
* 请先去应用详情中确认是否授予了阅读“读写手机存储”的权限。
* 自动识别目录失败,可能是相关目录规则未开启,请点击右上角的换源按钮手动更换目录规则。
* 如果尝试所有规则均无法识别,请在github上提交issue并附件相关txt文件,也可以发送邮件至i@qnmlgb.trade(标题:legado本地文件章节无法识别,内容对其具体情况进行简要说明,附件上传相关txt文件)。
4. 如何下载书籍到本地?
* 把在线书籍加入到书架后,在书架页面点击右上角,选择“离线缓存”即可。
5. 如何自定义导出的txt/epub文件名称?
* 点击 **离线缓存** - **导出文件名**.
* 使用方法:
- 导出文件名支持js语法
- 可用变量: name - 书名 author-作者
- 示例:
> {name+"作者:"+author}
- 导出文件名:
> Legado是最好的在线阅读软件 作者: kunfei.
**注意:** name、author等变量与字符串的拼接都需要在js环境中进行,即必须使用{ } 将变量与字符串包裹起来.
6. 为什么我打开本地的TXT文件,显示内容却是乱码?
* 部分编码在阅读上会识别错误,建议先用文本编辑器转换为常用的UTF-8格式。
7. 阅读对部分把正文(如所有含引号的句子)识别成标题,如何解决?
* 点击右上角更换目录规则即可。
## 书籍界面相关
1. 如何刷新书架?
* 在书架界面下拉即可刷新。
2. 书架界面书籍右上角的红色或者灰色背景小数字代表什么?
* 红色代表书籍有更新,灰色代表无更新,数字代表未读章节。
3. 如何查看书籍详情?
* 长按书籍。
4. 如何对书架上的书进行删除、切换书架的操作?
* 书籍详情页操作即可。
5. 如何禁止或允许某本书更新?
* 书籍详情页,点击右上角 - “允许更新”。
6. 如何更换小说封面、名字、作者或简介?
* 书籍详情页,点击右上角修改按钮。
7. 怎么使用自定义字体?
* 阅读界面 - 字体-点击右上角选择字体文件路径。
8. 目前支持哪些格式的字体文件?
* 目前支持ttf、otf格式。
9. 书籍经常“正在加载中”怎么办?
* 在线书籍出现这个问题通常是由于源质量不好或不兼容引起的,可以换其它源多试试;本地书籍出现这个问题大概率是目录规则问题,手动切换规则可以解决。
10. 书籍内容只有标题,正文内容是路径怎么办?
* 通常是缓存路径引起的,更换缓存路径即可。
11. 看书时如遇到“目录为空”、“加载失败”和长串英文等情况怎么办?
* 在线书籍一般是书源问题,切换或更新书源即可。本地书籍请尝试手动更换目录规则。
12. 为什么每一章的最后一页,阅读的文字和横线背景总是对不齐?
* 请在 设置-文字底部对齐 选项中关闭底部对齐,再调整排版。
13. 漫画源或图片章节只能看到第一页,如何解决?
* 请先查看原网页是否正常,若正常,请在书籍阅读界面点击右上角的 **⁝** 按钮,在弹出的菜单中,选择 **翻页动画(本书)**,将翻页动画更改为 **滚动**
14. 阅读图片章节、漫画或epub插图时,图片被缩放到一页中,以至无法看清,如何处理?
* 临时处理方案:长按图片可以进行双指缩放。图片章节请先参考Q13中的方案将翻页动画更改为**滚动**
* 3.0旧版可以点击书籍界面的章节标题进入 **编辑书源** 界面,在 正文-图片样式 中填入 *full*,保存更改,刷新当前章节即可。
* 3.0新版可以直接在书籍阅读界面点击右上角的 **⁝** 按钮,选择 图片样式- *full*.
## 替换净化相关
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,22 @@
# 书源调试
* 调试搜索>>输入关键字,如:
```
系统
```
* 调试发现>>输入发现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
```

@ -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"
}
```

File diff suppressed because one or more lines are too long

@ -0,0 +1,226 @@
# 正则表达式学习
- [基本匹配]
- [元字符]
- [英文句号]
- [字符集]
- [否定字符集]
- [重复]
- [星号]
- [加号]
- [问号]
- [花括号]
- [字符组]
- [分支结构]
- [转义特殊字符]
- [定位符]
- [插入符号]
- [美元符号]
- [简写字符集]
- [断言]
- [正向先行断言]
- [负向先行断言]
- [正向后行断言]
- [负向后行断言]
- [标记]
- [不区分大小写]
- [全局搜索]
- [多行匹配]
- [常用正则表达式]
## 1. 基本匹配
正则表达式只是我们用于在文本中检索字母和数字的模式。例如正则表达式 `cat`,表示: 字母 `c` 后面跟着一个字母 `a`,再后面跟着一个字母 `t`<pre>"cat" => The <a href="#learn-regex"><strong>cat</strong></a> sat on the mat</pre>
正则表达式 `123` 会匹配字符串 "123"。通过将正则表达式中的每个字符逐个与要匹配的字符串中的每个字符进行比较,来完成正则匹配。
正则表达式通常区分大小写,因此正则表达式 `Cat` 与字符串 "cat" 不匹配。<pre>"Cat" => The cat sat on the <a href="#learn-regex"><strong>Cat</strong></a></pre>
## 2. 元字符
元字符是正则表达式的基本组成元素。元字符在这里跟它通常表达的意思不一样,而是以某种特殊的含义去解释。有些元字符写在方括号内的时候有特殊含义。
元字符如下:
|元字符|描述|
|:----:|----|
|.|匹配除换行符以外的任意字符。|
|[ ]|字符类,匹配方括号中包含的任意字符。|
|[^ ]|否定字符类。匹配方括号中不包含的任意字符|
|*|匹配前面的子表达式零次或多次|
|+|匹配前面的子表达式一次或多次|
|?|匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。|
|{n,m}|花括号,匹配前面字符至少 n 次,但是不超过 m 次。|
|(xyz)|字符组,按照确切的顺序匹配字符xyz。|
|&#124;|分支结构,匹配符号之前的字符或后面的字符。|
|&#92;|转义符,它可以还原元字符原来的含义,允许你匹配保留字符 <code>[ ] ( ) { } . * + ? ^ $ \ &#124;</code>|
|^|匹配行的开始|
|$|匹配行的结束|
## 2.1 英文句号
英文句号 `.` 是元字符的最简单的例子。元字符 `.` 可以匹配任意单个字符。它不会匹配换行符和新行的字符。例如正则表达式 `.ar`,表示: 任意字符后面跟着一个字母 `a`
再后面跟着一个字母 `r`<pre>".ar" => The <a href="#learn-regex"><strong>car</strong></a> <a href="#learn-regex"><strong>par</strong></a>ked in the <a href="#learn-regex"><strong>gar</strong></a>age.</pre>
## 2.2 字符集
字符集也称为字符类。方括号被用于指定字符集。使用字符集内的连字符来指定字符范围。方括号内的字符范围的顺序并不重要。
例如正则表达式 `[Tt]he`,表示: 大写 `T` 或小写 `t` ,后跟字母 `h`,再后跟字母 `e`<pre>"[Tt]he" => <a href="#learn-regex"><strong>The</strong></a> car parked in <a href="#learn-regex"><strong>the</strong></a> garage.</pre>
然而,字符集中的英文句号表示它字面的含义。正则表达式 `ar[.]`,表示小写字母 `a`,后面跟着一个字母 `r`,再后面跟着一个英文句号 `.` 字符。<pre>"ar[.]" => A garage is a good place to park a c<a href="#learn-regex"><strong>ar.</strong></a></pre>
### 2.2.1 否定字符集
一般来说插入字符 `^` 表示一个字符串的开始,但是当它在方括号内出现时,它会取消字符集。例如正则表达式 `[^c]ar`,表示: 除了字母 `c` 以外的任意字符,后面跟着字符 `a`
再后面跟着一个字母 `r`<pre>"[^c]ar" => The car <a href="#learn-regex"><strong>par</strong></a>ked in the <a href="#learn-regex"><strong>gar</strong></a>age.</pre>
## 2.3 重复
以下元字符 `+`,`*` 或 `?` 用于指定子模式可以出现多少次。这些元字符在不同情况下的作用不同。
### 2.3.1 星号
该符号 `*` 表示匹配上一个匹配规则的零次或多次。正则表达式 `a*` 表示小写字母 `a` 可以重复零次或者多次。但是它如果出现在字符集或者字符类之后,它表示整个字符集的重复。
例如正则表达式 `[a-z]*`,表示: 一行中可以包含任意数量的小写字母。<pre>"[a-z]*" => T<a href="#learn-regex"><strong>he</strong></a> <a href="#learn-regex"><strong>car</strong></a> <a href="#learn-regex"><strong>parked</strong></a> <a href="#learn-regex"><strong>in</strong></a> <a href="#learn-regex"><strong>the</strong></a> <a href="#learn-regex"><strong>garage</strong></a> #21.</pre>
`*` 符号可以与元符号 `.` 用在一起,用来匹配任意字符串 `.*`。该 `*` 符号可以与空格符 `\s` 一起使用,用来匹配一串空格字符。
例如正则表达式 `\s*cat\s*`,表示: 零个或多个空格,后面跟小写字母 `c`,再后面跟小写字母 `a`,再再后面跟小写字母 `t`,后面再跟零个或多个空格。<pre>"\s*cat\s*" => The fat<a href="#learn-regex"><strong> cat </strong></a>sat on the <a href="#learn-regex"><strong>cat</strong></a>.</pre>
### 2.3.2 加号
该符号 `+` 匹配上一个字符的一次或多次。例如正则表达式 `c.+t`,表示: 一个小写字母 `c`,后跟任意数量的字符,后跟小写字母 `t`<pre>"c.+t" => The fat <a href="#learn-regex"><strong>cat sat on the mat</strong></a>.</pre>
### 2.3.3 问号
在正则表达式中,元字符 `?` 用来表示前一个字符是可选的。该符号匹配前一个字符的零次或一次。
例如正则表达式 `[T]?he`,表示: 可选的大写字母 `T`,后面跟小写字母 `h`,后跟小写字母 `e`<pre>"[T]he" => <a href="#learn-regex"><strong>The</strong></a> car is parked in the garage.</pre><pre>"[T]?he" => <a href="#learn-regex"><strong>The</strong></a> car is parked in t<a href="#learn-regex"><strong>he</strong></a> garage.</pre>
## 2.4 花括号
在正则表达式中花括号(也被称为量词 ?)用于指定字符或一组字符可以重复的次数。例如正则表达式 `[0-9]{2,3}`,表示: 匹配至少2位数字但不超过3位(0到9范围内的字符)。<pre>"[0-9]{2,3}" => The number was 9.<a href="#learn-regex"><strong>999</strong></a>7 but we rounded it off to <a href="#learn-regex"><strong>10</strong></a>.0.</pre>
我们可以省略第二个数字。例如正则表达式 `[0-9]{2,}`,表示: 匹配2个或更多个数字。如果我们也删除逗号,则正则表达式 `[0-9]{2}`,表示: 匹配正好为2位数的数字。<pre>"[0-9]{2,}" => The number was 9.<a href="#learn-regex"><strong>9997</strong></a> but we rounded it off to <a href="#learn-regex"><strong>10</strong></a>.0.</pre><pre>"[0-9]{2}" => The number was 9.<a href="#learn-regex"><strong>99</strong></a><a href="#learn-regex"><strong>97</strong></a> but we rounded it off to <a href="#learn-regex"><strong>10</strong></a>.0.</pre>
## 2.5 字符组
字符组是一组写在圆括号内的子模式 `(...)`。正如我们在正则表达式中讨论的那样,如果我们把一个量词放在一个字符之后,它会重复前一个字符。
但是,如果我们把量词放在一个字符组之后,它会重复整个字符组。
例如正则表达式 `(ab)*` 表示匹配零个或多个的字符串 "ab"。我们还可以在字符组中使用元字符 `|`。例如正则表达式 `(c|g|p)ar`,表示: 小写字母 `c`、`g` 或 `p` 后面跟字母 `a`,后跟字母 `r`<pre>"(c|g|p)ar" => The <a href="#learn-regex"><strong>car</strong></a> is <a href="#learn-regex"><strong>par</strong></a>ked in the <a href="#learn-regex"><strong>gar</strong></a>age.</pre>
## 2.6 分支结构
在正则表达式中垂直条 `|` 用来定义分支结构,分支结构就像多个表达式之间的条件。现在你可能认为这个字符集和分支机构的工作方式一样。
但是字符集和分支结构巨大的区别是字符集只在字符级别上有作用,然而分支结构在表达式级别上依然可以使用。
例如正则表达式 `(T|t)he|car`,表示: 大写字母 `T` 或小写字母 `t`,后面跟小写字母 `h`,后跟小写字母 `e` 或小写字母 `c`,后跟小写字母 `a`,后跟小写字母 `r`<pre>"(T|t)he|car" => <a href="#learn-regex"><strong>The</strong></a> <a href="#learn-regex"><strong>car</strong></a> is parked in <a href="#learn-regex"><strong>the</strong></a> garage.</pre>
## 2.7 转义特殊字符
正则表达式中使用反斜杠 `\` 来转义下一个字符。这将允许你使用保留字符来作为匹配字符 `{ } [ ] / \ + * . $ ^ | ?`。在特殊字符前面加 `\`,就可以使用它来做匹配字符。
例如正则表达式 `.` 是用来匹配除了换行符以外的任意字符。现在要在输入字符串中匹配 `.` 字符,正则表达式 `(f|c|m)at\.?`,表示: 小写字母 `f`、`c` 或者 `m` 后跟小写字母 `a`,后跟小写字母 `t`,后跟可选的 `.` 字符。<pre>"(f|c|m)at\.?" => The <a href="#learn-regex"><strong>fat</strong></a> <a href="#learn-regex"><strong>cat</strong></a> sat on the <a href="#learn-regex"><strong>mat.</strong></a></pre>
## 2.8 定位符
在正则表达式中,为了检查匹配符号是否是起始符号或结尾符号,我们使用定位符。
定位符有两种类型: 第一种类型是 `^` 检查匹配字符是否是起始字符,第二种类型是 `$`,它检查匹配字符是否是输入字符串的最后一个字符。
### 2.8.1 插入符号
插入符号 `^` 符号用于检查匹配字符是否是输入字符串的第一个字符。如果我们使用正则表达式 `^a` (如果a是起始符号)匹配字符串 `abc`,它会匹配到 `a`
但是如果我们使用正则表达式 `^b`,它是匹配不到任何东西的,因为在字符串 `abc` 中 "b" 不是起始字符。
让我们来看看另一个正则表达式 `^(T|t)he`,这表示: 大写字母 `T` 或小写字母 `t` 是输入字符串的起始符号,后面跟着小写字母 `h`,后跟小写字母 `e`<pre>"(T|t)he" => <a href="#learn-regex"><strong>The</strong></a> car is parked in <a href="#learn-regex"><strong>the</strong></a> garage.</pre><pre>"^(T|t)he" => <a href="#learn-regex"><strong>The</strong></a> car is parked in the garage.</pre>
### 2.8.2 美元符号
美元 `$` 符号用于检查匹配字符是否是输入字符串的最后一个字符。例如正则表达式 `(at\.)$`,表示: 小写字母 `a`,后跟小写字母 `t`,后跟一个 `.` 字符,且这个匹配器必须是字符串的结尾。<pre>"(at\.)" => The fat c<a href="#learn-regex"><strong>at.</strong></a> s<a href="#learn-regex"><strong>at.</strong></a> on the m<a href="#learn-regex"><strong>at.</strong></a></pre><pre>"(at\.)$" => The fat cat sat on the m<a href="#learn-regex"><strong>at.</strong></a></pre>
## 3. 简写字符集
正则表达式为常用的字符集和常用的正则表达式提供了简写。简写字符集如下:
|简写|描述|
|:----:|----|
|.|匹配除换行符以外的任意字符|
|\w|匹配所有字母和数字的字符: `[a-zA-Z0-9_]`|
|\W|匹配非字母和数字的字符: `[^\w]`|
|\d|匹配数字: `[0-9]`|
|\D|匹配非数字: `[^\d]`|
|\s|匹配空格符: `[\t\n\f\r\p{Z}]`|
|\S|匹配非空格符: `[^\s]`|
## 4. 断言
后行断言和先行断言有时候被称为断言,它们是特殊类型的 ***非捕获组*** (用于匹配模式,但不包括在匹配列表中)。当我们在一种特定模式之前或者之后有这种模式时,会优先使用断言。
例如我们想获取输入字符串 `$4.44 and $10.88` 中带有前缀 `$` 的所有数字。我们可以使用这个正则表达式 `(?<=\$)[0-9\.]*`,表示: 获取包含 `.` 字符且前缀为 `$` 的所有数字。
以下是正则表达式中使用的断言:
|符号|描述|
|:----:|----|
|?=|正向先行断言|
|?!|负向先行断言|
|?<=|正向后行断言|
|?<!|负向后行断言|
### 4.1 正向先行断言
正向先行断言认为第一部分的表达式必须是先行断言表达式。返回的匹配结果仅包含与第一部分表达式匹配的文本。
要在一个括号内定义一个正向先行断言,在括号中问号和等号是这样使用的 `(?=...)`。先行断言表达式写在括号中的等号后面。
例如正则表达式 `(T|t)he(?=\sfat)`,表示: 匹配大写字母 `T` 或小写字母 `t`,后面跟字母 `h`,后跟字母 `e`
在括号中,我们定义了正向先行断言,它会引导正则表达式引擎匹配 `The``the` 后面跟着 `fat`<pre>"(T|t)he(?=\sfat)" => <a href="#learn-regex"><strong>The</strong></a> fat cat sat on the mat.</pre>
### 4.2 负向先行断言
当我们需要从输入字符串中获取不匹配表达式的内容时,使用负向先行断言。负向先行断言的定义跟我们定义的正向先行断言一样,
唯一的区别是不是等号 `=`,我们使用否定符号 `!`,例如 `(?!...)`
我们来看看下面的正则表达式 `(T|t)he(?!\sfat)`,表示: 从输入字符串中获取全部 `The` 或者 `the` 且不匹配 `fat` 前面加上一个空格字符。<pre>"(T|t)he(?!\sfat)" => The fat cat sat on <a href="#learn-regex"><strong>the</strong></a> mat.</pre>
### 4.3 正向后行断言
正向后行断言是用于获取在特定模式之前的所有匹配内容。正向后行断言表示为 `(?<=...)`。例如正则表达式 `(?<=(T|t)he\s)(fat|mat)`,表示: 从输入字符串中获取在单词 `The``the` 之后的所有 `fat``mat` 单词。<pre>"(?<=(T|t)he\s)(fat|mat)" => The <a href="#learn-regex"><strong>fat</strong></a> cat sat on the <a href="#learn-regex"><strong>mat</strong></a>.</pre>
### 4.4 负向后行断言
负向后行断言是用于获取不在特定模式之前的所有匹配的内容。负向后行断言表示为 `(?<!...)`。例如正则表达式 `(?<!(T|t)he\s)(cat)`,表示: 在输入字符中获取所有不在 `The``the` 之后的所有单词 `cat`<pre>"(?&lt;!(T|t)he\s)(cat)" => The cat sat on <a href="#learn-regex"><strong>cat</strong></a>.</pre>
## 5. 标记
标记也称为修饰符,因为它会修改正则表达式的输出。这些标志可以以任意顺序或组合使用,并且是正则表达式的一部分。
|标记|描述|
|:----:|----|
|i|不区分大小写: 将匹配设置为不区分大小写。|
|g|全局搜索: 搜索整个输入字符串中的所有匹配。|
|m|多行匹配: 会匹配输入字符串每一行。|
### 5.1 不区分大小写
`i` 修饰符用于执行不区分大小写匹配。例如正则表达式 `/The/gi`,表示: 大写字母 `T`,后跟小写字母 `h`,后跟字母 `e`
但是在正则匹配结束时 `i` 标记会告诉正则表达式引擎忽略这种情况。正如你所看到的,我们还使用了 `g` 标记,因为我们要在整个输入字符串中搜索匹配。<pre>"The" => <a href="#learn-regex"><strong>The</strong></a> fat cat sat on the mat.</pre><pre>"/The/gi" => <a href="#learn-regex"><strong>The</strong></a> fat cat sat on <a href="#learn-regex"><strong>the</strong></a> mat.</pre>
### 5.2 全局搜索
`g` 修饰符用于执行全局匹配 (会查找所有匹配,不会在查找到第一个匹配时就停止)。
例如正则表达式 `/.(at)/g`,表示: 除换行符之外的任意字符,后跟小写字母 `a`,后跟小写字母 `t`
因为我们在正则表达式的末尾使用了 `g` 标记,它会从整个输入字符串中找到每个匹配项。<pre>".(at)" => The <a href="#learn-regex"><strong>fat</strong></a> cat sat on the mat.</pre><pre>"/.(at)/g" => The <a href="#learn-regex"><strong>fat</strong></a> <a href="#learn-regex"><strong>cat</strong></a> <a href="#learn-regex"><strong>sat</strong></a> on the <a href="#learn-regex"><strong>mat</strong></a>.</pre>
### 5.3 多行匹配
`m` 修饰符被用来执行多行的匹配。正如我们前面讨论过的 `(^, $)`,使用定位符来检查匹配字符是输入字符串开始或者结束。但是我们希望每一行都使用定位符,所以我们就使用 `m` 修饰符。
例如正则表达式 `/at(.)?$/gm`,表示: 小写字母 `a`,后跟小写字母 `t`,匹配除了换行符以外任意字符零次或一次。而且因为 `m` 标记,现在正则表达式引擎匹配字符串中每一行的末尾。<pre>"/.at(.)?$/" => The fat
cat sat
on the <a href="#learn-regex"><strong>mat.</strong></a></pre><pre>"/.at(.)?$/gm" => The <a href="#learn-regex"><strong>fat</strong></a>
cat <a href="#learn-regex"><strong>sat</strong></a>
on the <a href="#learn-regex"><strong>mat.</strong></a></pre>
## 常用正则表达式
* **数字**: `\d+$`
* **用户名**: `^[\w\d_.]{4,16}$`
* **字母数字字符**: `^[a-zA-Z0-9]*$`
* **带空格的字母数字字符**: `^[a-zA-Z0-9 ]*$`
* **小写字母**: `[a-z]+$`
* **大写字母**: `[A-Z]+$`
* **网址**: `^(((http|https|ftp):\/\/)?([[a-zA-Z0-9]\-\.])+(\.)([[a-zA-Z0-9]]){2,4}([[a-zA-Z0-9]\/+=%&_\.~?\-]*))*$`
* **日期 (MM/DD/YYYY)**: `^(0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.](19|20)?[0-9]{2}$`
* **日期 (YYYY/MM/DD)**: `^(19|20)?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])$`
* **求更求转发致谢**: `[\((【].*?[求更谢乐发推].*?[】)\)]`
* **查找最新章节**: `您可以.*?查找最新章节`
* **ps/PS**: `(?i)ps\b.*`
* **Html标签**: `<[^>]+?>`

@ -0,0 +1,6 @@
# 替换管理界面帮助
* 替换规则是用来替换正文内容的一种规则
* 菜单可以新建和导入规则
* 可以拖动排序
* 可以选择操作

@ -0,0 +1,177 @@
# 源规则帮助
* [书源帮助文档](https://alanskycn.gitee.io/teachme/Rule/source.html)
* [订阅源帮助文档](https://alanskycn.gitee.io/teachme/Rule/rss.html)
* [js扩展类](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/help/JsExtensions.kt)
* 辅助键盘❓中可插入URL参数模板,打开帮助,选择文件
* 规则标志, {{......}}内使用规则必须有明显的规则标志,没有规则标志当作js执行
```
@@ 默认规则,直接写时可以省略@@
@XPath: xpath规则,直接写时以//开头可省略@XPath
@Json: json规则,直接写时以$.开头可省略@Json
: regex规则,不可省略,只可以用在书籍列表和目录列表
```
* 发现url格式
```json
[
{
"title": "xxx",
"url": "",
"style": {
"layout_flexGrow": 0,
"layout_flexShrink": 1,
"layout_alignSelf": "auto",
"layout_flexBasisPercent": -1,
"layout_wrapBefore": false
}
}
]
```
* 获取登录后的cookie
```
java.getCookie("http://baidu.com", null) => userid=1234;pwd=adbcd
java.getCookie("http://baidu.com", "userid") => 1234
```
* 请求头,支持http代理,socks4 socks5代理设置
```
socks5代理
{
"proxy":"socks5://127.0.0.1:1080"
}
http代理
{
"proxy":"http://127.0.0.1:1080"
}
支持代理服务器验证
{
"proxy":"socks5://127.0.0.1:1080@用户名@密码"
}
注意:这些请求头是无意义的,会被忽略掉
```
* js 变量和函数
```
java 变量-当前类
baseUrl 变量-当前url,String
result 变量-上一步的结果
book 变量-书籍类,方法见 io.legado.app.data.entities.Book
cookie 变量-cookie操作类,方法见 io.legado.app.help.http.CookieStore
cache 变量-缓存操作类,方法见 io.legado.app.help.CacheManager
chapter 变量-当前目录类,方法见 io.legado.app.data.entities.BookChapter
title 变量-当前标题,String
src 内容,源码
```
* 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'"}
```
* 增加js方法,用于重定向拦截
* `java.get(urlStr: String, headers: Map<String, String>)`
* `java.post(urlStr: String, body: String, headers: Map<String, String>)`
* 对于搜索重定向的源,可以使用此方法获得重定向后的url
```
(()=>{
if(page==1){
let url='https://www.yooread.net/e/search/index.php,'+JSON.stringify({
"method":"POST",
"body":"show=title&tempid=1&keyboard="+key
});
return java.put('surl',String(java.connect(url).raw().request().url()));
} else {
return java.get('surl')+'&page='+(page-1)
}
})()
或者
(()=>{
let base='https://www.yooread.net/e/search/';
if(page==1){
let url=base+'index.php';
let body='show=title&tempid=1&keyboard='+key;
return base+java.put('surl',java.post(url,body,{}).header("Location"));
} else {
return base+java.get('surl')+'&page='+(page-1);
}
})()
```
* 正文图片链接支持修改headers
```
let options = {
"headers": {"User-Agent": "xxxx","Referrer":baseUrl,"Cookie":"aaa=vbbb;"}
};
'<img src="'+src+","+JSON.stringify(options)+'">'
```
## 部分js对象属性说明
上述js变量与函数中,一些js的对象属性用的频率较高,在此列举。方便写源的时候快速翻阅。
### book对象的可用属性
> 使用方法: 在js中或{{}}中使用book.属性的方式即可获取.如在正文内容后加上 ##{{book.name+"正文卷"+title}} 可以净化 书名+正文卷+章节名称(如 我是大明星正文卷第二章我爸是豪门总裁) 这一类的字符.
```
bookUrl // 详情页Url(本地书源存储完整文件路径)
tocUrl // 目录页Url (toc=table of Contents)
origin // 书源URL(默认BookType.local)
originName //书源名称 or 本地书籍文件名
name // 书籍名称(书源获取)
author // 作者名称(书源获取)
kind // 分类信息(书源获取)
customTag // 分类信息(用户修改)
coverUrl // 封面Url(书源获取)
customCoverUrl // 封面Url(用户修改)
intro // 简介内容(书源获取)
customIntro // 简介内容(用户修改)
charset // 自定义字符集名称(仅适用于本地书籍)
type // 0:text 1:audio
group // 自定义分组索引号
latestChapterTitle // 最新章节标题
latestChapterTime // 最新章节标题更新时间
lastCheckTime // 最近一次更新书籍信息的时间
lastCheckCount // 最近一次发现新章节的数量
totalChapterNum // 书籍目录总数
durChapterTitle // 当前章节名称
durChapterIndex // 当前章节索引
durChapterPos // 当前阅读的进度(首行字符的索引位置)
durChapterTime // 最近一次阅读书籍的时间(打开正文的时间)
canUpdate // 刷新书架时更新书籍信息
order // 手动排序
originOrder //书源排序
variable // 自定义书籍变量信息(用于书源规则检索书籍信息)
```
### chapter对象的可用属性
> 使用方法: 在js中或{{}}中使用chapter.属性的方式即可获取.如在正文内容后加上 ##{{chapter.title+chapter.index}} 可以净化 章节标题+序号(如 第二章 天仙下凡2) 这一类的字符.
```
url // 章节地址
title // 章节标题
baseUrl //用来拼接相对url
bookUrl // 书籍地址
index // 章节序号
resourceUrl // 音频真实URL
tag //
start // 章节起始位置
end // 章节终止位置
variable //变量
```
### 字体解析使用
> 使用方法,在正文替换规则中使用,原理根据f1字体的字形数据到f2中查找字形对应的编码
```
<js>
(function(){
var b64=String(src).match(/ttf;base64,([^\)]+)/);
if(b64){
var f1 = java.queryBase64TTF(b64[1]);
var f2 = java.queryTTF("https://alanskycn.gitee.io/teachme/assets/font/Source Han Sans CN Regular.ttf");
return java.replaceFont(result, f1, f2);
}
return result;
})()
</js>
```

@ -0,0 +1,19 @@
# WebDav备份教程
### 阅读支持云备份,采用WebDav协议,所有支持WebDav的云盘都可以,建议采用坚果云,每月免费1G流量,用来备份阅读足够了,下面就采用坚果云来讲解配置步骤.
1. 打开坚果云网站 https://www.jianguoyun.com/d/home#/
2. 如果没有注册过坚果云先注册一下
3. 登录坚果云
4. 右上角用户名点开点账户信息
5. 点击安全选项
6. 在第三方管理里添加应用
7. 将应用示例里的服务器地址,用户名,和密码填到阅读的WebDav设置里
8. 阅读的WebDav配置在我的-备份与恢复,创建子文件夹选项保持默认即可
9. 设置完成后手动执行一下备份,看看是否成功
10. 恢复时选择想要恢复的备份文件
### 自动备份说明
* 设置好备份之后每次退出App会自动进行备份
* WebDav同一天的备份会覆盖,不同日期的备份不会覆盖

@ -1,62 +0,0 @@
[
{
"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=3&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}"
}
]

@ -1,52 +0,0 @@
[
{
"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
}
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

@ -0,0 +1,150 @@
body {
margin: 0;
}
.editor {
display: flex;
align-items: stretch;
}
.setbox,
.menu,
.outbox {
flex: 1;
display: flex;
flex-flow: column;
max-height: 100vh;
overflow-y: auto;
}
.menu {
justify-content: center;
max-width: 90px;
margin: 0 5px;
}
.menu .button {
width: 90px;
height: 30px;
min-height: 30px;
margin: 5px 0px;
cursor: pointer;
}
@keyframes stroker {
0% {
stroke-dashoffset: 0;
}
100% {
stroke-dashoffset: -240;
}
}
.button rect {
width: 100%;
height: 100%;
fill: transparent;
stroke: #666;
stroke-width: 2px;
}
.button rect.busy {
stroke: #fd1850;
stroke-dasharray: 30 90;
animation: stroker 1s linear infinite;
}
.button text {
text-anchor: middle;
dominant-baseline: middle;
}
.setbox {
min-width: 40em;
}
.rules {
overflow: auto;
}
.tabbox {
flex: 1;
display: flex;
flex-flow: column;
}
.rules > * {
display: flex;
margin: 2px 0;
}
.rules textarea {
flex: 1;
margin-left: 5px;
}
.rules > *,
.rules > * > div,
.rules textarea {
min-height: 1em;
}
textarea {
word-break: break-all;
}
.tabtitle {
display: flex;
z-index: 1;
justify-content: flex-end;
}
.tabtitle > div {
cursor: pointer;
padding: 1px 10px 0 10px;
border-bottom: 3px solid transparent;
font-weight: bold;
}
.tabtitle > .this {
color: #4f9da6;
border-bottom-color: #4ebbe4;
}
.tabbody {
flex: 1;
display: flex;
margin-top: -1px;
border: 1px solid #a9a9a9;
height: 0;
}
.tabbody > * {
flex: 1;
flex-flow: column;
display: none;
}
.tabbody > .this {
display: flex;
}
.tabbody > * > .titlebar {
display: flex;
}
.tabbody > * > .titlebar > * {
flex: 1;
margin: 1px 1px 1px 1px;
}
.tabbody > * > .context {
flex: 1;
flex-flow: column;
border: 0;
padding: 5px;
overflow-y: auto;
}
.tabbody > * > .inputbox {
border: 0;
border-bottom: #a9a9a9 solid 1px;
height: 15px;
text-align: center;
}
.link > * {
display: flex;
margin: 5px;
border-bottom: 1px solid;
text-decoration: none;
}
#RuleList > label > * {
background: #eee;
padding-left: 3px;
margin: 2px 0;
cursor: pointer;
}
#RuleList input[type="radio"] {
display: none;
}
#RuleList input[type="radio"]:checked + * {
background: #15cda8;
}
.isError {
color: #ff0000;
}

@ -0,0 +1,401 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>阅读3.0书源编辑器_V4.0</title>
<link rel="icon" href="favicon.ico">
<link rel="stylesheet" type="text/css" href="index.css"/>
</head>
<body>
<div class="editor">
<div class="setbox">
<div>
<a href="../index.html">←主页</a>
</div>
<div class="rules">
<div><b>基本</b></div>
<div>
<div>源域名 :</div>
<textarea rows="1" id="bookSourceUrl" class="base" title="bookSourceUrl"
placeholder="<必填>通常填写网站主页,例: https://www.qidian.com"></textarea>
</div>
<div>
<div>源类型 :</div>
<textarea rows="1" id="bookSourceType" class="base" title="bookSourceType"
placeholder="&lt;必填&gt;0:文本 1:音频"></textarea>
</div>
<div>
<div>源名称 :</div>
<textarea rows="1" id="bookSourceName" class="base" title="bookSourceName"
placeholder="&lt;必填&gt;会显示在书源列表"></textarea>
</div>
<div>
<div>源分组 :</div>
<textarea rows="1" id="bookSourceGroup" class="base" title="bookSourceGroup"
placeholder="&lt;选填&gt;描述书源的特征信息"></textarea>
</div>
<div>
<div>源注释 :</div>
<textarea rows="1" id="bookSourceComment" class="base" title="bookSourceComment"
placeholder="&lt;选填&gt;描述书源作者和状态"></textarea>
</div>
<div>
<div>登录地址:</div>
<textarea rows="1" id="loginUrl" class="base" title="loginUrl"
placeholder="&lt;选填&gt;填写网站登录网址,仅在需要登录的书源有用"></textarea>
</div>
<div>
<div>链接验证:</div>
<textarea rows="1" id="bookUrlPattern" class="base" title="bookUrlPattern"
placeholder="&lt;选填&gt;当详情页URL与源URL的域名不一致时有效,用于添加网址"></textarea>
</div>
<div>
<div>请求头 :</div>
<textarea rows="3" id="header" class="base" title="header"
placeholder="&lt;选填&gt;客户端标识"></textarea>
</div>
<p></p>
<div><b>搜索</b></div>
<div>
<div>搜索地址:</div>
<textarea rows="3" id="searchUrl" class="base" title="searchUrl"
placeholder="[域名可省略]/search.php@kw={{key}}"></textarea>
</div>
<div>
<div>列表规则:</div>
<textarea rows="3" id="ruleSearch_bookList" class="ruleSearch" title="bookList"
placeholder="选择书籍节点 (规则结果为List&lt;Element&gt;)"></textarea>
</div>
<div>
<div>书名规则:</div>
<textarea rows="1" id="ruleSearch_name" class="ruleSearch" title="name"
placeholder="选择节点书名 (规则结果为String)"></textarea>
</div>
<div>
<div>作者规则:</div>
<textarea rows="1" id="ruleSearch_author" class="ruleSearch" title="author"
placeholder="选择节点作者 (规则结果为String)"></textarea>
</div>
<div>
<div>分类规则:</div>
<textarea rows="1" id="ruleSearch_kind" class="ruleSearch" title="kind"
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
</div>
<div>
<div>字数规则:</div>
<textarea rows="1" id="ruleSearch_wordCount" class="ruleSearch" title="wordCount"
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
</div>
<div>
<div>最新章节:</div>
<textarea rows="1" id="ruleSearch_lastChapter" class="ruleSearch"
title="lastChapter"
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
</div>
<div>
<div>简介规则:</div>
<textarea rows="1" id="ruleSearch_intro" class="ruleSearch" title="intro"
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
</div>
<div>
<div>封面规则:</div>
<textarea rows="1" id="ruleSearch_coverUrl" class="ruleSearch" title="coverUrl"
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
</div>
<div>
<div>详情地址:</div>
<textarea rows="1" id="ruleSearch_bookUrl" class="ruleSearch" title="bookUrl"
placeholder="选择书籍详情页网址 (规则结果为String类型的url)"></textarea>
</div>
<p></p>
<div><b>发现</b></div>
<div>
<div>发现地址:</div>
<textarea rows="6" id="exploreUrl" class="base" title="exploreUrl"
placeholder="内容能显示在发现菜单&#10;每行一条发现分类(网址域名可省略),例:&#10;名称1::网址(Url)1&#10;名称2::网址(Url)2&#10;..."></textarea>
</div>
<div>
<div>列表规则:</div>
<textarea rows="1" id="ruleExplore_bookList" class="ruleExplore" title="bookList"
placeholder="选择书籍节点 (规则结果为List&lt;Element&gt;)"></textarea>
</div>
<div>
<div>书名规则:</div>
<textarea rows="1" id="ruleExplore_name" class="ruleExplore" title="name"
placeholder="选择节点书名 (规则结果为String)"></textarea>
</div>
<div>
<div>作者规则:</div>
<textarea rows="1" id="ruleExplore_author" class="ruleExplore" title="author"
placeholder="选择节点作者 (规则结果为String)"></textarea>
</div>
<div>
<div>分类规则:</div>
<textarea rows="1" id="ruleExplore_kind" class="ruleExplore" title="kind"
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
</div>
<div>
<div>字数规则:</div>
<textarea rows="1" id="ruleExplore_wordCount" class="ruleExplore" title="wordCount"
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
</div>
<div>
<div>最新章节:</div>
<textarea rows="1" id="ruleExplore_lastChapter" class="ruleExplore"
title="lastChapter"
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
</div>
<div>
<div>简介规则:</div>
<textarea rows="1" id="ruleExplore_intro" class="ruleExplore" title="intro"
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
</div>
<div>
<div>封面规则:</div>
<textarea rows="1" id="ruleExplore_coverUrl" class="ruleExplore" title="coverUrl"
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
</div>
<div>
<div>详情地址:</div>
<textarea rows="1" id="ruleExplore_bookUrl" class="ruleExplore" title="bookUrl"
placeholder="选择书籍详情页网址 (规则结果为String类型的url)"></textarea>
</div>
<p></p>
<div><b>详情</b></div>
<div>
<div>预处理 :</div>
<textarea rows="3" id="ruleBookInfo_init" class="ruleBookInfo" title="init"
placeholder="用于加速详情信息检索,只支持AllInOne规则"></textarea>
</div>
<div>
<div>书名规则:</div>
<textarea rows="1" id="ruleBookInfo_name" class="ruleBookInfo" title="name"
placeholder="选择节点书名 (规则结果为String)"></textarea>
</div>
<div>
<div>作者规则:</div>
<textarea rows="1" id="ruleBookInfo_author" class="ruleBookInfo" title="author"
placeholder="选择节点作者 (规则结果为String)"></textarea>
</div>
<div>
<div>分类规则:</div>
<textarea rows="1" id="ruleBookInfo_kind" class="ruleBookInfo" title="kind"
placeholder="选择节点分类信息 (规则结果为String)"></textarea>
</div>
<div>
<div>字数规则:</div>
<textarea rows="1" id="ruleBookInfo_wordCount" class="ruleBookInfo"
title="wordCount"
placeholder="选择节点字数信息 (规则结果为String)"></textarea>
</div>
<div>
<div>最新章节:</div>
<textarea rows="1" id="ruleBookInfo_lastChapter" class="ruleBookInfo"
title="lastChapter"
placeholder="选择节点最新章节 (规则结果为String)"></textarea>
</div>
<div>
<div>简介规则:</div>
<textarea rows="1" id="ruleBookInfo_intro" class="ruleBookInfo" title="intro"
placeholder="选择节点书籍简介 (规则结果为String)"></textarea>
</div>
<div>
<div>封面规则:</div>
<textarea rows="1" id="ruleBookInfo_coverUrl" class="ruleBookInfo" title="coverUrl"
placeholder="选择节点书籍封面 (规则结果为String类型的url)"></textarea>
</div>
<div>
<div>目录地址:</div>
<textarea rows="1" id="ruleBookInfo_tocUrl" class="ruleBookInfo" title="tocUrl"
placeholder="选择书籍详情页网址 (规则结果为String类型的url, 与详情页相同时可省略)"></textarea>
</div>
<p></p>
<div><b>目录</b></div>
<div>
<div>列表规则:</div>
<textarea rows="3" id="ruleToc_chapterList" class="ruleToc" title="chapterList"
placeholder="选择目录列表的章节节点 (规则结果为List&lt;Element&gt;)"></textarea>
</div>
<div>
<div>章节名称:</div>
<textarea rows="1" id="ruleToc_chapterName" class="ruleToc" title="chapterName"
placeholder="选择章节名称 (规则结果为String)"></textarea>
</div>
<div>
<div>章节地址:</div>
<textarea rows="1" id="ruleToc_chapterUrl" class="ruleToc" title="chapterUrl"
placeholder="选择章节链接 (规则结果为String类型的Url)"></textarea>
</div>
<div>
<div>收费标识:</div>
<textarea rows="1" id="ruleToc_isVip" class="ruleToc" title="isVip"
placeholder="章节是否为VIP章节 (规则结果为Bool)"></textarea>
</div>
<div>
<div>章节信息:</div>
<textarea rows="1" id="ruleToc_updateTime" class="ruleToc" title="updateTime"
placeholder="选择章节信息 (规则结果为String)"></textarea>
</div>
<div>
<div>翻页规则:</div>
<textarea rows="1" id="ruleToc_nextTocUrl" class="ruleToc" title="nextTocUrl"
placeholder="选择目录下一页链接 (规则结果为List&lt;String&gt;或String)"></textarea>
</div>
<p></p>
<div><b>正文</b></div>
<div>
<div>脚本注入:</div>
<textarea rows="3" id="ruleContent_webJs" class="ruleContent" title="webJs"
placeholder="注入javascript,用于模拟鼠标点击等,必须有返回值,一般为String类型"></textarea>
</div>
<div>
<div>正文规则:</div>
<textarea rows="1" id="ruleContent_content" class="ruleContent" title="content"
placeholder="选择正文内容 (规则结果为String)"></textarea>
</div>
<div>
<div>翻页规则:</div>
<textarea rows="1" id="ruleContent_nextContentUrl" class="ruleContent"
title="nextContentUrl"
placeholder="选择下一分页(不是下一章)链接 (规则结果为String类型的Url)"></textarea>
</div>
<div>
<div>资源正则:</div>
<textarea rows="1" id="ruleContent_sourceRegex" class="ruleContent"
title="sourceRegex"
placeholder="匹配资源的url特征,用于嗅探"></textarea>
</div>
<div>
<div>替换规则:</div>
<textarea rows="1" id="ruleContent_replaceRegex" class="ruleContent"
title="replaceRegex"
placeholder="多页内容合并后替换,用于正文净化"></textarea>
</div>
<div>
<div>图片样式:</div>
<textarea rows="1" id="ruleContent_imageStyle" class="ruleContent"
title="imageStyle"
placeholder="FULL:铺满 不填:默认样式"></textarea>
</div>
<p></p>
<div><b>其它规则</b></div>
<div>
<div>启用搜索:</div>
<textarea rows="1" id="enabled" class="base" title="enabled"
placeholder="启用: true 关闭: false (可选,默认true)"></textarea>
</div>
<div>
<div>启用发现:</div>
<textarea rows="1" id="enabledExplore" class="base" title="enabledExplore"
placeholder="启用: true 关闭: false (可选,默认true)"></textarea>
</div>
<div>
<div>搜索权重:</div>
<textarea rows="1" id="weight" class="base" title="weight"
placeholder="整数: 0~N (可选,默认0) | 数字越大越靠前"></textarea>
</div>
<div>
<div>排序编号:</div>
<textarea rows="1" id="customOrder" class="base" title="customOrder"
placeholder="整数: 0~N (可选,默认0) | 数字越小越靠前"></textarea>
</div>
<div style="display:none;">
<div>更新时间:</div>
<textarea rows="1" id="lastUpdateTime" class="base" title="lastUpdateTime"
placeholder="毫秒级时间戳 (自动生成) | 请勿手动填写"></textarea>
</div>
</div>
</div>
<div class="menu">
<svg class="button">
<text x="50%" y="55%">⇈推送书源</text>
<rect id="push"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">⇊拉取书源</text>
<rect id="pull"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">⋘编辑书源</text>
<rect id="editor"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">⋙生成书源</text>
<rect id="conver"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">✗清空表单</text>
<rect id="initial"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">↶撤销操作</text>
<rect id="undo"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">↷重做操作</text>
<rect id="redo"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">⇏调试书源</text>
<rect id="debug"></rect>
</svg>
<svg class="button">
<text x="50%" y="55%">✓保存书源</text>
<rect id="accept"></rect>
</svg>
</div>
<div class="outbox">
<div class="tabbox">
<div class="tabtitle">
<div name="编辑书源" class="tab1 this">编辑书源</div>
<div name="调试书源" class="tab2">调试书源</div>
<div name="书源列表" class="tab3">书源列表</div>
<div name="帮助信息" class="tab4">帮助信息</div>
</div>
<div class="tabbody">
<div class="tab1 this">
<textarea class="context" id="RuleJsonString"
placeholder="这里输出序列化的JSON数据,可直接导入'阅读'APP"></textarea>
</div>
<div class="tab2">
<input type="text" class="inputbox" id="DebugKey" placeholder="输入搜索关键字,默认搜「我的」">
<textarea class="context" id="DebugConsole" placeholder="这里用于输出调试信息"></textarea>
</div>
<div class="tab3">
<input type="text" class="inputbox" id="Filter"
placeholder="输入筛选关键词(源名称、源URL或源分组)后按回车筛选源">
<div class="titlebar">
<button id="Import">导入书源文件</button>
<button id="Export">导出书源文件</button>
<button id="Delete">删除选中书源</button>
<button id="ClrAll">清空当前列表</button>
</div>
<div class="context" id="RuleList"></div>
</div>
<div class="tab4">
<div class="context link">
<a target="_blank" href="https://alanskycn.gitee.io/teachme">源制作教程</a>
<a target="_blank"
href="https://zhuanlan.zhihu.com/p/29436838">Xpath基础教程</a>
<a target="_blank"
href="https://zhuanlan.zhihu.com/p/32187820">Xpath高级教程</a>
<a target="_blank" href="https://www.w3cschool.cn/regex_rmjc">正则表达式教程</a>
<a target="_blank" href="https://regexr.com">正则表达式在线验证工具</a>
<div>^$()[]{}.?+*| 这些是Java正则特殊符号,匹配需转义
<br>(?s) 前缀表示跨行解析
<br>(?m) 前缀表示逐行匹配
<br>(?i) 前缀表示忽略大小写
</div>
<a target="_blank" href="https://www.beta.browxy.com">代码在线运行工具</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="index.js"></script>
</body>
</html>

@ -18,7 +18,7 @@ function hashParam(key, val) {
}
}
// 创建书源规则容器对象
const RuleJSON = (() => {
function Container() {
let ruleJson = {};
let searchJson = {};
let exploreJson = {};
@ -33,35 +33,29 @@ const RuleJSON = (() => {
ruleJson.weight = 0;
ruleJson.enabled = true;
ruleJson.enabledExplore = true;
ruleJson.bookSourceComment = ""
// 搜索规则
$$('.rules .ruleSearch').forEach(item => searchJson[item.title] = '');
//ruleJson.ruleSearch = JSON.stringify(searchJson);
ruleJson.ruleSearch = searchJson;
// 发现规则
$$('.rules .ruleExplore').forEach(item => exploreJson[item.title] = '');
//ruleJson.ruleExplore = JSON.stringify(exploreJson);
ruleJson.ruleExplore = exploreJson;
// 详情页规则
$$('.rules .ruleBookInfo').forEach(item => bookInfoJson[item.title] = '');
//ruleJson.ruleBookInfo = JSON.stringify(bookInfoJson);
ruleJson.ruleBookInfo = bookInfoJson;
// 目录规则
$$('.rules .ruleToc').forEach(item => tocJson[item.title] = '');
//ruleJson.ruleToc = JSON.stringify(tocJson);
ruleJson.ruleToc = tocJson;
// 正文规则
$$('.rules .ruleContent').forEach(item => contentJson[item.title] = '');
//ruleJson.ruleContent = JSON.stringify(contentJson);
ruleJson.ruleContent = contentJson;
return ruleJson;
})();
}
// 选项卡Tab切换事件处理
function showTab(tabName) {
$$('.tabtitle>*').forEach(node => { node.className = node.className.replace(' this', ''); });
@ -107,6 +101,7 @@ function HttpPost(url, data) {
}
// 将书源表单转化为书源对象
function rule2json() {
let RuleJSON = Container();
// 转换base
Object.keys(RuleJSON).forEach(key => {
if (!key.startsWith("rule")) {
@ -116,60 +111,55 @@ function rule2json() {
// 转换搜索规则
let searchJson = {};
//Object.keys(JSON.parse(RuleJSON.ruleSearch)).forEach(key => {
Object.keys(RuleJSON.ruleSearch).forEach(key => {
searchJson[key] = $('#' + 'ruleSearch_' + key).value;
if ($('#' + 'ruleSearch_' + key).value)
searchJson[key] = $('#' + 'ruleSearch_' + key).value;
});
//RuleJSON.ruleSearch = JSON.stringify(searchJson);
RuleJSON.ruleSearch = searchJson;
// 转换发现规则
let exploreJson = {};
//Object.keys(JSON.parse(RuleJSON.ruleExplore)).forEach(key => {
Object.keys(RuleJSON.ruleExplore).forEach(key => {
exploreJson[key] = $('#' + 'ruleExplore_' + key).value;
if ($('#' + 'ruleExplore_' + key).value)
exploreJson[key] = $('#' + 'ruleExplore_' + key).value;
});
//RuleJSON.ruleExplore = JSON.stringify(exploreJson);
RuleJSON.ruleExplore = exploreJson;
// 转换详情页规则
let bookInfoJson = {};
//Object.keys(JSON.parse(RuleJSON.ruleBookInfo)).forEach(key => {
Object.keys(RuleJSON.ruleBookInfo).forEach(key => {
bookInfoJson[key] = $('#' + 'ruleBookInfo_' + key).value;
if ($('#' + 'ruleBookInfo_' + key).value)
bookInfoJson[key] = $('#' + 'ruleBookInfo_' + key).value;
});
//RuleJSON.ruleBookInfo = JSON.stringify(bookInfoJson);
RuleJSON.ruleBookInfo = bookInfoJson;
// 转换目录规则
let tocJson = {};
//Object.keys(JSON.parse(RuleJSON.ruleToc)).forEach(key => {
Object.keys(RuleJSON.ruleToc).forEach(key => {
tocJson[key] = $('#' + 'ruleToc_' + key).value;
if ($('#' + 'ruleToc_' + key).value)
tocJson[key] = $('#' + 'ruleToc_' + key).value;
});
//RuleJSON.ruleToc = JSON.stringify(tocJson);
RuleJSON.ruleToc = tocJson;
// 转换正文规则
let contentJson = {};
//Object.keys(JSON.parse(RuleJSON.ruleContent)).forEach(key => {
Object.keys(RuleJSON.ruleContent).forEach(key => {
contentJson[key] = $('#' + 'ruleContent_' + key).value;
if ($('#' + 'ruleContent_' + key).value)
contentJson[key] = $('#' + 'ruleContent_' + key).value;
});
//RuleJSON.ruleContent = JSON.stringify(contentJson);
RuleJSON.ruleContent = contentJson;
RuleJSON.lastUpdateTime = RuleJSON.lastUpdateTime == '' ? 0 : parseInt(RuleJSON.lastUpdateTime);
RuleJSON.bookSourceComment = RuleJSON.bookSourceComment == '' ? "" : String(RuleJSON.bookSourceComment);
RuleJSON.lastUpdateTime = new Date().getTime();
RuleJSON.customOrder = RuleJSON.customOrder == '' ? 0 : parseInt(RuleJSON.customOrder);
RuleJSON.weight = RuleJSON.weight == '' ? 0 : parseInt(RuleJSON.weight);
RuleJSON.bookSourceType == RuleJSON.bookSourceType == '' ? 0 : parseInt(RuleJSON.weight);
RuleJSON.bookSourceType == RuleJSON.bookSourceType == '' ? 0 : parseInt(RuleJSON.bookSourceType);
RuleJSON.enabled = RuleJSON.enabled == '' || String(RuleJSON.enabled).toLocaleLowerCase().replace(/^\s*|\s*$/g, '') == 'true';
RuleJSON.enabledExplore = RuleJSON.enabledExplore == '' || String(RuleJSON.enabledExplore).toLocaleLowerCase().replace(/^\s*|\s*$/g, '') == 'true';
return RuleJSON;
}
// 将书源对象填充到书源表单
function json2rule(RuleEditor) {
let RuleJSON = Container();
// 转换base
Object.keys(RuleJSON).forEach(key => {
if (!key.startsWith("rule")) {
@ -188,9 +178,7 @@ function json2rule(RuleEditor) {
// 转换搜索规则
if (RuleEditor.ruleSearch) {
//let searchJson = JSON.parse(RuleEditor.ruleSearch);
let searchJson = RuleEditor.ruleSearch;
//Object.keys(JSON.parse(RuleJSON.ruleSearch)).forEach(key => {
Object.keys(RuleJSON.ruleSearch).forEach(key => {
$('#' + 'ruleSearch_' + key).value = searchJson[key] ? searchJson[key] : '';
});
@ -198,8 +186,6 @@ function json2rule(RuleEditor) {
// 转换发现规则
if (RuleEditor.ruleExplore) {
//let exploreJson = JSON.parse(RuleEditor.ruleExplore);
//Object.keys(JSON.parse(RuleJSON.ruleExplore)).forEach(key => {
let exploreJson = RuleEditor.ruleExplore;
Object.keys(RuleJSON.ruleExplore).forEach(key => {
$('#' + 'ruleExplore_' + key).value = exploreJson[key] ? exploreJson[key] : '';
@ -208,8 +194,6 @@ function json2rule(RuleEditor) {
// 转换详情页规则
if (RuleEditor.ruleBookInfo) {
//let bookInfoJson = JSON.parse(RuleEditor.ruleBookInfo);
//Object.keys(JSON.parse(RuleJSON.ruleBookInfo)).forEach(key => {
let bookInfoJson = RuleEditor.ruleBookInfo;
Object.keys(RuleJSON.ruleBookInfo).forEach(key => {
$('#' + 'ruleBookInfo_' + key).value = bookInfoJson[key] ? bookInfoJson[key] : '';
@ -218,8 +202,6 @@ function json2rule(RuleEditor) {
// 转换目录规则
if (RuleEditor.ruleToc) {
//let tocJson = JSON.parse(RuleEditor.ruleToc);
//Object.keys(JSON.parse(RuleJSON.ruleToc)).forEach(key => {
let tocJson = RuleEditor.ruleToc;
Object.keys(RuleJSON.ruleToc).forEach(key => {
$('#' + 'ruleToc_' + key).value = tocJson[key] ? tocJson[key] : '';
@ -228,8 +210,6 @@ function json2rule(RuleEditor) {
// 转换正文规则
if (RuleEditor.ruleContent) {
//let contentJson = JSON.parse(RuleEditor.ruleContent);
//Object.keys(JSON.parse(RuleJSON.ruleContent)).forEach(key => {
let contentJson = RuleEditor.ruleContent;
Object.keys(RuleJSON.ruleContent).forEach(key => {
$('#' + 'ruleContent_' + key).value = contentJson[key] ? contentJson[key] : '';
@ -378,15 +358,15 @@ $('.menu').addEventListener('click', e => {
ws.send(`{"tag":"${saveRule[0].bookSourceUrl}", "key":"${sKey}"}`);
};
ws.onmessage = (msg) => {
DebugPrint(msg.data == 'finish' ? `\n[${Date().split(' ')[4]}] 调试任务已完成!` : msg.data);
if (msg.data == 'finish') setRule(saveRule[0]);
console.log('[调试]', msg);
DebugPrint(msg.data);
};
ws.onerror = (err) => {
throw `${err.data}`;
}
ws.onclose = () => {
thisNode.setAttribute('class', '');
DebugPrint(`[${Date().split(' ')[4]}] 调试服务已关闭!`);
DebugPrint(`\n调试服务已关闭!`);
}
} else throw `${sResult.errorMsg}`;
}).catch(err => {
@ -533,4 +513,4 @@ $('.tab3>.titlebar').addEventListener('click', e => {
break;
default:
}
});
});

@ -1,176 +0,0 @@
html, body {
height: 100%;
margin: 0;
}
.hide {
display: none;
}
.top, .showchapter, .hidebooks {
width: 60px;
height: 50px;
position: absolute;
right: 30px;
bottom: 30px;
color: black;
font-size: 28px;
background-color: #ddd;
opacity: 0.85;
}
.top {
bottom: 150px;
}
.showchapter {
bottom: 90px;
bottom: 90px;
}
.address {
width: 270px;
}
.nav {
border-bottom: solid 1px #ccc;
}
input, button {
width: 110px;
line-height: 34px;
background-color: #eee;
color: #555;
border: none;
margin: 10px 5px;
font-weight: 500;
border-radius: 2px;
outline: none;
cursor: pointer;
}
input {
padding: 0 10px;
cursor: text;
}
input:hover, button:hover {
border-color: #aaa;
background-color: #efefef;
color: #222;
outline: solid 1px #ccc;
}
.allcontent {
height: calc(100% - 60px);
}
.allscreen {
height: 100%
}
.books > div {
display: inline-block;
margin: 10px;
vertical-align: top;
border: solid 1px #ddd;
}
.read > .books {
width: 420px;
float: left;
height: 100%;
overflow: auto;
border-right: solid 1px #ccc;
}
.read > .books > div {
margin-right: 0;
border-right: none;
}
.more {
overflow-y: auto;
height: 100%;
display: none;
}
.read .more {
display: block;
}
.books > div > img {
width: 120px;
height: 180px;
float: left;
margin-right: 10px;
cursor: pointer;
}
.info {
padding: 10px 20px 0 20px;
width: 600px;
margin: 0 auto;
}
.info > img {
width: 600px;
height: 900px;
}
.info p {
line-height: 1.5;
text-align: justify;
margin: 0;
}
.books tr:nth-child(n+2) td {
border-top: solid 1px #999;
}
.books td:nth-child(1) {
vertical-align: top;
width: 50px;
}
.books td:nth-child(2) {
vertical-align: top;
width: 200px;
}
.clear {
clear: both;
}
.chapter {
margin: 10px;
max-height: 500px;
overflow-y: auto;
border-top: solid 1px #333;
border-bottom: solid 1px #333;
}
.chapter button {
width: 230px;
text-align: left;
text-indent: 14px;
margin: 10px 4px;
}
.content {
padding: 20px;
text-align: justify;
min-height: 1000px;
padding-bottom: 200px;
}
.content h2 {
font-family: "Microsoft YaHei",微软雅黑,"MicrosoftJhengHei",华文细黑,STHeiti,MingLiu;
font-weight: 500;
text-align: center;
line-height: 100px;
font-size: 40px;
margin: 0;
}

@ -1,39 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>阅读3.0书架</title>
<link rel="icon" href="favicon.ico">
<link href="bookshelf.css" rel="stylesheet" />
</head>
<body>
<button id="top" class="top"></button>
<button id="showchapter" class="showchapter"></button>
<button id="hidebooks" class="hidebooks"></button>
<div class="nav">
<button id="back">返回</button>
<button id="type">所有书籍 ▼</button>
<button id="sort">手动排序 ▼</button>
<button id="setting">阅读设置</button>
<input type="text" class="address" id="address" title="阅读APP地址或IP" value="" />
<button id="refresh">重新加载</button>
</div>
<div class="allcontent" id="allcontent">
<div id="books" class="books"></div>
<div id="more" class="more">
<div id="info" class="info"></div>
<div class="clear"></div>
<div id="chapter" class="chapter"></div>
<div id="content" class="content"></div>
<div id="page" class="button">
<center><button id='up'>上一章</button><button id='down'>下一章</button></center>
</div>
</div>
</div>
<script src="bookshelf.js"></script>
</body>
</html>

@ -1,203 +0,0 @@
var $ = document.querySelector.bind(document)
, $$ = document.querySelectorAll.bind(document)
, $c = document.createElement.bind(document)
, randomImg = "http://api.mtyqx.cn/api/random.php"
, randomImg2 = "http://img.xjh.me/random_img.php"
, books
;
var now_chapter = -1;
var sum_chapter = 0;
var formatTime = value => {
return new Date(value).toLocaleString('zh-CN', {
hour12: false, year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"
}).replace(/\//g, "-");
};
var apiMap = {
"getBookshelf": "/getBookshelf",
"getChapterList": "/getChapterList",
"getBookContent": "/getBookContent",
"saveBook": "/saveBook"
};
var apiAddress = (apiName, url, index) => {
let address = $('#address').value || window.location.host;
if (!(/^http|^\/\//).test(address)) {
address = "//" + address;
}
if (!(/:\d{4,}/).test(address.split("//")[1].split("/")[0])) {
address += ":1122";
}
localStorage.setItem('address', address);
if (apiName == "getBookContent") {
return address + apiMap[apiName] + (url ? "?url=" + encodeURIComponent(url) : "") + "&index=" + index;
}
return address + apiMap[apiName] + (url ? "?url=" + encodeURIComponent(url) : "");
};
var init = () => {
$('#allcontent').classList.remove("read");
$('#books').innerHTML = "";
fetch(apiAddress("getBookshelf"), { mode: "cors" })
.then(res => res.json())
.then(data => {
if (!data.isSuccess) {
alert(getBookshelf.errorMsg);
return;
}
books = data.data;
books.forEach((book, i) => {
let bookDiv = $c("div");
let img = $c("img");
img.src = book.coverUrl || randomImg;
img.setAttribute("data-series-num", i);
bookDiv.appendChild(img);
bookDiv.innerHTML += `<table><tbody>
<tr><td>书名</td><td>${book.name}</td></tr>
<tr><td>作者</td><td>${book.author}</td></tr>
<tr><td>阅读</td><td>${book.durChapterTitle}<br>${formatTime(book.durChapterTime)}</td></tr>
<tr><td>更新</td><td>${book.latestChapterTitle}<br>${formatTime(book.latestChapterTime)}</td></tr>
<tr><td>来源</td><td>${book.origin}</td></tr>
</tbody></table>`;
$('#books').appendChild(bookDiv);
});
$$('#books img').forEach(bookImg =>
bookImg.addEventListener("click", () => {
now_chapter = -1;
sum_chapter = 0;
$('#allcontent').classList.add("read");
var book = books[bookImg.getAttribute("data-series-num")];
$("#info").innerHTML = `<img src="${bookImg.src}">
<p>  来源${book.origin}</p>
<p>  书名${book.name}</p>
<p>  作者${book.author}</p>
<p>阅读章节${book.durChapterName}</p>
<p>阅读时间${formatTime(book.durChapterTime)}</p>
<p>最新章节${book.latestChapterTitle}</p>
<p>检查时间${formatTime(book.lastCheckTime)}</p>
<p>  简介${book.intro.trim().replace(/\n/g, "<br>")}</p>`;
window.location.hash = "";
window.location.hash = "#info";
$("#content").innerHTML = "章节列表加载中...";
$("#chapter").innerHTML = "";
fetch(apiAddress("getChapterList", book.bookUrl), { mode: "cors" })
.then(res => res.json())
.then(data => {
if (!data.isSuccess) {
alert(data.errorMsg);
$("#content").innerHTML = "章节列表加载失败!";
return;
}
data.data.forEach(chapter => {
let ch = $c("button");
ch.setAttribute("data-url", chapter.bookUrl);
ch.setAttribute("data-index", chapter.index);
ch.setAttribute("title", chapter.title);
ch.innerHTML = chapter.title.length > 15 ? chapter.title.substring(0, 14) + "..." : chapter.title;
$("#chapter").appendChild(ch);
});
sum_chapter = data.data.length;
$('#chapter').scrollTop = 0;
$("#content").innerHTML = "章节列表加载完成!";
});
}));
});
};
$("#back").addEventListener("click", () => {
if (window.location.hash === "#content") {
window.location.hash = "#chapter";
} else if (window.location.hash === "#chapter") {
window.location.hash = "#info";
} else {
$('#allcontent').classList.remove("read");
}
});
$("#refresh").addEventListener("click", init);
$('#hidebooks').addEventListener("click", () => {
$("#books").classList.toggle("hide");
$(".nav").classList.toggle("hide");
$("#allcontent").classList.toggle("allscreen");
});
$('#top').addEventListener("click", () => {
window.location.hash = "";
window.location.hash = "#info";
});
$('#showchapter').addEventListener("click", () => {
window.location.hash = "";
window.location.hash = "#chapter";
});
$('#up').addEventListener('click', e => {
if (now_chapter > 0) {
now_chapter--;
let clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent("click", true, false);
$('[data-index="' + now_chapter + '"]').dispatchEvent(clickEvent);
} else if (now_chapter == 0) {
alert("已经是第一章了^_^!")
} else {
}
});
$('#down').addEventListener('click', e => {
if (now_chapter > -1) {
if (now_chapter < sum_chapter - 1) {
now_chapter++;
let clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent("click", true, false);
$('[data-index="' + now_chapter + '"]').dispatchEvent(clickEvent);
} else {
alert("已经是最后一章了^_^!")
}
}
});
$('#chapter').addEventListener("click", (e) => {
if (e.target.tagName === "BUTTON") {
var url = e.target.getAttribute("data-url");
var index = e.target.getAttribute("data-index");
var name = e.target.getAttribute("title");
if (!url) {
alert("未取得书籍地址");
}
if (!index && (0 != index)) {
alert("未取得章节索引");
}
now_chapter = parseInt(index);
$("#content").innerHTML = "<p>" + name + " 加载中...</p>";
fetch(apiAddress("getBookContent", url, index), { mode: "cors" })
.then(res => res.json())
.then(data => {
if (!data.isSuccess) {
alert(data.errorMsg);
$("#content").innerHTML = "<p>" + name + " 加载失败!</p>";
return;
}
var content = data.data.trim().split("\n\n");
if (content.length === 2) {
$("#content").innerHTML = `<h2>${content[0]}</h2>  (全文 ${content[1].length} 字)<br><br>  ` + content[1].trim().replace(/\n/g, "<br><br>");
} else {
$("#content").innerHTML = `<h2>${name || e.target.innerHTML}</h2>  (全文 ${data.data.length} 字)<br><br>  ` + data.data.trim().replace(/\n/g, "<br><br>");
}
window.location.hash = "";
window.location.hash = "#content";
});
}
});
$('#address').setAttribute("placeholder", "阅读APP地址或IP:" + window.location.host);
if (!$('#address').value && typeof localStorage && localStorage.getItem('address')) {
$('#address').value = localStorage.getItem('address');
}
init();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

@ -0,0 +1,43 @@
<!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.b9bb4fe0.css" rel="prefetch">
<link href="css/detail.e03dc50b.css" rel="prefetch">
<link href="js/about.9f8f9ac0.js" rel="prefetch">
<link href="js/about~detail.8270a871.js" rel="prefetch">
<link href="js/detail.4e6a53a9.js" rel="prefetch">
<link href="css/app.e4c919b7.css" rel="preload" as="style">
<link href="css/chunk-vendors.8a465a1d.css" rel="preload" as="style">
<link href="js/app.e84ee963.js" rel="preload" as="script">
<link href="js/chunk-vendors.3ef7796f.js" rel="preload" as="script">
<link href="css/chunk-vendors.8a465a1d.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.3ef7796f.js"></script>
<script src="js/app.e84ee963.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,70 @@
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "c6913d775f2f965ac5f3",
"url": "css/about.b9bb4fe0.css"
},
{
"revision": "c7b3e35a4e0391b1ed37",
"url": "css/app.e4c919b7.css"
},
{
"revision": "9a65f05f9810a3ea7f46",
"url": "css/chunk-vendors.8a465a1d.css"
},
{
"revision": "5ab5c6be15b21e2d609b",
"url": "css/detail.e03dc50b.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": "8a8424347500238b7b6c08a98d0f89af",
"url": "index.html"
},
{
"revision": "c6913d775f2f965ac5f3",
"url": "js/about.9f8f9ac0.js"
},
{
"revision": "5998ccb313ed338c15e1",
"url": "js/about~detail.8270a871.js"
},
{
"revision": "c7b3e35a4e0391b1ed37",
"url": "js/app.e84ee963.js"
},
{
"revision": "9a65f05f9810a3ea7f46",
"url": "js/chunk-vendors.3ef7796f.js"
},
{
"revision": "5ab5c6be15b21e2d609b",
"url": "js/detail.4e6a53a9.js"
},
{
"revision": "b46d04eb43bc31ca0f9f95121646440d",
"url": "manifest.json"
},
{
"revision": "b6216d61c03e6ce0c9aea6ca7808f7ca",
"url": "robots.txt"
}
]);

@ -14,7 +14,7 @@
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
importScripts(
"precache-manifest.9ae0b839acd886dbe2adc2f9d92aeabf.js"
"precache-manifest.5ae9ceec57e7f0f3cc808807b7fe5f32.js"
);
workbox.core.setCacheNameDetails({prefix: "yd-web-tool"});

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

@ -1,148 +0,0 @@
body {
margin: 0;
}
.editor {
display: flex;
align-items: stretch;
}
.setbox,
.menu,
.outbox {
flex: 1;
display: flex;
flex-flow: column;
max-height: 100vh;
overflow-y: auto;
}
.menu {
justify-content: center;
max-width: 90px;
margin: 0 5px;
}
.menu .button {
width: 90px;
height: 30px;
min-height: 30px;
margin: 5px 0px;
cursor: pointer;
}
@keyframes stroker {
0% {
stroke-dashoffset: 0
}
100% {
stroke-dashoffset: -240
}
}
.button rect {
width: 100%;
height: 100%;
fill: transparent;
stroke: #666;
stroke-width: 2px;
}
.button rect.busy {
stroke: #fD1850;
stroke-dasharray: 30 90;
animation: stroker 1s linear infinite;
}
.button text {
text-anchor: middle;
dominant-baseline: middle;
}
.setbox {
min-width: 40em;
}
.rules,
.tabbox {
flex: 1;
display: flex;
flex-flow: column;
}
.rules>* {
display: flex;
margin: 2px 0;
}
.rules textarea {
flex: 1;
margin-left: 5px;
}
.rules>*,
.rules>*>div,
.rules textarea {
min-height: 1em;
}
textarea {
word-break: break-all;
}
.tabtitle {
display: flex;
z-index: 1;
justify-content: flex-end;
}
.tabtitle>div {
cursor: pointer;
padding: 1px 10px 0 10px;
border-bottom: 3px solid transparent;
font-weight: bold;
}
.tabtitle>.this {
color: #4f9da6;
border-bottom-color: #4EBBE4;
}
.tabbody {
flex: 1;
display: flex;
margin-top: -1px;
border: 1px solid #A9A9A9;
height: 0;
}
.tabbody>* {
flex: 1;
flex-flow: column;
display: none;
}
.tabbody>.this {
display: flex;
}
.tabbody>*>.titlebar{
display: flex;
}
.tabbody>*>.titlebar>*{
flex: 1;
margin: 1px 1px 1px 1px;
}
.tabbody>*>.context {
flex: 1;
flex-flow: column;
border: 0;
padding: 5px;
overflow-y: auto;
}
.tabbody>*>.inputbox{
border: 0;
border-bottom: #A9A9A9 solid 1px;
height: 15px;
text-align:center;
}
.link>* {
display: flex;
margin: 5px;
border-bottom: 1px solid;
text-decoration: none;
}
#RuleList>label>* {
background: #eee;
padding-left: 3px;
margin: 2px 0;
cursor: pointer;
}
#RuleList input[type=radio] {
display: none;
}
#RuleList input[type="radio"]:checked+* {
background: #15cda8;
}
.isError {
color: #FF0000;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save