@ -0,0 +1,19 @@ |
|||||||
|
--- |
||||||
|
name: "[FeatureRequest] 功能请求模板" |
||||||
|
about: 提交你希望能够在阅读中增加的功能 |
||||||
|
title: "[Feature Request] " |
||||||
|
labels: '需求' |
||||||
|
assignees: '' |
||||||
|
--- |
||||||
|
|
||||||
|
### 功能描述(请清晰的、详细的描述你想要的功能) |
||||||
|
> |
||||||
|
|
||||||
|
### 期望实现方式(阅读应该如何实现该功能) |
||||||
|
> |
||||||
|
|
||||||
|
### 附加信息(其他的与功能相关的附加信息) |
||||||
|
> |
||||||
|
|
||||||
|
### 效果演示(可以手绘一些草图,或者提供可借鉴的图片) |
||||||
|
> |
@ -0,0 +1,98 @@ |
|||||||
|
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).json() |
||||||
|
log(f"{file_dir} -> {res['info']}") |
||||||
|
return res['zt'] == 1 |
||||||
|
|
||||||
|
|
||||||
|
# 上传文件夹内的文件 |
||||||
|
def upload_folder(folder_dir, folder_id): |
||||||
|
file_list = sorted(os.listdir(folder_dir), reverse=True) |
||||||
|
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) |
@ -0,0 +1,47 @@ |
|||||||
|
import os, sys, telebot |
||||||
|
|
||||||
|
# 上传文件 |
||||||
|
def upload_file(tb, chat_id, file_dir): |
||||||
|
doc = open(file_dir, 'rb') |
||||||
|
tb.send_document(chat_id, doc) |
||||||
|
|
||||||
|
# 上传文件夹内的文件 |
||||||
|
def upload_folder(tb, chat_id, folder_dir): |
||||||
|
file_list = sorted(os.listdir(folder_dir)) |
||||||
|
for file in file_list: |
||||||
|
path = os.path.join(folder_dir, file) |
||||||
|
if os.path.isfile(path): |
||||||
|
upload_file(tb, chat_id, path) |
||||||
|
else: |
||||||
|
upload_folder(tb, chat_id, path) |
||||||
|
|
||||||
|
# 上传 |
||||||
|
def upload(tb, chat_id, dir): |
||||||
|
if tb is None: |
||||||
|
log('ERROR: 输入正确的token') |
||||||
|
return |
||||||
|
if chat_id is None: |
||||||
|
log('ERROR: 输入正确的chat_id') |
||||||
|
return |
||||||
|
if dir is None: |
||||||
|
log('ERROR: 请指定上传的文件路径') |
||||||
|
return |
||||||
|
if os.path.isfile(dir): |
||||||
|
upload_file(tb, chat_id, dir) |
||||||
|
else: |
||||||
|
upload_folder(tb, chat_id, dir) |
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
argv = sys.argv[1:] |
||||||
|
if len(argv) != 3: |
||||||
|
log('ERROR: 参数错误,请以这种格式重新尝试\npython tg_bot.py $token $chat_id 待上传的路径') |
||||||
|
# Token |
||||||
|
TOKEN = argv[0] |
||||||
|
# chat_id |
||||||
|
chat_id = argv[1] |
||||||
|
# 待上传文件的路径 |
||||||
|
upload_path = argv[2] |
||||||
|
#创建连接 |
||||||
|
tb = telebot.TeleBot(TOKEN) |
||||||
|
#开始上传 |
||||||
|
upload(tb, chat_id, upload_path) |
@ -0,0 +1,32 @@ |
|||||||
|
#更新fork |
||||||
|
name: update fork |
||||||
|
|
||||||
|
on: |
||||||
|
schedule: |
||||||
|
- cron: '0 16 * * *' #设置定时任务 |
||||||
|
|
||||||
|
jobs: |
||||||
|
build: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
if: ${{ github.event.repository.owner.id == github.event.sender.id && github.actor != 'gedoor' }} |
||||||
|
steps: |
||||||
|
- name: Checkout |
||||||
|
uses: actions/checkout@v2 |
||||||
|
with: |
||||||
|
fetch-depth: 0 |
||||||
|
- name: Install git |
||||||
|
run: | |
||||||
|
sudo apt-get update |
||||||
|
sudo apt-get -y install git |
||||||
|
- name: Set env |
||||||
|
run: | |
||||||
|
git config --global user.email "github-actions@github.com" |
||||||
|
git config --global user.name "github-actions" |
||||||
|
- name: Update fork |
||||||
|
run: | |
||||||
|
git remote add upstream https://github.com/gedoor/legado.git |
||||||
|
git remote -v |
||||||
|
git fetch upstream |
||||||
|
git checkout master |
||||||
|
git merge upstream/master |
||||||
|
git push origin master |
@ -0,0 +1,99 @@ |
|||||||
|
name: Build and Release |
||||||
|
|
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- master |
||||||
|
paths: |
||||||
|
- 'CHANGELOG.md' |
||||||
|
# schedule: |
||||||
|
# - cron: '0 4 * * *' |
||||||
|
|
||||||
|
jobs: |
||||||
|
build: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
env: |
||||||
|
# 登录蓝奏云后在控制台运行document.cookie |
||||||
|
ylogin: ${{ secrets.LANZOU_ID }} |
||||||
|
phpdisk_info: ${{ secrets.LANZOU_PSD }} |
||||||
|
# 蓝奏云里的文件夹ID(阅读3测试版:2670621) |
||||||
|
LANZOU_FOLDER_ID: 'b0f7pt4ja' |
||||||
|
# 是否上传到artifact |
||||||
|
UPLOAD_ARTIFACT: 'true' |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
with: |
||||||
|
fetch-depth: 0 |
||||||
|
- 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: 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: Unify Version Name |
||||||
|
run: | |
||||||
|
echo "统一版本号" |
||||||
|
VERSION=$(date -d "8 hour" -u +3.%y.%m%d%H) |
||||||
|
echo "RELEASE_VERSION=$VERSION" >> $GITHUB_ENV |
||||||
|
sed "/def version/c def version = \"$VERSION\"" $GITHUB_WORKSPACE/app/build.gradle -i |
||||||
|
- name: Build With Gradle |
||||||
|
run: | |
||||||
|
echo "开始进行release构建" |
||||||
|
chmod +x gradlew |
||||||
|
./gradlew assembleRelease --build-cache --parallel |
||||||
|
- name: Organize the Files |
||||||
|
run: | |
||||||
|
mkdir -p ${{ github.workspace }}/apk/ |
||||||
|
cp -rf ${{ github.workspace }}/app/build/outputs/apk/*/*/*.apk ${{ github.workspace }}/apk/ |
||||||
|
- name: Upload App To Artifact |
||||||
|
if: ${{ env.UPLOAD_ARTIFACT != 'false' }} |
||||||
|
uses: actions/upload-artifact@v2 |
||||||
|
with: |
||||||
|
name: legado apk |
||||||
|
path: ${{ github.workspace }}/apk/*.apk |
||||||
|
- name: Upload App To Lanzou |
||||||
|
if: ${{ env.ylogin }} |
||||||
|
run: | |
||||||
|
path="$GITHUB_WORKSPACE/apk/" |
||||||
|
python3 $GITHUB_WORKSPACE/.github/scripts/lzy_web.py "$path" "$LANZOU_FOLDER_ID" |
||||||
|
echo "[$(date -u -d '+8 hour' '+%Y.%m.%d %H:%M:%S')] 分享链接: https://kunfei.lanzoux.com/b0f7pt4ja" |
||||||
|
- name: Release |
||||||
|
uses: softprops/action-gh-release@59c3b4891632ff9a897f99a91d7bc557467a3a22 |
||||||
|
with: |
||||||
|
name: legado_app_${{ env.RELEASE_VERSION }} |
||||||
|
tag_name: ${{ env.RELEASE_VERSION }} |
||||||
|
body_path: ${{ github.workspace }}/CHANGELOG.md |
||||||
|
draft: false |
||||||
|
prerelease: false |
||||||
|
files: ${{ github.workspace }}/apk/*.apk |
||||||
|
env: |
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
||||||
|
- name: Push Assets To "release" Branch |
||||||
|
run: | |
||||||
|
cd $GITHUB_WORKSPACE/apk || exit 1 |
||||||
|
git init |
||||||
|
git config --local user.name "github-actions[bot]" |
||||||
|
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" |
||||||
|
git checkout -b release |
||||||
|
git add *.apk |
||||||
|
git commit -m "${{ env.RELEASE_VERSION }}" |
||||||
|
git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" |
||||||
|
git push -f -u origin release |
||||||
|
- name: Purge Jsdelivr Cache |
||||||
|
run: | |
||||||
|
result=$(curl -s https://purge.jsdelivr.net/gh/${{ github.repository }}@release/) |
||||||
|
if echo $result |grep -q 'success.*true'; then |
||||||
|
echo "jsdelivr缓存更新成功" |
||||||
|
else |
||||||
|
echo $result |
||||||
|
fi |
@ -0,0 +1,161 @@ |
|||||||
|
name: Test Build |
||||||
|
|
||||||
|
on: |
||||||
|
push: |
||||||
|
branches: |
||||||
|
- master |
||||||
|
workflow_dispatch: |
||||||
|
|
||||||
|
jobs: |
||||||
|
prepare: |
||||||
|
runs-on: ubuntu-latest |
||||||
|
outputs: |
||||||
|
version: ${{ steps.set-ver.outputs.version }} |
||||||
|
versionL: ${{ steps.set-ver.outputs.versionL }} |
||||||
|
lanzou: ${{ steps.check.outputs.lanzou }} |
||||||
|
telegram: ${{ steps.check.outputs.telegram }} |
||||||
|
steps: |
||||||
|
- id: set-ver |
||||||
|
run: | |
||||||
|
echo "::set-output name=version::$(date -d "8 hour" -u +3.%y.%m%d%H)" |
||||||
|
echo "::set-output name=versionL::$(date -d "8 hour" -u +3.%y.%m%d%H%M)" |
||||||
|
- id: check |
||||||
|
run: | |
||||||
|
if [ ${{ secrets.LANZOU_ID }} ]; then |
||||||
|
echo "::set-output name=lanzou::yes" |
||||||
|
fi |
||||||
|
if [ ${{ secrets.BOT_TOKEN }} ]; then |
||||||
|
echo "::set-output name=telegram::yes" |
||||||
|
fi |
||||||
|
|
||||||
|
build: |
||||||
|
needs: prepare |
||||||
|
strategy: |
||||||
|
matrix: |
||||||
|
product: [app, google] |
||||||
|
type: [release, releaseA] |
||||||
|
fail-fast: false |
||||||
|
runs-on: ubuntu-latest |
||||||
|
env: |
||||||
|
product: ${{ matrix.product }} |
||||||
|
type: ${{ matrix.type }} |
||||||
|
VERSION: ${{ needs.prepare.outputs.version }} |
||||||
|
VERSIONL: ${{ needs.prepare.outputs.versionL }} |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
with: |
||||||
|
fetch-depth: 0 |
||||||
|
- 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: Build With Gradle |
||||||
|
run: | |
||||||
|
if [ ${{ env.type }} == 'release' ]; then |
||||||
|
typeName="原包名" |
||||||
|
else |
||||||
|
typeName="共存" |
||||||
|
sed "s/'.release'/'.releaseA'/" $GITHUB_WORKSPACE/app/build.gradle -i |
||||||
|
sed 's/.release/.releaseA/' $GITHUB_WORKSPACE/app/google-services.json -i |
||||||
|
fi |
||||||
|
echo "统一版本号" |
||||||
|
sed "/def version/c def version = \"${{ env.VERSION }}\"" $GITHUB_WORKSPACE/app/build.gradle -i |
||||||
|
echo "开始${{ env.product }}$typeName构建" |
||||||
|
chmod +x gradlew |
||||||
|
./gradlew assemble${{ env.product }}release --build-cache --parallel --daemon --warning-mode all |
||||||
|
echo "修改文件名" |
||||||
|
mkdir -p ${{ github.workspace }}/apk/ |
||||||
|
for file in `ls ${{ github.workspace }}/app/build/outputs/apk/*/*/*.apk`; do |
||||||
|
mv "$file" ${{ github.workspace }}/apk/legado_${{ env.product }}_${{ env.VERSIONL }}_$typeName.apk |
||||||
|
done |
||||||
|
- name: Upload App To Artifact |
||||||
|
uses: actions/upload-artifact@v2 |
||||||
|
with: |
||||||
|
name: legado.${{ env.product }}.${{ env.type }} |
||||||
|
path: ${{ github.workspace }}/apk/*.apk |
||||||
|
|
||||||
|
lanzou: |
||||||
|
needs: [prepare, build] |
||||||
|
if: ${{ needs.prepare.outputs.lanzou }} |
||||||
|
runs-on: ubuntu-latest |
||||||
|
env: |
||||||
|
# 登录蓝奏云后在控制台运行document.cookie |
||||||
|
ylogin: ${{ secrets.LANZOU_ID }} |
||||||
|
phpdisk_info: ${{ secrets.LANZOU_PSD }} |
||||||
|
# 蓝奏云里的文件夹ID(阅读3测试版:2670621) |
||||||
|
LANZOU_FOLDER_ID: '2670621' |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
- uses: actions/download-artifact@v2 |
||||||
|
with: |
||||||
|
path: apk/ |
||||||
|
- working-directory: apk/ |
||||||
|
run: mv */*.apk . ;rm -rf */ |
||||||
|
- name: Upload To Lanzou |
||||||
|
continue-on-error: true |
||||||
|
run: | |
||||||
|
path="$GITHUB_WORKSPACE/apk/" |
||||||
|
python3 $GITHUB_WORKSPACE/.github/scripts/lzy_web.py "$path" "$LANZOU_FOLDER_ID" |
||||||
|
echo "[$(date -u -d '+8 hour' '+%Y.%m.%d %H:%M:%S')] 分享链接: https://kunfei.lanzoux.com/b0f810h4b" |
||||||
|
|
||||||
|
test_Branch: |
||||||
|
needs: [prepare, build] |
||||||
|
runs-on: ubuntu-latest |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
- uses: actions/download-artifact@v2 |
||||||
|
with: |
||||||
|
path: apk/ |
||||||
|
- working-directory: apk/ |
||||||
|
run: mv */*.apk . ;rm -rf */ |
||||||
|
- name: Push To "test" Branch |
||||||
|
run: | |
||||||
|
cd $GITHUB_WORKSPACE/apk |
||||||
|
git init |
||||||
|
git config --local user.name "github-actions[bot]" |
||||||
|
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" |
||||||
|
git checkout -b test |
||||||
|
git add *.apk |
||||||
|
git commit -m "${{ needs.prepare.outputs.versionL }}" |
||||||
|
git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" |
||||||
|
git push -f -u origin test |
||||||
|
|
||||||
|
telegram: |
||||||
|
needs: [prepare, build] |
||||||
|
if: ${{ needs.prepare.outputs.telegram }} |
||||||
|
runs-on: ubuntu-latest |
||||||
|
env: |
||||||
|
CHANNEL_ID: ${{ secrets.CHANNEL_ID }} |
||||||
|
BOT_TOKEN: ${{ secrets.BOT_TOKEN }} |
||||||
|
steps: |
||||||
|
- uses: actions/checkout@v2 |
||||||
|
- uses: actions/download-artifact@v2 |
||||||
|
with: |
||||||
|
path: apk/ |
||||||
|
- working-directory: apk/ |
||||||
|
run: | |
||||||
|
for file in `ls */*.apk`; do |
||||||
|
mv "$file" "$(echo "$file"|sed -e 's#.*\/##g' -e "s/_/ /g" -e 's/legado/阅读/')" |
||||||
|
done |
||||||
|
rm -rf */ |
||||||
|
- name: Post to channel |
||||||
|
run: | |
||||||
|
pip install pyTelegramBotAPI |
||||||
|
path="$GITHUB_WORKSPACE/apk/" |
||||||
|
python3 $GITHUB_WORKSPACE/.github/scripts/tg_bot.py "$BOT_TOKEN" "$CHANNEL_ID" "$path" |
@ -0,0 +1,14 @@ |
|||||||
|
*.iml |
||||||
|
.gradle |
||||||
|
/local.properties |
||||||
|
.DS_Store |
||||||
|
/build |
||||||
|
/captures |
||||||
|
.externalNativeBuild |
||||||
|
/release |
||||||
|
/tmp |
||||||
|
node_modules/ |
||||||
|
/app/app |
||||||
|
/app/google |
||||||
|
/app/gradle.properties |
||||||
|
package-lock.json |
@ -0,0 +1,14 @@ |
|||||||
|
# Default ignored files |
||||||
|
/shelf/ |
||||||
|
/workspace.xml |
||||||
|
# Datasource local storage ignored files |
||||||
|
/dataSources/ |
||||||
|
/dataSources.local.xml |
||||||
|
# Editor-based HTTP Client requests |
||||||
|
/httpRequests/ |
||||||
|
# Custom ignored |
||||||
|
/caches/ |
||||||
|
/dictionaries/ |
||||||
|
/modules/ |
||||||
|
/libraries/ |
||||||
|
/*.xml |
@ -0,0 +1,125 @@ |
|||||||
|
<component name="ProjectCodeStyleConfiguration"> |
||||||
|
<code_scheme name="Project" version="173"> |
||||||
|
<JetCodeStyleSettings> |
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> |
||||||
|
</JetCodeStyleSettings> |
||||||
|
<codeStyleSettings language="XML"> |
||||||
|
<indentOptions> |
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" /> |
||||||
|
</indentOptions> |
||||||
|
<arrangement> |
||||||
|
<rules> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>xmlns:android</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>xmlns:.*</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
<order>BY_NAME</order> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>.*:id</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>.*:name</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>name</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>style</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>.*</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>^$</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
<order>BY_NAME</order> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>.*</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
<order>ANDROID_ATTRIBUTE_ORDER</order> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
<section> |
||||||
|
<rule> |
||||||
|
<match> |
||||||
|
<AND> |
||||||
|
<NAME>.*</NAME> |
||||||
|
<XML_ATTRIBUTE /> |
||||||
|
<XML_NAMESPACE>.*</XML_NAMESPACE> |
||||||
|
</AND> |
||||||
|
</match> |
||||||
|
<order>BY_NAME</order> |
||||||
|
</rule> |
||||||
|
</section> |
||||||
|
</rules> |
||||||
|
</arrangement> |
||||||
|
</codeStyleSettings> |
||||||
|
<codeStyleSettings language="kotlin"> |
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> |
||||||
|
<indentOptions> |
||||||
|
<option name="CONTINUATION_INDENT_SIZE" value="4" /> |
||||||
|
</indentOptions> |
||||||
|
</codeStyleSettings> |
||||||
|
</code_scheme> |
||||||
|
</component> |
@ -0,0 +1,5 @@ |
|||||||
|
<component name="ProjectCodeStyleConfiguration"> |
||||||
|
<state> |
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" /> |
||||||
|
</state> |
||||||
|
</component> |
@ -0,0 +1,20 @@ |
|||||||
|
<component name="InspectionProjectProfileManager"> |
||||||
|
<profile version="1.0"> |
||||||
|
<option name="myName" value="Project Default" /> |
||||||
|
<inspection_tool class="ConstantConditions" enabled="true" level="WARNING" enabled_by_default="true"> |
||||||
|
<option name="SUGGEST_NULLABLE_ANNOTATIONS" value="false" /> |
||||||
|
<option name="DONT_REPORT_TRUE_ASSERT_STATEMENTS" value="false" /> |
||||||
|
</inspection_tool> |
||||||
|
<inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true"> |
||||||
|
<option name="myValues"> |
||||||
|
<value> |
||||||
|
<list size="1"> |
||||||
|
<item index="0" class="java.lang.String" itemvalue="name" /> |
||||||
|
</list> |
||||||
|
</value> |
||||||
|
</option> |
||||||
|
<option name="myCustomValuesEnabled" value="true" /> |
||||||
|
</inspection_tool> |
||||||
|
<inspection_tool class="NonAsciiCharacters" enabled="false" level="WARNING" enabled_by_default="false" /> |
||||||
|
</profile> |
||||||
|
</component> |
@ -0,0 +1,6 @@ |
|||||||
|
<component name="InspectionProjectProfileManager"> |
||||||
|
<settings> |
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" /> |
||||||
|
<version value="1.0" /> |
||||||
|
</settings> |
||||||
|
</component> |
@ -0,0 +1,4 @@ |
|||||||
|
**2021/08/09** |
||||||
|
|
||||||
|
1. 修复选择文字不能选择单个文字的bug |
||||||
|
2. |
@ -0,0 +1,674 @@ |
|||||||
|
GNU GENERAL PUBLIC LICENSE |
||||||
|
Version 3, 29 June 2007 |
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> |
||||||
|
Everyone is permitted to copy and distribute verbatim copies |
||||||
|
of this license document, but changing it is not allowed. |
||||||
|
|
||||||
|
Preamble |
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for |
||||||
|
software and other kinds of works. |
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed |
||||||
|
to take away your freedom to share and change the works. By contrast, |
||||||
|
the GNU General Public License is intended to guarantee your freedom to |
||||||
|
share and change all versions of a program--to make sure it remains free |
||||||
|
software for all its users. We, the Free Software Foundation, use the |
||||||
|
GNU General Public License for most of our software; it applies also to |
||||||
|
any other work released this way by its authors. You can apply it to |
||||||
|
your programs, too. |
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not |
||||||
|
price. Our General Public Licenses are designed to make sure that you |
||||||
|
have the freedom to distribute copies of free software (and charge for |
||||||
|
them if you wish), that you receive source code or can get it if you |
||||||
|
want it, that you can change the software or use pieces of it in new |
||||||
|
free programs, and that you know you can do these things. |
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you |
||||||
|
these rights or asking you to surrender the rights. Therefore, you have |
||||||
|
certain responsibilities if you distribute copies of the software, or if |
||||||
|
you modify it: responsibilities to respect the freedom of others. |
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether |
||||||
|
gratis or for a fee, you must pass on to the recipients the same |
||||||
|
freedoms that you received. You must make sure that they, too, receive |
||||||
|
or can get the source code. And you must show them these terms so they |
||||||
|
know their rights. |
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps: |
||||||
|
(1) assert copyright on the software, and (2) offer you this License |
||||||
|
giving you legal permission to copy, distribute and/or modify it. |
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains |
||||||
|
that there is no warranty for this free software. For both users' and |
||||||
|
authors' sake, the GPL requires that modified versions be marked as |
||||||
|
changed, so that their problems will not be attributed erroneously to |
||||||
|
authors of previous versions. |
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run |
||||||
|
modified versions of the software inside them, although the manufacturer |
||||||
|
can do so. This is fundamentally incompatible with the aim of |
||||||
|
protecting users' freedom to change the software. The systematic |
||||||
|
pattern of such abuse occurs in the area of products for individuals to |
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we |
||||||
|
have designed this version of the GPL to prohibit the practice for those |
||||||
|
products. If such problems arise substantially in other domains, we |
||||||
|
stand ready to extend this provision to those domains in future versions |
||||||
|
of the GPL, as needed to protect the freedom of users. |
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents. |
||||||
|
States should not allow patents to restrict development and use of |
||||||
|
software on general-purpose computers, but in those that do, we wish to |
||||||
|
avoid the special danger that patents applied to a free program could |
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that |
||||||
|
patents cannot be used to render the program non-free. |
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and |
||||||
|
modification follow. |
||||||
|
|
||||||
|
TERMS AND CONDITIONS |
||||||
|
|
||||||
|
0. Definitions. |
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License. |
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of |
||||||
|
works, such as semiconductor masks. |
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this |
||||||
|
License. Each licensee is addressed as "you". "Licensees" and |
||||||
|
"recipients" may be individuals or organizations. |
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work |
||||||
|
in a fashion requiring copyright permission, other than the making of an |
||||||
|
exact copy. The resulting work is called a "modified version" of the |
||||||
|
earlier work or a work "based on" the earlier work. |
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based |
||||||
|
on the Program. |
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without |
||||||
|
permission, would make you directly or secondarily liable for |
||||||
|
infringement under applicable copyright law, except executing it on a |
||||||
|
computer or modifying a private copy. Propagation includes copying, |
||||||
|
distribution (with or without modification), making available to the |
||||||
|
public, and in some countries other activities as well. |
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other |
||||||
|
parties to make or receive copies. Mere interaction with a user through |
||||||
|
a computer network, with no transfer of a copy, is not conveying. |
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices" |
||||||
|
to the extent that it includes a convenient and prominently visible |
||||||
|
feature that (1) displays an appropriate copyright notice, and (2) |
||||||
|
tells the user that there is no warranty for the work (except to the |
||||||
|
extent that warranties are provided), that licensees may convey the |
||||||
|
work under this License, and how to view a copy of this License. If |
||||||
|
the interface presents a list of user commands or options, such as a |
||||||
|
menu, a prominent item in the list meets this criterion. |
||||||
|
|
||||||
|
1. Source Code. |
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work |
||||||
|
for making modifications to it. "Object code" means any non-source |
||||||
|
form of a work. |
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official |
||||||
|
standard defined by a recognized standards body, or, in the case of |
||||||
|
interfaces specified for a particular programming language, one that |
||||||
|
is widely used among developers working in that language. |
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other |
||||||
|
than the work as a whole, that (a) is included in the normal form of |
||||||
|
packaging a Major Component, but which is not part of that Major |
||||||
|
Component, and (b) serves only to enable use of the work with that |
||||||
|
Major Component, or to implement a Standard Interface for which an |
||||||
|
implementation is available to the public in source code form. A |
||||||
|
"Major Component", in this context, means a major essential component |
||||||
|
(kernel, window system, and so on) of the specific operating system |
||||||
|
(if any) on which the executable work runs, or a compiler used to |
||||||
|
produce the work, or an object code interpreter used to run it. |
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all |
||||||
|
the source code needed to generate, install, and (for an executable |
||||||
|
work) run the object code and to modify the work, including scripts to |
||||||
|
control those activities. However, it does not include the work's |
||||||
|
System Libraries, or general-purpose tools or generally available free |
||||||
|
programs which are used unmodified in performing those activities but |
||||||
|
which are not part of the work. For example, Corresponding Source |
||||||
|
includes interface definition files associated with source files for |
||||||
|
the work, and the source code for shared libraries and dynamically |
||||||
|
linked subprograms that the work is specifically designed to require, |
||||||
|
such as by intimate data communication or control flow between those |
||||||
|
subprograms and other parts of the work. |
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users |
||||||
|
can regenerate automatically from other parts of the Corresponding |
||||||
|
Source. |
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that |
||||||
|
same work. |
||||||
|
|
||||||
|
2. Basic Permissions. |
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of |
||||||
|
copyright on the Program, and are irrevocable provided the stated |
||||||
|
conditions are met. This License explicitly affirms your unlimited |
||||||
|
permission to run the unmodified Program. The output from running a |
||||||
|
covered work is covered by this License only if the output, given its |
||||||
|
content, constitutes a covered work. This License acknowledges your |
||||||
|
rights of fair use or other equivalent, as provided by copyright law. |
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not |
||||||
|
convey, without conditions so long as your license otherwise remains |
||||||
|
in force. You may convey covered works to others for the sole purpose |
||||||
|
of having them make modifications exclusively for you, or provide you |
||||||
|
with facilities for running those works, provided that you comply with |
||||||
|
the terms of this License in conveying all material for which you do |
||||||
|
not control copyright. Those thus making or running the covered works |
||||||
|
for you must do so exclusively on your behalf, under your direction |
||||||
|
and control, on terms that prohibit them from making any copies of |
||||||
|
your copyrighted material outside their relationship with you. |
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under |
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10 |
||||||
|
makes it unnecessary. |
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological |
||||||
|
measure under any applicable law fulfilling obligations under article |
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
||||||
|
similar laws prohibiting or restricting circumvention of such |
||||||
|
measures. |
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid |
||||||
|
circumvention of technological measures to the extent such circumvention |
||||||
|
is effected by exercising rights under this License with respect to |
||||||
|
the covered work, and you disclaim any intention to limit operation or |
||||||
|
modification of the work as a means of enforcing, against the work's |
||||||
|
users, your or third parties' legal rights to forbid circumvention of |
||||||
|
technological measures. |
||||||
|
|
||||||
|
4. Conveying Verbatim Copies. |
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you |
||||||
|
receive it, in any medium, provided that you conspicuously and |
||||||
|
appropriately publish on each copy an appropriate copyright notice; |
||||||
|
keep intact all notices stating that this License and any |
||||||
|
non-permissive terms added in accord with section 7 apply to the code; |
||||||
|
keep intact all notices of the absence of any warranty; and give all |
||||||
|
recipients a copy of this License along with the Program. |
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey, |
||||||
|
and you may offer support or warranty protection for a fee. |
||||||
|
|
||||||
|
5. Conveying Modified Source Versions. |
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to |
||||||
|
produce it from the Program, in the form of source code under the |
||||||
|
terms of section 4, provided that you also meet all of these conditions: |
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified |
||||||
|
it, and giving a relevant date. |
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is |
||||||
|
released under this License and any conditions added under section |
||||||
|
7. This requirement modifies the requirement in section 4 to |
||||||
|
"keep intact all notices". |
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this |
||||||
|
License to anyone who comes into possession of a copy. This |
||||||
|
License will therefore apply, along with any applicable section 7 |
||||||
|
additional terms, to the whole of the work, and all its parts, |
||||||
|
regardless of how they are packaged. This License gives no |
||||||
|
permission to license the work in any other way, but it does not |
||||||
|
invalidate such permission if you have separately received it. |
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display |
||||||
|
Appropriate Legal Notices; however, if the Program has interactive |
||||||
|
interfaces that do not display Appropriate Legal Notices, your |
||||||
|
work need not make them do so. |
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent |
||||||
|
works, which are not by their nature extensions of the covered work, |
||||||
|
and which are not combined with it such as to form a larger program, |
||||||
|
in or on a volume of a storage or distribution medium, is called an |
||||||
|
"aggregate" if the compilation and its resulting copyright are not |
||||||
|
used to limit the access or legal rights of the compilation's users |
||||||
|
beyond what the individual works permit. Inclusion of a covered work |
||||||
|
in an aggregate does not cause this License to apply to the other |
||||||
|
parts of the aggregate. |
||||||
|
|
||||||
|
6. Conveying Non-Source Forms. |
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms |
||||||
|
of sections 4 and 5, provided that you also convey the |
||||||
|
machine-readable Corresponding Source under the terms of this License, |
||||||
|
in one of these ways: |
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product |
||||||
|
(including a physical distribution medium), accompanied by the |
||||||
|
Corresponding Source fixed on a durable physical medium |
||||||
|
customarily used for software interchange. |
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product |
||||||
|
(including a physical distribution medium), accompanied by a |
||||||
|
written offer, valid for at least three years and valid for as |
||||||
|
long as you offer spare parts or customer support for that product |
||||||
|
model, to give anyone who possesses the object code either (1) a |
||||||
|
copy of the Corresponding Source for all the software in the |
||||||
|
product that is covered by this License, on a durable physical |
||||||
|
medium customarily used for software interchange, for a price no |
||||||
|
more than your reasonable cost of physically performing this |
||||||
|
conveying of source, or (2) access to copy the |
||||||
|
Corresponding Source from a network server at no charge. |
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the |
||||||
|
written offer to provide the Corresponding Source. This |
||||||
|
alternative is allowed only occasionally and noncommercially, and |
||||||
|
only if you received the object code with such an offer, in accord |
||||||
|
with subsection 6b. |
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated |
||||||
|
place (gratis or for a charge), and offer equivalent access to the |
||||||
|
Corresponding Source in the same way through the same place at no |
||||||
|
further charge. You need not require recipients to copy the |
||||||
|
Corresponding Source along with the object code. If the place to |
||||||
|
copy the object code is a network server, the Corresponding Source |
||||||
|
may be on a different server (operated by you or a third party) |
||||||
|
that supports equivalent copying facilities, provided you maintain |
||||||
|
clear directions next to the object code saying where to find the |
||||||
|
Corresponding Source. Regardless of what server hosts the |
||||||
|
Corresponding Source, you remain obligated to ensure that it is |
||||||
|
available for as long as needed to satisfy these requirements. |
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided |
||||||
|
you inform other peers where the object code and Corresponding |
||||||
|
Source of the work are being offered to the general public at no |
||||||
|
charge under subsection 6d. |
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded |
||||||
|
from the Corresponding Source as a System Library, need not be |
||||||
|
included in conveying the object code work. |
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any |
||||||
|
tangible personal property which is normally used for personal, family, |
||||||
|
or household purposes, or (2) anything designed or sold for incorporation |
||||||
|
into a dwelling. In determining whether a product is a consumer product, |
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular |
||||||
|
product received by a particular user, "normally used" refers to a |
||||||
|
typical or common use of that class of product, regardless of the status |
||||||
|
of the particular user or of the way in which the particular user |
||||||
|
actually uses, or expects or is expected to use, the product. A product |
||||||
|
is a consumer product regardless of whether the product has substantial |
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent |
||||||
|
the only significant mode of use of the product. |
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods, |
||||||
|
procedures, authorization keys, or other information required to install |
||||||
|
and execute modified versions of a covered work in that User Product from |
||||||
|
a modified version of its Corresponding Source. The information must |
||||||
|
suffice to ensure that the continued functioning of the modified object |
||||||
|
code is in no case prevented or interfered with solely because |
||||||
|
modification has been made. |
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or |
||||||
|
specifically for use in, a User Product, and the conveying occurs as |
||||||
|
part of a transaction in which the right of possession and use of the |
||||||
|
User Product is transferred to the recipient in perpetuity or for a |
||||||
|
fixed term (regardless of how the transaction is characterized), the |
||||||
|
Corresponding Source conveyed under this section must be accompanied |
||||||
|
by the Installation Information. But this requirement does not apply |
||||||
|
if neither you nor any third party retains the ability to install |
||||||
|
modified object code on the User Product (for example, the work has |
||||||
|
been installed in ROM). |
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a |
||||||
|
requirement to continue to provide support service, warranty, or updates |
||||||
|
for a work that has been modified or installed by the recipient, or for |
||||||
|
the User Product in which it has been modified or installed. Access to a |
||||||
|
network may be denied when the modification itself materially and |
||||||
|
adversely affects the operation of the network or violates the rules and |
||||||
|
protocols for communication across the network. |
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided, |
||||||
|
in accord with this section must be in a format that is publicly |
||||||
|
documented (and with an implementation available to the public in |
||||||
|
source code form), and must require no special password or key for |
||||||
|
unpacking, reading or copying. |
||||||
|
|
||||||
|
7. Additional Terms. |
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this |
||||||
|
License by making exceptions from one or more of its conditions. |
||||||
|
Additional permissions that are applicable to the entire Program shall |
||||||
|
be treated as though they were included in this License, to the extent |
||||||
|
that they are valid under applicable law. If additional permissions |
||||||
|
apply only to part of the Program, that part may be used separately |
||||||
|
under those permissions, but the entire Program remains governed by |
||||||
|
this License without regard to the additional permissions. |
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option |
||||||
|
remove any additional permissions from that copy, or from any part of |
||||||
|
it. (Additional permissions may be written to require their own |
||||||
|
removal in certain cases when you modify the work.) You may place |
||||||
|
additional permissions on material, added by you to a covered work, |
||||||
|
for which you have or can give appropriate copyright permission. |
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you |
||||||
|
add to a covered work, you may (if authorized by the copyright holders of |
||||||
|
that material) supplement the terms of this License with terms: |
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the |
||||||
|
terms of sections 15 and 16 of this License; or |
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or |
||||||
|
author attributions in that material or in the Appropriate Legal |
||||||
|
Notices displayed by works containing it; or |
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or |
||||||
|
requiring that modified versions of such material be marked in |
||||||
|
reasonable ways as different from the original version; or |
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or |
||||||
|
authors of the material; or |
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some |
||||||
|
trade names, trademarks, or service marks; or |
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that |
||||||
|
material by anyone who conveys the material (or modified versions of |
||||||
|
it) with contractual assumptions of liability to the recipient, for |
||||||
|
any liability that these contractual assumptions directly impose on |
||||||
|
those licensors and authors. |
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further |
||||||
|
restrictions" within the meaning of section 10. If the Program as you |
||||||
|
received it, or any part of it, contains a notice stating that it is |
||||||
|
governed by this License along with a term that is a further |
||||||
|
restriction, you may remove that term. If a license document contains |
||||||
|
a further restriction but permits relicensing or conveying under this |
||||||
|
License, you may add to a covered work material governed by the terms |
||||||
|
of that license document, provided that the further restriction does |
||||||
|
not survive such relicensing or conveying. |
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you |
||||||
|
must place, in the relevant source files, a statement of the |
||||||
|
additional terms that apply to those files, or a notice indicating |
||||||
|
where to find the applicable terms. |
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the |
||||||
|
form of a separately written license, or stated as exceptions; |
||||||
|
the above requirements apply either way. |
||||||
|
|
||||||
|
8. Termination. |
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly |
||||||
|
provided under this License. Any attempt otherwise to propagate or |
||||||
|
modify it is void, and will automatically terminate your rights under |
||||||
|
this License (including any patent licenses granted under the third |
||||||
|
paragraph of section 11). |
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your |
||||||
|
license from a particular copyright holder is reinstated (a) |
||||||
|
provisionally, unless and until the copyright holder explicitly and |
||||||
|
finally terminates your license, and (b) permanently, if the copyright |
||||||
|
holder fails to notify you of the violation by some reasonable means |
||||||
|
prior to 60 days after the cessation. |
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is |
||||||
|
reinstated permanently if the copyright holder notifies you of the |
||||||
|
violation by some reasonable means, this is the first time you have |
||||||
|
received notice of violation of this License (for any work) from that |
||||||
|
copyright holder, and you cure the violation prior to 30 days after |
||||||
|
your receipt of the notice. |
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the |
||||||
|
licenses of parties who have received copies or rights from you under |
||||||
|
this License. If your rights have been terminated and not permanently |
||||||
|
reinstated, you do not qualify to receive new licenses for the same |
||||||
|
material under section 10. |
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies. |
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or |
||||||
|
run a copy of the Program. Ancillary propagation of a covered work |
||||||
|
occurring solely as a consequence of using peer-to-peer transmission |
||||||
|
to receive a copy likewise does not require acceptance. However, |
||||||
|
nothing other than this License grants you permission to propagate or |
||||||
|
modify any covered work. These actions infringe copyright if you do |
||||||
|
not accept this License. Therefore, by modifying or propagating a |
||||||
|
covered work, you indicate your acceptance of this License to do so. |
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients. |
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically |
||||||
|
receives a license from the original licensors, to run, modify and |
||||||
|
propagate that work, subject to this License. You are not responsible |
||||||
|
for enforcing compliance by third parties with this License. |
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an |
||||||
|
organization, or substantially all assets of one, or subdividing an |
||||||
|
organization, or merging organizations. If propagation of a covered |
||||||
|
work results from an entity transaction, each party to that |
||||||
|
transaction who receives a copy of the work also receives whatever |
||||||
|
licenses to the work the party's predecessor in interest had or could |
||||||
|
give under the previous paragraph, plus a right to possession of the |
||||||
|
Corresponding Source of the work from the predecessor in interest, if |
||||||
|
the predecessor has it or can get it with reasonable efforts. |
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the |
||||||
|
rights granted or affirmed under this License. For example, you may |
||||||
|
not impose a license fee, royalty, or other charge for exercise of |
||||||
|
rights granted under this License, and you may not initiate litigation |
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that |
||||||
|
any patent claim is infringed by making, using, selling, offering for |
||||||
|
sale, or importing the Program or any portion of it. |
||||||
|
|
||||||
|
11. Patents. |
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this |
||||||
|
License of the Program or a work on which the Program is based. The |
||||||
|
work thus licensed is called the contributor's "contributor version". |
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims |
||||||
|
owned or controlled by the contributor, whether already acquired or |
||||||
|
hereafter acquired, that would be infringed by some manner, permitted |
||||||
|
by this License, of making, using, or selling its contributor version, |
||||||
|
but do not include claims that would be infringed only as a |
||||||
|
consequence of further modification of the contributor version. For |
||||||
|
purposes of this definition, "control" includes the right to grant |
||||||
|
patent sublicenses in a manner consistent with the requirements of |
||||||
|
this License. |
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free |
||||||
|
patent license under the contributor's essential patent claims, to |
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and |
||||||
|
propagate the contents of its contributor version. |
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express |
||||||
|
agreement or commitment, however denominated, not to enforce a patent |
||||||
|
(such as an express permission to practice a patent or covenant not to |
||||||
|
sue for patent infringement). To "grant" such a patent license to a |
||||||
|
party means to make such an agreement or commitment not to enforce a |
||||||
|
patent against the party. |
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license, |
||||||
|
and the Corresponding Source of the work is not available for anyone |
||||||
|
to copy, free of charge and under the terms of this License, through a |
||||||
|
publicly available network server or other readily accessible means, |
||||||
|
then you must either (1) cause the Corresponding Source to be so |
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the |
||||||
|
patent license for this particular work, or (3) arrange, in a manner |
||||||
|
consistent with the requirements of this License, to extend the patent |
||||||
|
license to downstream recipients. "Knowingly relying" means you have |
||||||
|
actual knowledge that, but for the patent license, your conveying the |
||||||
|
covered work in a country, or your recipient's use of the covered work |
||||||
|
in a country, would infringe one or more identifiable patents in that |
||||||
|
country that you have reason to believe are valid. |
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or |
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a |
||||||
|
covered work, and grant a patent license to some of the parties |
||||||
|
receiving the covered work authorizing them to use, propagate, modify |
||||||
|
or convey a specific copy of the covered work, then the patent license |
||||||
|
you grant is automatically extended to all recipients of the covered |
||||||
|
work and works based on it. |
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within |
||||||
|
the scope of its coverage, prohibits the exercise of, or is |
||||||
|
conditioned on the non-exercise of one or more of the rights that are |
||||||
|
specifically granted under this License. You may not convey a covered |
||||||
|
work if you are a party to an arrangement with a third party that is |
||||||
|
in the business of distributing software, under which you make payment |
||||||
|
to the third party based on the extent of your activity of conveying |
||||||
|
the work, and under which the third party grants, to any of the |
||||||
|
parties who would receive the covered work from you, a discriminatory |
||||||
|
patent license (a) in connection with copies of the covered work |
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily |
||||||
|
for and in connection with specific products or compilations that |
||||||
|
contain the covered work, unless you entered into that arrangement, |
||||||
|
or that patent license was granted, prior to 28 March 2007. |
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting |
||||||
|
any implied license or other defenses to infringement that may |
||||||
|
otherwise be available to you under applicable patent law. |
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom. |
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or |
||||||
|
otherwise) that contradict the conditions of this License, they do not |
||||||
|
excuse you from the conditions of this License. If you cannot convey a |
||||||
|
covered work so as to satisfy simultaneously your obligations under this |
||||||
|
License and any other pertinent obligations, then as a consequence you may |
||||||
|
not convey it at all. For example, if you agree to terms that obligate you |
||||||
|
to collect a royalty for further conveying from those to whom you convey |
||||||
|
the Program, the only way you could satisfy both those terms and this |
||||||
|
License would be to refrain entirely from conveying the Program. |
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License. |
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have |
||||||
|
permission to link or combine any covered work with a work licensed |
||||||
|
under version 3 of the GNU Affero General Public License into a single |
||||||
|
combined work, and to convey the resulting work. The terms of this |
||||||
|
License will continue to apply to the part which is the covered work, |
||||||
|
but the special requirements of the GNU Affero General Public License, |
||||||
|
section 13, concerning interaction through a network will apply to the |
||||||
|
combination as such. |
||||||
|
|
||||||
|
14. Revised Versions of this License. |
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of |
||||||
|
the GNU General Public License from time to time. Such new versions will |
||||||
|
be similar in spirit to the present version, but may differ in detail to |
||||||
|
address new problems or concerns. |
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the |
||||||
|
Program specifies that a certain numbered version of the GNU General |
||||||
|
Public License "or any later version" applies to it, you have the |
||||||
|
option of following the terms and conditions either of that numbered |
||||||
|
version or of any later version published by the Free Software |
||||||
|
Foundation. If the Program does not specify a version number of the |
||||||
|
GNU General Public License, you may choose any version ever published |
||||||
|
by the Free Software Foundation. |
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future |
||||||
|
versions of the GNU General Public License can be used, that proxy's |
||||||
|
public statement of acceptance of a version permanently authorizes you |
||||||
|
to choose that version for the Program. |
||||||
|
|
||||||
|
Later license versions may give you additional or different |
||||||
|
permissions. However, no additional obligations are imposed on any |
||||||
|
author or copyright holder as a result of your choosing to follow a |
||||||
|
later version. |
||||||
|
|
||||||
|
15. Disclaimer of Warranty. |
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||||
|
|
||||||
|
16. Limitation of Liability. |
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
||||||
|
SUCH DAMAGES. |
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16. |
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided |
||||||
|
above cannot be given local legal effect according to their terms, |
||||||
|
reviewing courts shall apply local law that most closely approximates |
||||||
|
an absolute waiver of all civil liability in connection with the |
||||||
|
Program, unless a warranty or assumption of liability accompanies a |
||||||
|
copy of the Program in return for a fee. |
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS |
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs |
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest |
||||||
|
possible use to the public, the best way to achieve this is to make it |
||||||
|
free software which everyone can redistribute and change under these terms. |
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest |
||||||
|
to attach them to the start of each source file to most effectively |
||||||
|
state the exclusion of warranty; and each file should have at least |
||||||
|
the "copyright" line and a pointer to where the full notice is found. |
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.> |
||||||
|
Copyright (C) <year> <name of author> |
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify |
||||||
|
it under the terms of the GNU General Public License as published by |
||||||
|
the Free Software Foundation, either version 3 of the License, or |
||||||
|
(at your option) any later version. |
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, |
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
GNU General Public License for more details. |
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License |
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. |
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail. |
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short |
||||||
|
notice like this when it starts in an interactive mode: |
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author> |
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
||||||
|
This is free software, and you are welcome to redistribute it |
||||||
|
under certain conditions; type `show c' for details. |
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate |
||||||
|
parts of the General Public License. Of course, your program's commands |
||||||
|
might be different; for a GUI interface, you would use an "about box". |
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school, |
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary. |
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see |
||||||
|
<https://www.gnu.org/licenses/>. |
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program |
||||||
|
into proprietary programs. If your program is a subroutine library, you |
||||||
|
may consider it more useful to permit linking proprietary applications with |
||||||
|
the library. If this is what you want to do, use the GNU Lesser General |
||||||
|
Public License instead of this License. But first, please read |
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>. |
@ -0,0 +1,130 @@ |
|||||||
|
[![icon_android](https://github.com/gedoor/gedoor.github.io/blob/master/images/icon_android.png)](https://play.google.com/store/apps/details?id=io.legado.play.release) |
||||||
|
<a href="https://data.newrank.cn/m/s.html?s=NykyOzI9MS5LNQ%3D%3D" target="_blank"> |
||||||
|
<img src="https://img.shields.io/badge/-微信关注“开源阅读”公众号-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
<div align="center"> |
||||||
|
<img width="125" height="125" src="https://github.com/gedoor/legado/raw/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png" alt="legado"/> |
||||||
|
|
||||||
|
Legado / 开源阅读 |
||||||
|
<br> |
||||||
|
<a href="https://gedoor.github.io" target="_blank">gedoor.github.io</a> / <a href="https://www.legado.top/" target="_blank">legado.top</a> |
||||||
|
<br> |
||||||
|
Legado is a free and open source novel reader for Android. |
||||||
|
</div> |
||||||
|
|
||||||
|
[![](https://img.shields.io/badge/-Contents:-696969.svg)](#contents) [![](https://img.shields.io/badge/-Function-F5F5F5.svg)](#Function-主要功能-) [![](https://img.shields.io/badge/-Download-F5F5F5.svg)](#Download-下载-) [![](https://img.shields.io/badge/-Community-F5F5F5.svg)](#Community-交流社区-) [![](https://img.shields.io/badge/-API-F5F5F5.svg)](#API-) [![](https://img.shields.io/badge/-Other-F5F5F5.svg)](#Other-其他-) [![](https://img.shields.io/badge/-Grateful-F5F5F5.svg)](#Grateful-感谢-) [![](https://img.shields.io/badge/-Interface-F5F5F5.svg)](#Interface-界面-) |
||||||
|
|
||||||
|
>新用户? |
||||||
|
> |
||||||
|
>软件不提供内容,需要您自己手动添加,例如导入书源等。 |
||||||
|
>看看 [官方帮助文档](https://www.yuque.com/legado/wiki),也许里面就有你要的答案。 |
||||||
|
|
||||||
|
# Function-主要功能 [![](https://img.shields.io/badge/-Function-F5F5F5.svg)](#Function-主要功能-) |
||||||
|
<details><summary>English</summary> |
||||||
|
1. Online reading from a variety of sources.<br> |
||||||
|
2. Local reading of downloaded content.<br> |
||||||
|
3. A configurable reader with multiple viewers, reading directions and other settings. <br> |
||||||
|
4. Categories to organize your library.<br> |
||||||
|
5. Light and dark themes.<br> |
||||||
|
6. Schedule updating your library for new chapters.<br> |
||||||
|
7. read offline or to your desired cloud service |
||||||
|
</details> |
||||||
|
|
||||||
|
<details><summary>中文</summary> |
||||||
|
1.自定义书源,自己设置规则,抓取网页数据,规则简单易懂,软件内有规则说明。<br> |
||||||
|
2.列表书架,网格书架自由切换。<br> |
||||||
|
3.书源规则支持搜索及发现,所有找书看书功能全部自定义,找书更方便。<br> |
||||||
|
4.订阅内容,可以订阅想看的任何内容,看你想看<br> |
||||||
|
5.支持替换净化,去除广告替换内容很方便。<br> |
||||||
|
6.支持本地TXT、EPUB阅读,手动浏览,智能扫描。<br> |
||||||
|
7.支持高度自定义阅读界面,切换字体、颜色、背景、行距、段距、加粗、简繁转换等。<br> |
||||||
|
8.支持多种翻页模式,覆盖、仿真、滑动、滚动等。<br> |
||||||
|
9.软件开源,持续优化,无广告。 |
||||||
|
</details> |
||||||
|
|
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# Download-下载 [![](https://img.shields.io/badge/-Download-F5F5F5.svg)](#Download-下载-) |
||||||
|
#### Android-安卓 |
||||||
|
* [Releases](https://github.com/gedoor/legado/releases/latest) |
||||||
|
* [Google play - $1.99](https://play.google.com/store/apps/details?id=io.legado.play.release) |
||||||
|
* [Coolapk](https://www.coolapk.com/apk/io.legado.app.release) |
||||||
|
* [Jsdelivr](https://cdn.jsdelivr.net/gh/gedoor/legado@release/) |
||||||
|
* [\#Beta](https://kunfei.lanzoui.com/b0f810h4b) |
||||||
|
|
||||||
|
|
||||||
|
#### IOS-苹果 |
||||||
|
* 准备中(No release) - [Github](https://github.com/gedoor/YueDuFlutter) |
||||||
|
|
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# Community-交流社区 [![](https://img.shields.io/badge/-Community-F5F5F5.svg)](#Community-交流社区-) |
||||||
|
|
||||||
|
#### Telegram |
||||||
|
[![Telegram-group](https://img.shields.io/badge/Telegram-%E7%BE%A4%E7%BB%84-blue)](https://t.me/yueduguanfang) [![Telegram-channel](https://img.shields.io/badge/Telegram-%E9%A2%91%E9%81%93-blue)](https://t.me/legado_channels) |
||||||
|
|
||||||
|
#### Discord |
||||||
|
[![Discord](https://img.shields.io/discord/560731361414086666?color=%235865f2&label=Discord)](https://discord.gg/VtUfRyzRXn) |
||||||
|
|
||||||
|
#### Other |
||||||
|
https://www.yuque.com/legado/wiki/community |
||||||
|
|
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# API [![](https://img.shields.io/badge/-API-F5F5F5.svg)](#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小说目录规则,在线朗读引擎,主题,阅读排版 |
||||||
|
|
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# Other-其他 [![](https://img.shields.io/badge/-Other-F5F5F5.svg)](#Other-其他-) |
||||||
|
##### 免责声明 |
||||||
|
https://gedoor.github.io/about.html |
||||||
|
##### 阅读3.0 |
||||||
|
* [书源规则](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="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# Grateful-感谢 [![](https://img.shields.io/badge/-Grateful-F5F5F5.svg)](#Grateful-感谢-) |
||||||
|
> * org.jsoup:jsoup |
||||||
|
> * cn.wanghaomiao:JsoupXpath |
||||||
|
> * com.jayway.jsonpath:json-path |
||||||
|
> * com.github.gedoor:rhino-android |
||||||
|
> * com.squareup.okhttp3:okhttp |
||||||
|
> * 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 |
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
||||||
|
|
||||||
|
# Interface-界面 [![](https://img.shields.io/badge/-Interface-F5F5F5.svg)](#Interface-界面-) |
||||||
|
<img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B1.jpg" width="270"><img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B2.jpg" width="270"><img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B3.jpg" width="270"> |
||||||
|
<img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B4.jpg" width="270"><img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B5.jpg" width="270"><img src="https://github.com/gedoor/gedoor.github.io/blob/master/images/%E9%98%85%E8%AF%BB%E7%AE%80%E4%BB%8B6.jpg" width="270"> |
||||||
|
|
||||||
|
<a href="#readme"> |
||||||
|
<img src="https://img.shields.io/badge/-返回顶部-orange.svg" alt="#" align="right"> |
||||||
|
</a> |
@ -0,0 +1,194 @@ |
|||||||
|
# 阅读API |
||||||
|
## 对于Web的配置 |
||||||
|
您需要先在设置中启用"Web 服务"。 |
||||||
|
## 使用 |
||||||
|
### Web |
||||||
|
以下说明假设您的操作在本机进行,且开放端口为1234。 |
||||||
|
如果您要从远程计算机访问[阅读](),请将`127.0.0.1`替换成手机IP。 |
||||||
|
#### 插入单个书源 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/saveSource |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求BODY内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt) |
||||||
|
|
||||||
|
#### 插入多个书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/saveBookSources |
||||||
|
URL = http://127.0.0.1:1234/saveRssSources |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求BODY内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 |
||||||
|
|
||||||
|
#### 获取书源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getBookSource?url=xxx |
||||||
|
URL = http://127.0.0.1:1234/getRssSource?url=xxx |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
#### 获取所有书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getBookSources |
||||||
|
URL = http://127.0.0.1:1234/getRssSources |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
#### 删除多个书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/deleteBookSources |
||||||
|
URL = http://127.0.0.1:1234/deleteRssSources |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求BODY内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 |
||||||
|
|
||||||
|
#### 插入书籍 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/saveBook |
||||||
|
Method = POST |
||||||
|
``` |
||||||
|
|
||||||
|
请求BODY内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。 |
||||||
|
|
||||||
|
#### 获取所有书籍 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getBookshelf |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书籍。 |
||||||
|
|
||||||
|
#### 获取书籍章节列表 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getChapterList?url=xxx |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定图书的章节列表。 |
||||||
|
|
||||||
|
#### 获取书籍内容 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/getBookContent?url=xxx&index=1 |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
获取指定图书的第`index`章节的文本内容。 |
||||||
|
|
||||||
|
#### 获取封面 |
||||||
|
``` |
||||||
|
URL = http://127.0.0.1:1234/cover?path=xxxxx |
||||||
|
Method = GET |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Content Provider |
||||||
|
* 需声明`io.legado.READ_WRITE`权限 |
||||||
|
* `providerHost`为`包名.readerProvider`, 如`io.legado.app.release.readerProvider`,不同包的地址不同,防止冲突安装失败 |
||||||
|
* 以下出现的`providerHost`请自行替换 |
||||||
|
|
||||||
|
#### 插入单个书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/bookSource/insert |
||||||
|
URL = content://providerHost/rssSource/insert |
||||||
|
Method = insert |
||||||
|
``` |
||||||
|
|
||||||
|
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt) |
||||||
|
|
||||||
|
#### 插入多个书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/bookSources/insert |
||||||
|
URL = content://providerHost/rssSources/insert |
||||||
|
Method = insert |
||||||
|
``` |
||||||
|
|
||||||
|
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 |
||||||
|
|
||||||
|
#### 获取书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/bookSource/query?url=xxx |
||||||
|
URL = content://providerHost/rssSource/query?url=xxx |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定URL对应的书源信息。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取所有书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/bookSources/query |
||||||
|
URL = content://providerHost/rssSources/query |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书源。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 删除多个书源or订阅源 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/bookSources/delete |
||||||
|
URL = content://providerHost/rssSources/delete |
||||||
|
Method = delete |
||||||
|
``` |
||||||
|
|
||||||
|
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/BookSource.kt),**为数组格式**。 |
||||||
|
|
||||||
|
#### 插入书籍 |
||||||
|
``` |
||||||
|
URL = content://providerHost/book/insert |
||||||
|
Method = insert |
||||||
|
``` |
||||||
|
|
||||||
|
创建`Key="json"`的`ContentValues`,内容为`JSON`字符串, |
||||||
|
格式参考[这个文件](https://github.com/gedoor/legado/blob/master/app/src/main/java/io/legado/app/data/entities/Book.kt)。 |
||||||
|
|
||||||
|
#### 获取所有书籍 |
||||||
|
``` |
||||||
|
URL = content://providerHost/books/query |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取APP内的所有书籍。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取书籍章节列表 |
||||||
|
``` |
||||||
|
URL = content://providerHost/book/chapter/query?url=xxx |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
|
||||||
|
获取指定图书的章节列表。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取书籍内容 |
||||||
|
|
||||||
|
``` |
||||||
|
URL = content://providerHost/book/content/query?url=xxx&index=1 |
||||||
|
Method = query |
||||||
|
``` |
||||||
|
获取指定图书的第`index`章节的文本内容。 |
||||||
|
用`Cursor.getString(0)`取出返回结果。 |
||||||
|
|
||||||
|
#### 获取封面 |
||||||
|
``` |
||||||
|
URL = content://providerHost/book/cover/query?path=xxxx |
||||||
|
Method = query |
||||||
|
``` |
@ -0,0 +1,2 @@ |
|||||||
|
/build |
||||||
|
/so |
@ -0,0 +1,227 @@ |
|||||||
|
apply plugin: 'com.android.application' |
||||||
|
apply plugin: 'kotlin-android' |
||||||
|
apply plugin: 'kotlin-parcelize' |
||||||
|
apply plugin: 'kotlin-kapt' |
||||||
|
apply plugin: 'de.timfreiheit.resourceplaceholders' |
||||||
|
apply from: 'download.gradle' |
||||||
|
|
||||||
|
static def releaseTime() { |
||||||
|
return new Date().format("yy.MMddHH", TimeZone.getTimeZone("GMT+8")) |
||||||
|
} |
||||||
|
|
||||||
|
def name = "legado" |
||||||
|
def version = "3." + releaseTime() |
||||||
|
def gitCommits = Integer.parseInt('git rev-list --count HEAD'.execute([], project.rootDir).text.trim()) |
||||||
|
|
||||||
|
android { |
||||||
|
compileSdkVersion 32 |
||||||
|
buildToolsVersion '32.0.0' |
||||||
|
kotlinOptions { |
||||||
|
jvmTarget = "11" |
||||||
|
} |
||||||
|
signingConfigs { |
||||||
|
if (project.hasProperty("RELEASE_STORE_FILE")) { |
||||||
|
myConfig { |
||||||
|
storeFile file(RELEASE_STORE_FILE) |
||||||
|
storePassword RELEASE_STORE_PASSWORD |
||||||
|
keyAlias RELEASE_KEY_ALIAS |
||||||
|
keyPassword RELEASE_KEY_PASSWORD |
||||||
|
v1SigningEnabled true |
||||||
|
v2SigningEnabled true |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
defaultConfig { |
||||||
|
applicationId "io.legado.app" |
||||||
|
minSdkVersion 21 |
||||||
|
targetSdkVersion 32 |
||||||
|
versionCode gitCommits |
||||||
|
versionName version |
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" |
||||||
|
project.ext.set("archivesBaseName", name + "_" + version) |
||||||
|
multiDexEnabled true |
||||||
|
|
||||||
|
javaCompileOptions { |
||||||
|
annotationProcessorOptions { |
||||||
|
arguments += [ |
||||||
|
"room.incremental" : "true", |
||||||
|
"room.expandProjection": "true", |
||||||
|
"room.schemaLocation" : "$projectDir/schemas".toString() |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
buildFeatures { |
||||||
|
viewBinding true |
||||||
|
} |
||||||
|
buildTypes { |
||||||
|
release { |
||||||
|
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\"" |
||||||
|
if (project.hasProperty("RELEASE_STORE_FILE")) { |
||||||
|
signingConfig signingConfigs.myConfig |
||||||
|
} |
||||||
|
applicationIdSuffix '.release' |
||||||
|
|
||||||
|
minifyEnabled false |
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||||
|
} |
||||||
|
debug { |
||||||
|
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\"" |
||||||
|
if (project.hasProperty("RELEASE_STORE_FILE")) { |
||||||
|
signingConfig signingConfigs.myConfig |
||||||
|
} |
||||||
|
applicationIdSuffix '.debug' |
||||||
|
versionNameSuffix 'debug' |
||||||
|
minifyEnabled false |
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' |
||||||
|
} |
||||||
|
android.applicationVariants.all { variant -> |
||||||
|
variant.outputs.all { |
||||||
|
def flavor = variant.productFlavors[0].name |
||||||
|
outputFileName = "${name}_${flavor}_${defaultConfig.versionName}.apk" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
flavorDimensions "mode" |
||||||
|
productFlavors { |
||||||
|
app { |
||||||
|
dimension "mode" |
||||||
|
manifestPlaceholders = [APP_CHANNEL_VALUE: "app"] |
||||||
|
} |
||||||
|
google { |
||||||
|
dimension "mode" |
||||||
|
applicationId "io.legado.play" |
||||||
|
manifestPlaceholders = [APP_CHANNEL_VALUE: "google"] |
||||||
|
} |
||||||
|
} |
||||||
|
compileOptions { |
||||||
|
// Flag to enable support for the new language APIs |
||||||
|
coreLibraryDesugaringEnabled true |
||||||
|
// Sets Java compatibility to Java 11 |
||||||
|
sourceCompatibility JavaVersion.VERSION_11 |
||||||
|
targetCompatibility JavaVersion.VERSION_11 |
||||||
|
} |
||||||
|
|
||||||
|
sourceSets { |
||||||
|
// Adds exported schema location as test app assets. |
||||||
|
androidTest.assets.srcDirs += files("$projectDir/schemas".toString()) |
||||||
|
} |
||||||
|
tasks.withType(JavaCompile) { |
||||||
|
//options.compilerArgs << "-Xlint:unchecked" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
resourcePlaceholders { |
||||||
|
files = ['xml/shortcuts.xml'] |
||||||
|
} |
||||||
|
|
||||||
|
kapt { |
||||||
|
arguments { |
||||||
|
arg("room.schemaLocation", "$projectDir/schemas") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
dependencies { |
||||||
|
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") |
||||||
|
//Kotlin反射 |
||||||
|
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version") |
||||||
|
//协程 |
||||||
|
def coroutines_version = '1.6.0' |
||||||
|
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.7.0') |
||||||
|
implementation('androidx.appcompat:appcompat:1.4.0') |
||||||
|
implementation('androidx.activity:activity-ktx:1.4.0') |
||||||
|
implementation('androidx.fragment:fragment-ktx:1.4.0') |
||||||
|
implementation('androidx.preference:preference-ktx:1.1.1') |
||||||
|
implementation('androidx.constraintlayout:constraintlayout:2.1.2') |
||||||
|
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.9') |
||||||
|
implementation('androidx.webkit:webkit:1.4.0') |
||||||
|
|
||||||
|
implementation('com.jakewharton.timber:timber:5.0.1') |
||||||
|
|
||||||
|
//media |
||||||
|
implementation("androidx.media:media:1.4.3") |
||||||
|
def exoplayer_version = '2.16.1' |
||||||
|
implementation("com.google.android.exoplayer:exoplayer-core:$exoplayer_version") |
||||||
|
implementation("com.google.android.exoplayer:extension-okhttp:$exoplayer_version") |
||||||
|
|
||||||
|
//Splitties |
||||||
|
def splitties_version = '3.0.0' |
||||||
|
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.4.0' |
||||||
|
implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycle_version") |
||||||
|
|
||||||
|
//room |
||||||
|
def room_version = '2.4.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('io.github.jeremyliao:live-event-bus-x:1.8.0') |
||||||
|
|
||||||
|
//规则相关 |
||||||
|
implementation('org.jsoup:jsoup:1.14.3') |
||||||
|
implementation('com.jayway.jsonpath:json-path:2.6.0') |
||||||
|
implementation('cn.wanghaomiao:JsoupXpath:2.5.1') |
||||||
|
implementation(project(path: ':epublib')) |
||||||
|
|
||||||
|
//JS rhino |
||||||
|
implementation('com.github.gedoor:rhino-android:1.6') |
||||||
|
|
||||||
|
//网络 |
||||||
|
implementation('com.squareup.okhttp3:okhttp:4.9.3') |
||||||
|
implementation(fileTree(dir: 'cronetlib', include: ['*.jar', '*.aar'])) |
||||||
|
|
||||||
|
//Glide |
||||||
|
implementation('com.github.bumptech.glide:glide:4.12.0') |
||||||
|
kapt('com.github.bumptech.glide:compiler:4.12.0') |
||||||
|
|
||||||
|
//webServer |
||||||
|
def nanoHttpdVersion = "2.3.1" |
||||||
|
implementation("org.nanohttpd:nanohttpd:$nanoHttpdVersion") |
||||||
|
implementation("org.nanohttpd:nanohttpd-websocket:$nanoHttpdVersion") |
||||||
|
|
||||||
|
//二维码 |
||||||
|
implementation('com.github.jenly1314:zxing-lite:2.1.1') |
||||||
|
|
||||||
|
//颜色选择 |
||||||
|
implementation('com.jaredrummler:colorpicker:1.1.0') |
||||||
|
|
||||||
|
//apache |
||||||
|
implementation('org.apache.commons:commons-text:1.9') |
||||||
|
|
||||||
|
//MarkDown |
||||||
|
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.github.liuyueyi.quick-chinese-transfer:quick-transfer-core:0.2.3') |
||||||
|
|
||||||
|
//代码编辑com.github.AmrDeveloper:CodeView已集成到应用内 |
||||||
|
//epubLib集成到应用内 |
||||||
|
|
||||||
|
// LeakCanary |
||||||
|
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' |
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
import java.security.MessageDigest |
||||||
|
|
||||||
|
apply plugin: 'de.undercouch.download' |
||||||
|
|
||||||
|
def BASE_PATH = "https://storage.googleapis.com/chromium-cronet/android/" + CronetVersion + "/Release/cronet/" |
||||||
|
def assetsDir = projectDir.toString() + "/src/main/assets" |
||||||
|
def libPath = projectDir.toString() + "/cronetlib" |
||||||
|
def soPath = projectDir.toString() + "/so" |
||||||
|
|
||||||
|
/** |
||||||
|
* 从文件生成MD5 |
||||||
|
* @param file |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
static def generateMD5(final file) { |
||||||
|
MessageDigest digest = MessageDigest.getInstance("MD5") |
||||||
|
file.withInputStream() { is -> |
||||||
|
byte[] buffer = new byte[1024] |
||||||
|
int numRead = 0 |
||||||
|
while ((numRead = is.read(buffer)) > 0) { |
||||||
|
digest.update(buffer, 0, numRead) |
||||||
|
} |
||||||
|
} |
||||||
|
return String.format("%032x", new BigInteger(1, digest.digest())).toLowerCase() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 下载Cronet相关的jar |
||||||
|
*/ |
||||||
|
task downloadJar(type: Download) { |
||||||
|
src([ |
||||||
|
BASE_PATH + "cronet_api.jar", |
||||||
|
BASE_PATH + "cronet_impl_common_java.jar", |
||||||
|
BASE_PATH + "cronet_impl_native_java.jar", |
||||||
|
BASE_PATH + "cronet_impl_platform_java.jar", |
||||||
|
]) |
||||||
|
dest libPath |
||||||
|
overwrite true |
||||||
|
onlyIfModified true |
||||||
|
} |
||||||
|
/** |
||||||
|
* 下载Cronet的arm64-v8a so |
||||||
|
*/ |
||||||
|
task downloadARM64(type: Download) { |
||||||
|
src BASE_PATH + "libs/arm64-v8a/libcronet." + CronetVersion + ".so" |
||||||
|
dest soPath + "/arm64-v8a.so" |
||||||
|
overwrite true |
||||||
|
onlyIfModified true |
||||||
|
} |
||||||
|
/** |
||||||
|
* 下载Cronet的armeabi-v7a so |
||||||
|
*/ |
||||||
|
task downloadARMv7(type: Download) { |
||||||
|
src BASE_PATH + "libs/armeabi-v7a/libcronet." + CronetVersion + ".so" |
||||||
|
dest soPath + "/armeabi-v7a.so" |
||||||
|
overwrite true |
||||||
|
onlyIfModified true |
||||||
|
} |
||||||
|
/** |
||||||
|
* 下载Cronet的x86_64 so |
||||||
|
*/ |
||||||
|
task downloadX86_64(type: Download) { |
||||||
|
src BASE_PATH + "libs/x86_64/libcronet." + CronetVersion + ".so" |
||||||
|
dest soPath + "/x86_64.so" |
||||||
|
overwrite true |
||||||
|
onlyIfModified true |
||||||
|
} |
||||||
|
/** |
||||||
|
* 下载Cronet的x86 so |
||||||
|
*/ |
||||||
|
task downloadX86(type: Download) { |
||||||
|
src BASE_PATH + "libs/x86/libcronet." + CronetVersion + ".so" |
||||||
|
dest soPath + "/x86.so" |
||||||
|
overwrite true |
||||||
|
onlyIfModified true |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 更新Cronet版本时执行这个task |
||||||
|
* 先更改gradle.properties 里面的版本号,然后再执行 |
||||||
|
* gradlew app:downloadCronet |
||||||
|
*/ |
||||||
|
task downloadCronet() { |
||||||
|
dependsOn downloadJar, downloadARM64, downloadARMv7, downloadX86_64, downloadX86 |
||||||
|
|
||||||
|
doLast { |
||||||
|
StringBuilder sb = new StringBuilder("{") |
||||||
|
def files = new File(soPath).listFiles() |
||||||
|
for (File file : files) { |
||||||
|
println file.name.replace(".so", "") |
||||||
|
sb.append("\"").append(file.name.replace(".so", "")).append("\":\"").append(generateMD5(file)).append("\",") |
||||||
|
} |
||||||
|
sb.append("\"version\":\"").append(CronetVersion).append("\"}") |
||||||
|
|
||||||
|
println sb.toString() |
||||||
|
|
||||||
|
println assetsDir |
||||||
|
def f1 = new File(assetsDir + "/cronet.json") |
||||||
|
if (!f1.exists()) { |
||||||
|
f1.parentFile.mkdirs() |
||||||
|
f1.createNewFile() |
||||||
|
} |
||||||
|
f1.text = sb.toString() |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,151 @@ |
|||||||
|
{ |
||||||
|
"project_info": { |
||||||
|
"project_number": "453392274790", |
||||||
|
"firebase_url": "https://legado-fca69.firebaseio.com", |
||||||
|
"project_id": "legado-fca69", |
||||||
|
"storage_bucket": "legado-fca69.appspot.com" |
||||||
|
}, |
||||||
|
"client": [ |
||||||
|
{ |
||||||
|
"client_info": { |
||||||
|
"mobilesdk_app_id": "1:453392274790:android:c4eac14b1410eec5f624a7", |
||||||
|
"android_client_info": { |
||||||
|
"package_name": "io.legado.app.debug" |
||||||
|
} |
||||||
|
}, |
||||||
|
"oauth_client": [ |
||||||
|
{ |
||||||
|
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
||||||
|
"client_type": 3 |
||||||
|
} |
||||||
|
], |
||||||
|
"api_key": [ |
||||||
|
{ |
||||||
|
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
||||||
|
} |
||||||
|
], |
||||||
|
"services": { |
||||||
|
"appinvite_service": { |
||||||
|
"other_platform_oauth_client": [ |
||||||
|
{ |
||||||
|
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
||||||
|
"client_type": 3 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"client_info": { |
||||||
|
"mobilesdk_app_id": "1:453392274790:android:c1481c1c3d3f51eff624a7", |
||||||
|
"android_client_info": { |
||||||
|
"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 |
||||||
|
} |
||||||
|
], |
||||||
|
"api_key": [ |
||||||
|
{ |
||||||
|
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
||||||
|
} |
||||||
|
], |
||||||
|
"services": { |
||||||
|
"appinvite_service": { |
||||||
|
"other_platform_oauth_client": [ |
||||||
|
{ |
||||||
|
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
||||||
|
"client_type": 3 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"client_info": { |
||||||
|
"mobilesdk_app_id": "1:453392274790:android:b891abd2331577dff624a7", |
||||||
|
"android_client_info": { |
||||||
|
"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 |
||||||
|
} |
||||||
|
], |
||||||
|
"api_key": [ |
||||||
|
{ |
||||||
|
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
||||||
|
} |
||||||
|
], |
||||||
|
"services": { |
||||||
|
"appinvite_service": { |
||||||
|
"other_platform_oauth_client": [ |
||||||
|
{ |
||||||
|
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
||||||
|
"client_type": 3 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"client_info": { |
||||||
|
"mobilesdk_app_id": "1:453392274790:android:b891abd2331577dff624a7", |
||||||
|
"android_client_info": { |
||||||
|
"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 |
||||||
|
} |
||||||
|
], |
||||||
|
"api_key": [ |
||||||
|
{ |
||||||
|
"current_key": "AIzaSyD90mfNLhA7cAzzI9SonpSz5mrF5BnmyJA" |
||||||
|
} |
||||||
|
], |
||||||
|
"services": { |
||||||
|
"appinvite_service": { |
||||||
|
"other_platform_oauth_client": [ |
||||||
|
{ |
||||||
|
"client_id": "453392274790-hnbpatpce9hbjiggj76hgo7queu86atq.apps.googleusercontent.com", |
||||||
|
"client_type": 3 |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
], |
||||||
|
"configuration_version": "1" |
||||||
|
} |
@ -0,0 +1,231 @@ |
|||||||
|
# Add project specific ProGuard rules here. |
||||||
|
# You can control the set of applied configuration files using the |
||||||
|
# proguardFiles setting in build.gradle. |
||||||
|
# |
||||||
|
# For more details, see |
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html |
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following |
||||||
|
# and specify the fully qualified class name to the JavaScript interface |
||||||
|
# class: |
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { |
||||||
|
# public *; |
||||||
|
#} |
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for |
||||||
|
# debugging stack traces. |
||||||
|
#-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to |
||||||
|
# hide the original source file name. |
||||||
|
#-renamesourcefileattribute SourceFile |
||||||
|
# 混合时不使用大小写混合,混合后的类名为小写 |
||||||
|
-dontusemixedcaseclassnames |
||||||
|
|
||||||
|
# 指定不去忽略非公共库的类 |
||||||
|
-dontskipnonpubliclibraryclasses |
||||||
|
|
||||||
|
# 这句话能够使我们的项目混淆后产生映射文件 |
||||||
|
# 包含有类名->混淆后类名的映射关系 |
||||||
|
-verbose |
||||||
|
|
||||||
|
# 指定不去忽略非公共库的类成员 |
||||||
|
-dontskipnonpubliclibraryclassmembers |
||||||
|
|
||||||
|
# 不做预校验,preverify是proguard的四个步骤之一,Android不需要preverify,去掉这一步能够加快混淆速度。 |
||||||
|
-dontpreverify |
||||||
|
|
||||||
|
# 保留Annotation不混淆 |
||||||
|
-keepattributes *Annotation*,InnerClasses |
||||||
|
|
||||||
|
# 避免混淆泛型 |
||||||
|
-keepattributes Signature |
||||||
|
|
||||||
|
# 抛出异常时保留代码行号 |
||||||
|
-keepattributes SourceFile,LineNumberTable |
||||||
|
|
||||||
|
# 指定混淆是采用的算法,后面的参数是一个过滤器 |
||||||
|
# 这个过滤器是谷歌推荐的算法,一般不做更改 |
||||||
|
-optimizations !code/simplification/cast,!field/*,!class/merging/* |
||||||
|
|
||||||
|
|
||||||
|
############################################# |
||||||
|
# |
||||||
|
# Android开发中一些需要保留的公共部分 |
||||||
|
# |
||||||
|
############################################# |
||||||
|
# 屏蔽错误Unresolved class name |
||||||
|
#noinspection ShrinkerUnresolvedReference |
||||||
|
|
||||||
|
# 保留我们使用的四大组件,自定义的Application等等这些类不被混淆 |
||||||
|
# 因为这些子类都有可能被外部调用 |
||||||
|
-keep public class * extends android.app.Activity |
||||||
|
-keep public class * extends android.app.Application |
||||||
|
-keep public class * extends android.app.Service |
||||||
|
-keep public class * extends android.content.BroadcastReceiver |
||||||
|
-keep public class * extends android.content.ContentProvider |
||||||
|
-keep public class * extends android.app.backup.BackupAgentHelper |
||||||
|
-keep public class * extends android.preference.Preference |
||||||
|
-keep public class * extends android.view.View |
||||||
|
|
||||||
|
# 保留androidx下的所有类及其内部类 |
||||||
|
-keep class androidx.** {*;} |
||||||
|
|
||||||
|
# 保留继承的 |
||||||
|
-keep public class * extends androidx.** |
||||||
|
|
||||||
|
# 保留R下面的资源 |
||||||
|
-keep class **.R$* {*;} |
||||||
|
|
||||||
|
# 保留本地native方法不被混淆 |
||||||
|
-keepclasseswithmembernames class * { |
||||||
|
native <methods>; |
||||||
|
} |
||||||
|
|
||||||
|
# 保留在Activity中的方法参数是view的方法, |
||||||
|
# 这样以来我们在layout中写的onClick就不会被影响 |
||||||
|
-keepclassmembers class * extends android.app.Activity{ |
||||||
|
public void *(android.view.View); |
||||||
|
} |
||||||
|
|
||||||
|
# 保留枚举类不被混淆 |
||||||
|
-keepclassmembers enum * { |
||||||
|
public static **[] values(); |
||||||
|
public static ** valueOf(java.lang.String); |
||||||
|
} |
||||||
|
|
||||||
|
# 保留我们自定义控件(继承自View)不被混淆 |
||||||
|
-keep public class * extends android.view.View{ |
||||||
|
*** get*(); |
||||||
|
void set*(***); |
||||||
|
public <init>(android.content.Context); |
||||||
|
public <init>(android.content.Context, android.util.AttributeSet); |
||||||
|
public <init>(android.content.Context, android.util.AttributeSet, int); |
||||||
|
} |
||||||
|
|
||||||
|
# 保留Parcelable序列化类不被混淆 |
||||||
|
-keep class * implements android.os.Parcelable { |
||||||
|
public static final android.os.Parcelable$Creator *; |
||||||
|
} |
||||||
|
|
||||||
|
# 保留Serializable序列化的类不被混淆 |
||||||
|
-keepclassmembers class * implements java.io.Serializable { |
||||||
|
static final long serialVersionUID; |
||||||
|
private static final java.io.ObjectStreamField[] serialPersistentFields; |
||||||
|
!static !transient <fields>; |
||||||
|
!private <fields>; |
||||||
|
!private <methods>; |
||||||
|
private void writeObject(java.io.ObjectOutputStream); |
||||||
|
private void readObject(java.io.ObjectInputStream); |
||||||
|
java.lang.Object writeReplace(); |
||||||
|
java.lang.Object readResolve(); |
||||||
|
} |
||||||
|
|
||||||
|
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆 |
||||||
|
-keepclassmembers class * { |
||||||
|
void *(**On*Event); |
||||||
|
void *(**On*Listener); |
||||||
|
} |
||||||
|
|
||||||
|
# webView处理,项目中没有使用到webView忽略即可 |
||||||
|
-keepclassmembers class * extends android.webkit.WebViewClient { |
||||||
|
public void *(android.webkit.WebView, java.lang.String); |
||||||
|
public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); |
||||||
|
public boolean *(android.webkit.WebView, java.lang.String); |
||||||
|
} |
||||||
|
|
||||||
|
# 移除Log类打印各个等级日志的代码,打正式包的时候可以做为禁log使用,这里可以作为禁止log打印的功能使用 |
||||||
|
# 记得proguard-android.txt中一定不要加-dontoptimize才起作用 |
||||||
|
# 另外的一种实现方案是通过BuildConfig.DEBUG的变量来控制 |
||||||
|
-assumenosideeffects class android.util.Log { |
||||||
|
public static int v(...); |
||||||
|
public static int i(...); |
||||||
|
public static int w(...); |
||||||
|
public static int d(...); |
||||||
|
public static int e(...); |
||||||
|
} |
||||||
|
|
||||||
|
# 保持js引擎调用的java类 |
||||||
|
-keep class **.analyzeRule.**{*;} |
||||||
|
# 保持web类 |
||||||
|
-keep class **.web.**{*;} |
||||||
|
#数据类 |
||||||
|
-keep class **.data.**{*;} |
||||||
|
|
||||||
|
-dontwarn rx.** |
||||||
|
-dontwarn okio.** |
||||||
|
-dontwarn javax.annotation.** |
||||||
|
-dontwarn org.apache.log4j.lf5.viewer.** |
||||||
|
-dontnote org.apache.log4j.lf5.viewer.** |
||||||
|
-dontwarn freemarker.** |
||||||
|
-dontnote org.python.core.** |
||||||
|
-dontwarn com.hwangjr.rxbus.** |
||||||
|
-dontwarn okhttp3.** |
||||||
|
-dontwarn org.conscrypt.** |
||||||
|
-dontwarn com.jeremyliao.liveeventbus.** |
||||||
|
|
||||||
|
-keep class com.google.gson.** { *; } |
||||||
|
-keep class com.ke.gson.** { *; } |
||||||
|
-keep class com.jeremyliao.liveeventbus.** { *; } |
||||||
|
-keep class okhttp3.**{*;} |
||||||
|
-keep class okio.**{*;} |
||||||
|
-keep class com.hwangjr.rxbus.**{*;} |
||||||
|
-keep class org.conscrypt.**{*;} |
||||||
|
-keep class android.support.**{*;} |
||||||
|
-keep class me.grantland.widget.**{*;} |
||||||
|
-keep class de.hdodenhof.circleimageview.**{*;} |
||||||
|
-keep class tyrant.explosionfield.**{*;} |
||||||
|
-keep class tyrantgit.explosionfield.**{*;} |
||||||
|
-keep class freemarker.**{*;} |
||||||
|
-keep class com.gyf.barlibrary.** {*;} |
||||||
|
##JSOUP |
||||||
|
-keep class org.jsoup.**{*;} |
||||||
|
-keep class **.xpath.**{*;} |
||||||
|
|
||||||
|
-keep class org.slf4j.**{*;} |
||||||
|
-dontwarn org.slf4j.** |
||||||
|
|
||||||
|
-keep class org.codehaus.**{*;} |
||||||
|
-dontwarn org.codehaus.** |
||||||
|
-keep class com.jayway.**{*;} |
||||||
|
-dontwarn com.jayway.** |
||||||
|
-keep class com.fasterxml.**{*;} |
||||||
|
|
||||||
|
-keep class javax.swing.**{*;} |
||||||
|
-dontwarn javax.swing.** |
||||||
|
-keep class java.awt.**{*;} |
||||||
|
-dontwarn java.awt.** |
||||||
|
-keep class sun.misc.**{*;} |
||||||
|
-dontwarn sun.misc.** |
||||||
|
-keep class sun.reflect.**{*;} |
||||||
|
-dontwarn sun.reflect.** |
||||||
|
|
||||||
|
## Rhino |
||||||
|
-keep class javax.script.** { *; } |
||||||
|
-keep class com.sun.script.javascript.** { *; } |
||||||
|
-keep class org.mozilla.javascript.** { *; } |
||||||
|
|
||||||
|
###EPUB |
||||||
|
-dontwarn nl.siegmann.epublib.** |
||||||
|
-dontwarn org.xmlpull.** |
||||||
|
-keep class nl.siegmann.epublib.**{*;} |
||||||
|
-keep class javax.xml.**{*;} |
||||||
|
-keep class org.xmlpull.**{*;} |
||||||
|
|
||||||
|
-keep class org.simpleframework.**{*;} |
||||||
|
-dontwarn org.simpleframework.xml.** |
||||||
|
|
||||||
|
-keepclassmembers class * { |
||||||
|
public <init> (org.json.JSONObject); |
||||||
|
} |
||||||
|
-keepclassmembers enum * { |
||||||
|
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 *; |
||||||
|
*; |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package io.legado.app |
||||||
|
|
||||||
|
import android.net.Uri |
||||||
|
import android.util.Log |
||||||
|
import androidx.test.InstrumentationRegistry |
||||||
|
import androidx.test.runner.AndroidJUnit4 |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
|
||||||
|
/** |
||||||
|
* Instrumented test, which will execute on an Android device. |
||||||
|
* |
||||||
|
* See [testing documentation](http://d.android.com/tools/testing). |
||||||
|
*/ |
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class ExampleInstrumentedTest { |
||||||
|
@Test |
||||||
|
fun testContentProvider() { |
||||||
|
// Context of the app under test. |
||||||
|
val appContext = InstrumentationRegistry.getTargetContext() |
||||||
|
Log.d("test", |
||||||
|
appContext.contentResolver.query(Uri.parse("content://io.legado.app.api.ReaderProvider/sources/query"),null,null,null,null) |
||||||
|
!!.getString(0) |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
package io.legado.app |
||||||
|
|
||||||
|
import androidx.room.Room |
||||||
|
import androidx.room.migration.Migration |
||||||
|
import androidx.room.testing.MigrationTestHelper |
||||||
|
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory |
||||||
|
import androidx.test.platform.app.InstrumentationRegistry |
||||||
|
import androidx.test.runner.AndroidJUnit4 |
||||||
|
import io.legado.app.data.AppDatabase |
||||||
|
import org.junit.Rule |
||||||
|
import org.junit.Test |
||||||
|
import org.junit.runner.RunWith |
||||||
|
import java.io.IOException |
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class) |
||||||
|
class MigrationTest { |
||||||
|
private val TEST_DB = "migration-test" |
||||||
|
|
||||||
|
private val ALL_MIGRATIONS = arrayOf<Migration>( |
||||||
|
|
||||||
|
) |
||||||
|
|
||||||
|
@Rule |
||||||
|
val helper: MigrationTestHelper = MigrationTestHelper( |
||||||
|
InstrumentationRegistry.getInstrumentation(), |
||||||
|
AppDatabase::class.java.canonicalName, |
||||||
|
FrameworkSQLiteOpenHelperFactory() |
||||||
|
) |
||||||
|
|
||||||
|
@Test |
||||||
|
@Throws(IOException::class) |
||||||
|
fun migrateAll() { |
||||||
|
// Create earliest version of the database. |
||||||
|
helper.createDatabase(TEST_DB, 30).apply { |
||||||
|
close() |
||||||
|
} |
||||||
|
|
||||||
|
// Open latest version of the database. Room will validate the schema |
||||||
|
// once all migrations execute. |
||||||
|
Room.databaseBuilder( |
||||||
|
InstrumentationRegistry.getInstrumentation().targetContext, |
||||||
|
AppDatabase::class.java, |
||||||
|
TEST_DB |
||||||
|
).addMigrations(*ALL_MIGRATIONS) |
||||||
|
.build().apply { |
||||||
|
openHelper.writableDatabase |
||||||
|
close() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,4 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">阅读·D</string> |
||||||
|
<string name="receiving_shared_label">阅读·D·搜索</string> |
||||||
|
</resources> |
@ -0,0 +1,4 @@ |
|||||||
|
<resources> |
||||||
|
<string name="app_name">legado·D</string> |
||||||
|
<string name="receiving_shared_label">legado·D·search</string> |
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">阅读Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">閱讀Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">閱讀Pro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,6 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<resources> |
||||||
|
|
||||||
|
<string name="app_name">legadoPro</string> |
||||||
|
|
||||||
|
</resources> |
@ -0,0 +1,465 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
package="io.legado.app"> |
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" /> |
||||||
|
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" /> |
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> |
||||||
|
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> |
||||||
|
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" /> |
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> |
||||||
|
<uses-permission android:name="android.permission.GET_ACCOUNTS" /> |
||||||
|
<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" |
||||||
|
android:allowBackup="true" |
||||||
|
android:icon="@mipmap/ic_launcher" |
||||||
|
android:label="@string/app_name" |
||||||
|
android:networkSecurityConfig="@xml/network_security_config" |
||||||
|
android:requestLegacyExternalStorage="true" |
||||||
|
android:supportsRtl="true" |
||||||
|
android:theme="@style/AppTheme.Light" |
||||||
|
tools:ignore="AllowBackup,GoogleAppIndexingWarning,UnusedAttribute"> |
||||||
|
<!-- 主入口 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.welcome.WelcomeActivity" |
||||||
|
android:exported="true"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.MAIN" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标1 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标2 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标3 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标4 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标5 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 图标6 --> |
||||||
|
<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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" /> |
||||||
|
</intent-filter> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="android.app.shortcuts" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:resource="@xml/shortcuts" /> |
||||||
|
</activity> |
||||||
|
<!-- 主界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.main.MainActivity" |
||||||
|
android:alwaysRetainTaskState="true" |
||||||
|
android:launchMode="singleTask" /> |
||||||
|
<!-- 阅读界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.read.ReadBookActivity" |
||||||
|
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout" |
||||||
|
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" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- 书籍信息编辑 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.info.edit.BookInfoEditActivity" |
||||||
|
android:launchMode="singleTask" /> |
||||||
|
<!-- 音频播放界面 --> |
||||||
|
<activity |
||||||
|
android:name="io.legado.app.ui.book.audio.AudioPlayActivity" |
||||||
|
android:launchMode="singleTask" /> |
||||||
|
<!-- 授权界面 --> |
||||||
|
<activity |
||||||
|
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" |
||||||
|
android:configChanges="locale|keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:windowSoftInputMode="adjustResize|stateHidden" /> |
||||||
|
<!-- 订阅源编辑 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.source.edit.RssSourceEditActivity" |
||||||
|
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" |
||||||
|
android:launchMode="singleTask" /> |
||||||
|
<!-- 搜索界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.search.SearchActivity" |
||||||
|
android:launchMode="standard" /> |
||||||
|
<!-- 关于界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.about.AboutActivity" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 捐赠界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.about.DonateActivity" |
||||||
|
android:launchMode="singleTask" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 书源管理 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.source.manage.BookSourceActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 订阅源管理 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.source.manage.RssSourceActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- txt目录规则管理 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.local.rule.TxtTocRuleActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 替换规则界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.replace.ReplaceRuleActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 书籍管理 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.arrange.ArrangeBookActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 书源调试 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.source.debug.BookSourceDebugActivity" |
||||||
|
android:launchMode="singleTop" |
||||||
|
android:screenOrientation="behind" /> |
||||||
|
<!-- 目录 --> |
||||||
|
<activity |
||||||
|
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条目 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.article.RssSortActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- RSS阅读 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.read.ReadRssActivity" |
||||||
|
android:configChanges="orientation|screenSize" |
||||||
|
android:hardwareAccelerated="true" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- 导入书籍 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.local.ImportBookActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- 发现界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.explore.ExploreShowActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- 订阅源调试 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.source.debug.RssSourceDebugActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- Rss收藏 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.rss.favorites.RssFavoritesActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- 缓存界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.book.cache.CacheActivity" |
||||||
|
android:launchMode="singleTop" /> |
||||||
|
<!-- WebView界面 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.browser.WebViewActivity" |
||||||
|
android:launchMode="standard" /> |
||||||
|
<!-- 书源登录 --> |
||||||
|
<activity |
||||||
|
android:name="io.legado.app.ui.login.SourceLoginActivity" |
||||||
|
android:configChanges="orientation|screenSize" |
||||||
|
android:hardwareAccelerated="true" |
||||||
|
android:theme="@style/AppTheme.Transparent" /> |
||||||
|
<!-- 阅读记录 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.about.ReadRecordActivity" |
||||||
|
android:configChanges="orientation|screenSize" |
||||||
|
android:hardwareAccelerated="true" /> |
||||||
|
<!-- 选择文件 --> |
||||||
|
<activity |
||||||
|
android:name=".ui.document.HandleFileActivity" |
||||||
|
android:configChanges="orientation|screenSize" |
||||||
|
android:hardwareAccelerated="true" |
||||||
|
android:theme="@style/AppTheme.Transparent" /> |
||||||
|
<!-- 文字处理 --> |
||||||
|
<activity |
||||||
|
android:name=".receiver.SharedReceiverActivity" |
||||||
|
android:exported="true" |
||||||
|
android:label="@string/receiving_shared_label" |
||||||
|
android:theme="@style/AppTheme.Transparent"> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.PROCESS_TEXT" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" /> |
||||||
|
|
||||||
|
<data android:mimeType="text/plain" /> |
||||||
|
</intent-filter> |
||||||
|
<intent-filter> |
||||||
|
<action android:name="android.intent.action.SEND" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" /> |
||||||
|
|
||||||
|
<data android:mimeType="text/plain" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
<!-- 一键导入 --> |
||||||
|
<activity |
||||||
|
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" /> |
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" /> |
||||||
|
<category android:name="android.intent.category.BROWSABLE" /> |
||||||
|
|
||||||
|
<data android:scheme="legado" /> |
||||||
|
<data android:scheme="yuedu" /> |
||||||
|
</intent-filter> |
||||||
|
</activity> |
||||||
|
<!-- 打开文件 --> |
||||||
|
<activity |
||||||
|
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: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> |
||||||
|
<!-- 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="*" /> |
||||||
|
|
||||||
|
<data android:scheme="app" /> |
||||||
|
<data android:scheme="content" /> |
||||||
|
<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.CacheBookService" /> |
||||||
|
<service android:name=".service.WebService" /> |
||||||
|
<service |
||||||
|
android:name=".service.WebTileService" |
||||||
|
android:exported="true" |
||||||
|
android:icon="@drawable/ic_web_service_noti" |
||||||
|
android:label="legado Web Service" |
||||||
|
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"> |
||||||
|
<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" |
||||||
|
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" |
||||||
|
android:enabled="true" |
||||||
|
android:exported="true" |
||||||
|
tools:ignore="ExportedContentProvider" /> |
||||||
|
<provider |
||||||
|
android:name="androidx.core.content.FileProvider" |
||||||
|
android:authorities="${applicationId}.fileProvider" |
||||||
|
android:exported="false" |
||||||
|
android:grantUriPermissions="true"> |
||||||
|
<meta-data |
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS" |
||||||
|
android:resource="@xml/file_paths" /> |
||||||
|
</provider> |
||||||
|
|
||||||
|
<meta-data |
||||||
|
android:name="channel" |
||||||
|
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> |
@ -0,0 +1,284 @@ |
|||||||
|
OGN5dS5jb20= |
||||||
|
c2cwMC54eXo= |
||||||
|
aXRyYWZmaWNuZXQuY29t |
||||||
|
eGlhb3FpYW5nNTIw |
||||||
|
MTIzeGlhb3FpYW5n |
||||||
|
eGlhb3FpYW5neHM= |
||||||
|
eGlhb3FpYW5nNTIw |
||||||
|
MzM1eHM= |
||||||
|
eGN4czk= |
||||||
|
eGN4czUyMA== |
||||||
|
c2h1YmFvYW4= |
||||||
|
c2h1YmFvd2FuZzEyMw== |
||||||
|
c2h1YmFvYW4= |
||||||
|
aGFpdGFuZzEyMw== |
||||||
|
eXV6aGFpd3VsYQ== |
||||||
|
cG8xOA== |
||||||
|
Ymwtbm92ZWw= |
||||||
|
NXRucw== |
||||||
|
c2hhb3NodWdl |
||||||
|
amluamlzaHV3dQ== |
||||||
|
NDJ3Zw== |
||||||
|
eWlxdXNodQ== |
||||||
|
c2h1YmFvd2FuZzEyMw== |
||||||
|
M2hlYmFv |
||||||
|
MzNoZWJhbw== |
||||||
|
bHVvcWl1enc= |
||||||
|
bXlzaHVnZQ== |
||||||
|
c3NzeHN3 |
||||||
|
eWl0ZQ== |
||||||
|
Y3Vpd2VpanV1 |
||||||
|
Y3Vpd2VpanV4cw== |
||||||
|
Y3Vpd2VpanV4 |
||||||
|
eGlhb3FpYW5nd3g= |
||||||
|
YXN6dw== |
||||||
|
YXN6dzY= |
||||||
|
c2FuaGFveHM= |
||||||
|
ODdzaHV3dQ== |
||||||
|
NDh3eA== |
||||||
|
bG9uZ3Rlbmcy |
||||||
|
NnF3eA== |
||||||
|
bG9uZ3Rlbmd4cw== |
||||||
|
aGF4ZHU= |
||||||
|
M3R3eA== |
||||||
|
aGF4d3g1 |
||||||
|
NjZsZXdlbg== |
||||||
|
eGJhbnpodQ== |
||||||
|
aGR5cA== |
||||||
|
ZHliejk= |
||||||
|
ZGl5aWJhbnpodTk= |
||||||
|
ZGl5aWJhbnpodQ== |
||||||
|
ZGl5aWJhbnpodTc= |
||||||
|
YnoyMjI= |
||||||
|
d29kZWFwaTAwMQ== |
||||||
|
dGFuZ3poZWthbg== |
||||||
|
YmF4aWFueHM= |
||||||
|
eGlhb3NodW9zaGVuemhhbg== |
||||||
|
ZGFtb2tl |
||||||
|
emh3ZW5wZw== |
||||||
|
eXV6aGFpZ2U= |
||||||
|
d21wOA== |
||||||
|
OXhpYW53ZW4= |
||||||
|
bmFucmVudmlw |
||||||
|
cmV5b28= |
||||||
|
eWZ4aWFvc2h1b2U= |
||||||
|
c2Fuaml1enc= |
||||||
|
N3Fpbmc3 |
||||||
|
cWR4aWFvc2h1bw== |
||||||
|
Y2hpbmVzZXpq |
||||||
|
MzlzaHViYW8= |
||||||
|
a3l4czU= |
||||||
|
NTZtcw== |
||||||
|
bml1c2hh |
||||||
|
bWt4czY= |
||||||
|
MjIyMjJ4cw== |
||||||
|
OTVkdXNodQ== |
||||||
|
YmFuemh1MjI= |
||||||
|
d3JsdHh0 |
||||||
|
dHVkb3V0eHQ= |
||||||
|
cm5neHM= |
||||||
|
OTl3ZW5rdQ== |
||||||
|
bGFvc2lqaXhz |
||||||
|
ZnVzaHV6aGFpMQ== |
||||||
|
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= |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 246 KiB |
After Width: | Height: | Size: 312 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 287 KiB |
@ -0,0 +1 @@ |
|||||||
|
{"arm64-v8a":"690c212d9bbad4b09b9e1ba450b273bb","armeabi-v7a":"4dbb88e5229abef7d84138218772f872","x86":"3f2421e040147da48abb07cfc6c7c87e","x86_64":"730a71ef4f03a27d1c8c8a77e7d09ff5","version":"96.0.4664.104"} |
@ -0,0 +1,48 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"bookSourceComment": "", |
||||||
|
"bookSourceGroup": "听书", |
||||||
|
"bookSourceName": "消消乐听书", |
||||||
|
"bookSourceType": 1, |
||||||
|
"bookSourceUrl": "https://www.kaixin7days.com", |
||||||
|
"customOrder": 0, |
||||||
|
"enabled": true, |
||||||
|
"enabledExplore": true, |
||||||
|
"exploreUrl": "@js:var header = JSON.parsesource.getLoginHeader()\nvar json = ''\nvar j = null\nif (header != null) {\n json = java.connect('https://www.kaixin7days.com/book-service/bookMgt/getBookCategroy,{\"method\":\"POST\",\"body\":{}}', header).body()\n j = JSON.parse(json)\n}\nif (j == null || j.statusCode != 200) {\n json = java.connect('https://www.kaixin7days.com/visitorLogin,{\"method\":\"POST\", \"body\":{} }').body()\n j = JSON.parse(json)\n var accessToken = {\n Authorization: 'Bearer ' + j.content.accessToken\n }\n header = JSON.stringify(accessToken)\n source.putLoginHeader(header)\n json = java.connect('https://www.kaixin7days.com/book-service/bookMgt/getBookCategroy,{\"method\":\"POST\",\"body\":{} }', header).body()\n j = JSON.parse(json)\n}\nvar fls = j.content\nvar fx = []\nfor (var i = 0; i < fls.length; i++) {\n fx.push({\n title: fls[i].categoryName,\n url: '/book-service/bookMgt/getAllBookByCategroyId,{\"method\":\"POST\",\"body\":{\"categoryIds\": \"' + fls[i].associationCategoryIDs + '\",\"pageNum\": {{page}},\"pageSize\": 100}}'\n })\n}\nJSON.stringify(fx)", |
||||||
|
"searchUrl": "https://www.kaixin7days.com/book-service/bookMgt/findBookName,{\"method\":\"POST\",\"body\":{\"title\": \"searchKey\",\"pageNum\": {{searchPage}},\"pageSize\": 100}}", |
||||||
|
"lastUpdateTime": 1630656684531, |
||||||
|
"loginCheckJs": "var strRes = result\nvar c = JSON.parse(result.body())\nif (c.statusCode == 301) {\n var loginInfo = source.getLoginInfo()\n var dl = null\n if (loginInfo) {\n dl = java.connect('https://www.kaixin7days.com/login,{\"method\":\"POST\",\"body\":' + loginInfo + '}').body()\n } else {\n dl = java.connect('https://www.kaixin7days.com/visitorLogin,{\"method\":\"POST\",\"body\":{}}').body()\n }\n c = JSON.parse(dl)\n var accessToken = {\n Authorization: \"Bearer \" + c.content.accessToken\n }\n var header = JSON.stringify(accessToken)\n source.putLoginHeader(header)\n strRes = java.connect(url, header)\n}\nstrRes", |
||||||
|
"loginUi": "[{\"name\": \"telephone\",\"type\": \"text\"},{\"name\": \"password\",\"type\": \"password\"},{\"name\": \"注册\",\"type\": \"button\",\"action\": \"http://www.yooike.com/xiaoshuo/#/register?title=%E6%B3%A8%E5%86%8C\"}]", |
||||||
|
"loginUrl": "var loginInfo = source.getLoginInfo()\nvar json = java.connect('https://www.kaixin7days.com/login,{\"method\":\"POST\",\"body\":' + loginInfo + '}').body()\nvar loginRes = JSON.parse(json)\nvar header = null\nif (loginRes.statusCode == 200) {\n var accessToken = {\n Authorization: \"Bearer \" + loginRes.content.accessToken\n }\n header = JSON.stringify(accessToken)\n source.putLoginHeader(header)\n}\nheader", |
||||||
|
"respondTime": 180000, |
||||||
|
"ruleBookInfo": {}, |
||||||
|
"ruleContent": { |
||||||
|
"content": "", |
||||||
|
"payAction": "var header = JSON.parse(source.getLoginHeader()); var bookId = book.getVariableMap().get('bookId');var chapterId = java.get('chapterId');\n'http://www.shuidi.online/?name=' + book.getName() + '&type=2&cover=' + book.getCoverUrl() + '&chapterId=' + chapterId + '&chapter=203&allNumber=' + book.getTotalChapterNum() + '&bookId=' + bookId + '&chapterIds=' + chapterId + '&number=' + chapter.getIndex() + '&accessToken=' + header.Authorization.substring(7) + '#/pay'" |
||||||
|
}, |
||||||
|
"ruleExplore": { |
||||||
|
"author": "$.author", |
||||||
|
"bookList": "$.content.content", |
||||||
|
"bookUrl": "$.id@js:java.put('bookId', result);'https://www.kaixin7days.com/book-service/bookMgt/getAllChapterByBookId,{ \"method\": \"POST\",\"body\": {\"bookId\": \"'+result+'\",\"pageNum\": \"1\",\"pageSize\": \"10000\"} }'", |
||||||
|
"coverUrl": "$.cover@js:var cover = JSON.parse(result);'https://www.shuidi.online/fileMgt/getPicture?filePath='+cover.storeFilePath", |
||||||
|
"intro": "$.desc", |
||||||
|
"lastChapter": "$.newestChapter", |
||||||
|
"name": "$.title" |
||||||
|
}, |
||||||
|
"ruleSearch": { |
||||||
|
"author": "$.author", |
||||||
|
"bookList": "$.content.content", |
||||||
|
"bookUrl": "$.id@js:java.put('bookId', result);'https://www.kaixin7days.com/book-service/bookMgt/getAllChapterByBookId,{ \"method\": \"POST\",\"body\": {\"bookId\": \"'+result+'\",\"pageNum\": \"1\",\"pageSize\": \"10000\"} }'", |
||||||
|
"coverUrl": "$.cover@js:var cover = JSON.parse(result);'https://www.shuidi.online/fileMgt/getPicture?filePath='+cover.storeFilePath", |
||||||
|
"intro": "$.desc", |
||||||
|
"lastChapter": "$.newestChapter", |
||||||
|
"name": "$.title" |
||||||
|
}, |
||||||
|
"ruleToc": { |
||||||
|
"chapterList": "$.content.content", |
||||||
|
"chapterName": "$.chapterTitle", |
||||||
|
"chapterUrl": "$.id@js:java.put('chapterId', result);'https://www.shuidi.online/fileMgt/getAudioByChapterId?bookId=' + java.get('bookId') + '&chapterId=' + result + \"&pageNum=1&pageSize=50&keyId={{var header = JSON.parse(source.getLoginHeader());var keyId = '1632746188011002';var ks = java.md5Encode(keyId + java.get('chapterId') + header.Authorization);keyId + '&keySecret=' + ks}\" + '}'" |
||||||
|
}, |
||||||
|
"weight": 0 |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,5 @@ |
|||||||
|
{ |
||||||
|
"UploadUrl": "http://sy.miaogongzi.cc/shuyuan,{\"method\":\"POST\",\"body\": {\"file\": \"fileRequest\"},\"type\": \"multipart/form-data\"}", |
||||||
|
"DownloadUrlRule": "$.data@js:if (result == '') \n '' \n else \n 'https://shuyuan.miaogongzi.cc/shuyuan/' + result", |
||||||
|
"summary": "有效期2天" |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"id": -100, |
||||||
|
"name": "1.百度", |
||||||
|
"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}", |
||||||
|
"contentType": "audio/wav" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"id": -29, |
||||||
|
"name": "2.阿里云语音", |
||||||
|
"url": "https://nls-gateway.cn-shanghai.aliyuncs.com/stream/v1/tts,{\"method\": \"POST\",\"body\": {\"appkey\":\"{{source.getLoginInfoMap().get('AppKey')}}\",\"text\":\"{{speakText}}\",\"format\":\"mp3\",\"volume\":100,\"speech_rate\":{{String((speakSpeed) * 20 - 400)}} }}", |
||||||
|
"contentType": "audio/mpeg", |
||||||
|
"loginUrl": "var loginInfo = source.getLoginInfoMap();\nvar accessKeyId = loginInfo.get('AccessKeyId');\nvar accessKeySecret = loginInfo.get('AccessKeySecret');\nvar timestamp = java.timeFormatUTC(new Date().getTime(), \"yyyy-MM-dd'T'HH:mm:ss'Z'\", 0);\nvar aly = new JavaImporter(Packages.javax.crypto.Mac, Packages.javax.crypto.spec.SecretKeySpec, Packages.javax.xml.bind.DatatypeConverter, Packages.java.net.URLEncoder, Packages.java.lang.String, Packages.android.util.Base64);\nwith (aly) {\n function percentEncode(value) {\n return URLEncoder.encode(value, \"UTF-8\").replace(\"+\", \"%20\")\n .replace(\"*\", \"%2A\").replace(\"%7E\", \"~\")\n }\n\n function sign(stringToSign, accessKeySecret) {\n var mac = Mac.getInstance('HmacSHA1');\n mac.init(new SecretKeySpec(String(accessKeySecret + '&').getBytes(\"UTF-8\"), \"HmacSHA1\"));\n var signData = mac.doFinal(String(stringToSign).getBytes(\"UTF-8\"));\n var signBase64 = Base64.encodeToString(signData, Base64.NO_WRAP);\n var signUrlEncode = percentEncode(signBase64);\n return signUrlEncode;\n }\n}\nvar query = 'AccessKeyId=' + accessKeyId + '&Action=CreateToken&Format=JSON&RegionId=cn-shanghai&SignatureMethod=HMAC-SHA1&SignatureNonce=' + java.randomUUID() + '&SignatureVersion=1.0&Timestamp=' + percentEncode(timestamp) + '&Version=2019-02-28';\nvar signStr = sign('GET&' + percentEncode('/') + '&' + percentEncode(query), accessKeySecret);\nvar queryStringWithSign = \"Signature=\" + signStr + \"&\" + query;\nvar body = java.ajax('http://nls-meta.cn-shanghai.aliyuncs.com/?' + queryStringWithSign)\nvar res = JSON.parse(body)\nif (res.Message) {\n throw new Error(res.Message)\n}\nvar header = { \"X-NLS-Token\": res.Token.Id };\nsource.putLoginHeader(JSON.stringify(header))", |
||||||
|
"loginUi": [ |
||||||
|
{ |
||||||
|
"name": "AppKey", |
||||||
|
"type": "text" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "AccessKeyId", |
||||||
|
"type": "text" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"name": "AccessKeySecret", |
||||||
|
"type": "text" |
||||||
|
} |
||||||
|
], |
||||||
|
"loginCheckJs": "var response = result;\nif (response.headers().get(\"Content-Type\") != \"audio/mpeg\") {\n var body = JSON.parse(response.body().string())\n if (body.status == 40000001) {\n source.login()\n java.getHeaderMap().putAll(source.getHeaderMap(true))\n response = java.getResponse()\n } else {\n throw body.message\n }\n}\nresponse" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,42 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"customOrder": 1, |
||||||
|
"enableJs": true, |
||||||
|
"enabled": true, |
||||||
|
"singleUrl": true, |
||||||
|
"sourceGroup": "legado", |
||||||
|
"sourceIcon": "https://cdn.jsdelivr.net/gh/gedoor/legado@master/app/src/main/res/mipmap-hdpi/ic_launcher.png", |
||||||
|
"sourceName": "使用说明", |
||||||
|
"sourceUrl": "https://www.yuque.com/legado" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"customOrder": 2, |
||||||
|
"enableJs": true, |
||||||
|
"enabled": true, |
||||||
|
"singleUrl": true, |
||||||
|
"sourceGroup": "legado", |
||||||
|
"sourceIcon": "http://mmbiz.qpic.cn/mmbiz_png/hpfMV8hEuL2eS6vnCxvTzoOiaCAibV6exBzJWq9xMic9xDg3YXAick87tsfafic0icRwkQ5ibV0bJ84JtSuxhPuEDVquA/0?wx_fmt=png", |
||||||
|
"sourceName": "小说拾遗", |
||||||
|
"sourceUrl": "snssdk1128://user/profile/562564899806367" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"customOrder": 3, |
||||||
|
"enableJs": true, |
||||||
|
"enabled": true, |
||||||
|
"singleUrl": true, |
||||||
|
"sourceGroup": "legado", |
||||||
|
"sourceIcon": "https://Cloud.miaogongzi.site/images/icon.png", |
||||||
|
"sourceName": "Meow云", |
||||||
|
"sourceUrl": "https://pan.miaogongzi.net" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"customOrder": 4, |
||||||
|
"enableJs": true, |
||||||
|
"enabled": true, |
||||||
|
"singleUrl": true, |
||||||
|
"sourceGroup": "legado", |
||||||
|
"sourceIcon": "https://cdn.jsdelivr.net/gh/gedoor/legado@master/app/src/main/res/mipmap-hdpi/ic_launcher.png", |
||||||
|
"sourceName": "烏雲净化", |
||||||
|
"sourceUrl": "https://www.lanzoux.com/b0bw8jwoh" |
||||||
|
} |
||||||
|
] |
@ -0,0 +1,26 @@ |
|||||||
|
[ |
||||||
|
{ |
||||||
|
"themeName": "典雅蓝", |
||||||
|
"isNightTheme": false, |
||||||
|
"primaryColor": "#03A9F4", |
||||||
|
"accentColor": "#AD1457", |
||||||
|
"backgroundColor": "#F5F5F5", |
||||||
|
"bottomBackground": "#EEEEEE" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"themeName": "黑白", |
||||||
|
"isNightTheme": true, |
||||||
|
"primaryColor": "#303030", |
||||||
|
"accentColor": "#E0E0E0", |
||||||
|
"backgroundColor": "#424242", |
||||||
|
"bottomBackground": "#424242" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"themeName": "A屏黑", |
||||||
|
"isNightTheme": true, |
||||||
|
"primaryColor": "#000000", |
||||||
|
"accentColor": "#FFFFFF", |
||||||
|
"backgroundColor": "#000000", |
||||||
|
"bottomBackground": "#000000" |
||||||
|
} |
||||||
|
] |