diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..6c49568 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,20 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**请详细描述一下遇到的问题** + +**期望的结果** + +**书籍BookID** +如果涉及到特定书籍,请提供书籍的 bookId; +如果下载的书有格式错误,请提供一份有问题的文件方便调试 + +**运行平台** + +**使用的阅读器及版本** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..010478f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,10 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**请详细描述一下你想要的功能** diff --git a/.gitignore b/.gitignore index 861e5b7..b2ccb78 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ .husky/pre-push .DS_Store node_modules +download +test diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..1ddf16e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${file}", + "outFiles": [ + "${workspaceFolder}/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 60e01b7..c359c51 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,146 @@ # wereadx -微信读书辅助工具,基于微信读书网页版开发的额外功能 +微信读书辅助工具,数据来自于微信读书网页版 + +## 声明 +**本软件只能下载用户可访问的书籍,不支持下载需付费才能查看的书籍,请勿用于非法用途!本软件作者不对滥用行为承担任何赔偿责任。** + +## ⚠️警告⚠️ +- **不要同时下载多本书,不但容易下载失败,还可能导致被微信读书封号处理!!!** +- **尽量不要下载超过 200 章的书,很容易被检测到然后封号** +- **本工具可靠性已经不能保证,很容易被检测到,尽量不要再用了** ## 功能列表 -1. 下载书架上的书到本地,目前仅支持下载 html 格式 +1. 下载书架上的书到本地,仅支持下载 **html** 和 **epub** 格式 2. 自动更新阅读时长,可用于刷“读书排行榜”或者“阅读挑战赛” 3. 每周日晚 23:30 自动领取“时长兑福利”中的免费体验卡(暂未对外开放) -4. 支持下载用户上传的 pdf 格式的书(不计入下载次数限制,因为走的是外部的流量) +4. 支持下载用户自己上传的 pdf 格式的书 -> 如果需要更多功能,可以在issue区讨论 +## 本地运行 -## 环境变量说明 -请在项目根目录下新建`.env`文件,存放以下环境变量: -``` -# Supabase 数据库连接字符串 -DATABASE_URL= +> 需要提前安装 deno,参考官方的[安装指南](https://docs.deno.com/runtime/manual/getting_started/installation) -# Deno KV Access Token -DENO_KV_ACCESS_TOKEN= - -# Deno KV UUID -DENO_KV_UUID= +```shell +deno task dev +``` +或者 +```shell +npm run dev ``` +或者 +```shell +yarn dev +``` + ## 部署指南 > 如果想要自己部署,可参考以下步骤进行部署,目前仅支持部署到 Deno Deploy。 -> 如果不想自己部署,可以使用 https://weread.deno.dev 公共服务,但有会限制,比如下载次数限制为每月100次,不支持自动领取体验卡等。 +> 如果不想自己部署,可以使用 https://weread.deno.dev 公共服务,但会有限制,比如下载次数限制为每月100次,不支持自动领取体验卡等。 ### 1. fork 本项目 -### 2. 在根目录创建`.env`文件,内容按照上面的说明填写 - -### 3. 新建 Deno Deploy 项目,配置如下: +### 2. 新建 Deno Deploy 项目,配置如下: ![项目配置](assets/setup.png) -### 4. 部署完成,在 Deno Deploy 的设置页面,添加环境变量 +### 3. 部署完成,在 Deno Deploy 的设置页面,添加环境变量 + +| 变量名 | 功能 | 是否必填 | +|----------------|-----------------------------------------------|---------------| +| DEPLOY_DOMAIN | 最终部署的域名,格式为: `https://xxx.deno.dev`,与发送提醒邮件有关 | 需要自动阅读暂停提醒时必填 | +| RESEND_API_KEY | 用于发送邮件,格式为: `re_xxx` | 需要自动阅读暂停提醒时必填 | +| RESEND_DOMAIN | Resend 配置的域名,不含`https://`前缀 | 需要自动阅读暂停提醒时必填 | +| DATABASE_URL | 记录日志,格式为: `postgresql://xxx` | 选填 | +| CRON_KEY | cron任务的key (自定义的随机字符串,在下面的触发器任务中使用) | 使用cron任务时必填 | + + +
+获取 RESEND_API_KEY 和 RESEND_DOMAIN + +注册 https://resend.com/ 账号,然后添加一个 API key,如下图: + +![resend api key](assets/resend-api-key1.png) +![resend api key](assets/resend-api-key2.png) + + +想要正常发送邮件,还需要配置域名 +![resend domain](assets/resend-domain1.png) +![resend domain](assets/resend-domain2.png) + +按照这个配置你的域名,最终效果如下: +![resend domain result](assets/resend-domain-result.png) +
+ + +
+获取 DATABASE_URL + +注册 https://supabase.com/ 账号,创建一个新的项目,如下图: + +![创建一个数据库项目](assets/new-database-project.png) + +> **保存这个数据库密码,后面连接字符串需要使用** + +等待项目创建成功后,进入**Project Settings**里面的**Database**: + +![数据库配置入口](assets/database-entry.png) + +找到 **连接字符串** 面板,切换到`URI`,这个就是`DATABASE_URL`。注意需要用上面保存的数据库密码替换里面的`[YOUR-PASSWORD]`部分。 + +![连接字符串](assets/connect-string.png) +
+ +完整的环境变量配置如下: + ![环境变量配置](assets/env.png) +### 4. 设置定时任务 +自动阅读和兑换体验卡都需要定时任务来触发执行,目前deno deploy自己的消息队列不太好用,所以采用 cloudflare 的 worker 来作为定时任务的触发器。 + +#### 自动阅读的触发器 +在 CloudFlare 控制台添加一个 worker,代码如下: +```js +export default { + async scheduled(event, env, ctx) { + // 注意:此处的域名替换成你自己部署的域名,CRON_KEY 替换成上面环境变量配置的 CRON_KEY + const resp = await fetch('https://[your.domain.com]/cron/read/v2?key=[CRON_KEY]') + console.log(await resp.text()) + }, +}; +``` +设置 cron 触发周期为 `*/30 19-21 * * *`(北京时间每天凌晨3点到凌晨6点,中间每隔30分钟更新一次),如下图所示: +![自动阅读的触发器](assets/cron-read.png) + +#### 自动兑换体验卡的触发器 +worker代码如下: +```js +export default { + async scheduled(event, env, ctx) { + // 注意:此处的域名替换成你自己部署的域名,CRON_KEY 替换成上面环境变量配置的 CRON_KEY + const resp = await fetch('https://[your.domain.com]/cron/exchange-awards?key=[CRON_KEY]') + console.log(await resp.text()) + }, +}; +``` +触发周期设置为 `30 15 * * sun`(北京时间每周日晚11点30分),如下图所示: +![兑换体验卡的触发器](assets/cron-exchange.png) + + +### 5. 后续更新操作 +如果发现 fork 的版本比源版本落后,需要更新到最新版本时,只需要在 github 更新仓库代码即可,不需要删除 deploy 上面的项目重新 fork。 + +![fork版本是最新版本](assets/fork-is-latest.png) +上面这个图表示当前 fork 的代码是最新版本,不需要更新。 + +![fork版本是落后版本](assets/fork-is-behind.png) +上面这个图表示当前 fork 的代码落后源版本1个版本,可以点击右边的**Sync fork**更新代码,如下图所示: + +![更新fork版本](assets/update-fork.png) + +更新完之后,deploy 上面会自动重新部署最新版本。 + ## 特别注意 @@ -54,13 +155,17 @@ DENO_KV_UUID= ![登录时二次确认](assets/login.png) -这个应该是属于微信读书的bug,后续如果微信读书调整的话,我会跟进处理这个问题。 +这个应该是属于微信读书的bug,后续如果微信读书调整的话,我再跟进处理这个问题。 ## 后续计划 -- 修复部分图片无法加载的问题; -- 美化网站样式; -- 添加更多微信读书API,比如导出笔记、书评等; -- 支持下载更多电子书格式,比如 epub/azw3 等,[可以关注这个issue。](https://github.com/champkeh/wereadx/issues/2) -- 加入搜索功能,方便下载非书架上的书(因为[技术限制](https://github.com/champkeh/wereadx/issues/3),并不保证能搜索到所有的书)。 +- 解决 issue 中的 bug 及提出的优化点; +- 优化网站样式; +- 优化 epub 格式; +- 导出书籍中的的笔记/划线; + + +## Stargazers over time + +[![Stargazers over time](https://starchart.cc/champkeh/wereadx.svg)](https://starchart.cc/champkeh/wereadx) diff --git a/assets/connect-string.png b/assets/connect-string.png new file mode 100644 index 0000000..8f4acdf Binary files /dev/null and b/assets/connect-string.png differ diff --git a/assets/cron-exchange.png b/assets/cron-exchange.png new file mode 100644 index 0000000..6dc6065 Binary files /dev/null and b/assets/cron-exchange.png differ diff --git a/assets/cron-read.png b/assets/cron-read.png new file mode 100644 index 0000000..2757589 Binary files /dev/null and b/assets/cron-read.png differ diff --git a/assets/database-entry.png b/assets/database-entry.png new file mode 100644 index 0000000..03a703b Binary files /dev/null and b/assets/database-entry.png differ diff --git a/assets/env.png b/assets/env.png index 3d90617..b02d66d 100644 Binary files a/assets/env.png and b/assets/env.png differ diff --git a/assets/fork-is-behind.png b/assets/fork-is-behind.png new file mode 100644 index 0000000..5c552e5 Binary files /dev/null and b/assets/fork-is-behind.png differ diff --git a/assets/fork-is-latest.png b/assets/fork-is-latest.png new file mode 100644 index 0000000..67f215e Binary files /dev/null and b/assets/fork-is-latest.png differ diff --git a/assets/new-database-project.png b/assets/new-database-project.png new file mode 100644 index 0000000..ee211c6 Binary files /dev/null and b/assets/new-database-project.png differ diff --git a/assets/resend-api-key1.png b/assets/resend-api-key1.png new file mode 100644 index 0000000..5413125 Binary files /dev/null and b/assets/resend-api-key1.png differ diff --git a/assets/resend-api-key2.png b/assets/resend-api-key2.png new file mode 100644 index 0000000..eaa1230 Binary files /dev/null and b/assets/resend-api-key2.png differ diff --git a/assets/resend-domain-result.png b/assets/resend-domain-result.png new file mode 100644 index 0000000..e71c6ac Binary files /dev/null and b/assets/resend-domain-result.png differ diff --git a/assets/resend-domain1.png b/assets/resend-domain1.png new file mode 100644 index 0000000..bbcb305 Binary files /dev/null and b/assets/resend-domain1.png differ diff --git a/assets/resend-domain2.png b/assets/resend-domain2.png new file mode 100644 index 0000000..b329edf Binary files /dev/null and b/assets/resend-domain2.png differ diff --git a/assets/update-fork.png b/assets/update-fork.png new file mode 100644 index 0000000..3ea5750 Binary files /dev/null and b/assets/update-fork.png differ diff --git a/deno.json b/deno.json new file mode 100644 index 0000000..206e401 --- /dev/null +++ b/deno.json @@ -0,0 +1,12 @@ +{ + "nodeModulesDir": "auto", + "tasks": { + "dev": "deno run -A --unstable --unstable-kv src/server.ts local", + "serve": "deno run -A --unstable --unstable-kv src/server.ts" + }, + "imports": { + "crypto-js": "npm:crypto-js@4.2.0", + "xss": "npm:xss@1.0.14", + "parse5": "npm:parse5@7.1.2" + } +} \ No newline at end of file diff --git a/deno.lock b/deno.lock new file mode 100644 index 0000000..e477db5 --- /dev/null +++ b/deno.lock @@ -0,0 +1,547 @@ +{ + "version": "4", + "specifiers": { + "npm:crypto-js@*": "4.2.0", + "npm:crypto-js@4.2.0": "4.2.0", + "npm:crypto-js@^4.2.0": "4.2.0", + "npm:css-tree@2.3.1": "2.3.1", + "npm:parse5@7.1.2": "7.1.2", + "npm:xss@1.0.14": "1.0.14" + }, + "npm": { + "commander@2.20.3": { + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "crypto-js@4.2.0": { + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "css-tree@2.3.1": { + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": [ + "mdn-data", + "source-map-js" + ] + }, + "cssfilter@0.0.10": { + "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==" + }, + "entities@4.5.0": { + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "mdn-data@2.0.30": { + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "parse5@7.1.2": { + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": [ + "entities" + ] + }, + "source-map-js@1.2.1": { + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==" + }, + "xss@1.0.14": { + "integrity": "sha512-og7TEJhXvn1a7kzZGQ7ETjdQVS2UfZyTlsEdDOqvQF7GoxNfY+0YLCzBy1kPdsDDx4QuNAonQPddpsn6Xl/7sw==", + "dependencies": [ + "commander", + "cssfilter" + ] + } + }, + "redirects": { + "https://esm.sh/linkedom": "https://esm.sh/linkedom@0.18.5" + }, + "remote": { + "https://deno.land/std@0.132.0/_deno_unstable.ts": "23a1a36928f1b6d3b0170aaa67de09af12aa998525f608ff7331b9fb364cbde6", + "https://deno.land/std@0.132.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", + "https://deno.land/std@0.132.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617", + "https://deno.land/std@0.132.0/_wasm_crypto/crypto.mjs": "3b383eb715e8bfe61b4450ef0644b2653429c88d494807c86c5235979f62e56b", + "https://deno.land/std@0.132.0/_wasm_crypto/crypto.wasm.mjs": "0ad9ecc0d03ca8a083d9109db22e7507f019f63cf55b82ea618ab58855617577", + "https://deno.land/std@0.132.0/_wasm_crypto/mod.ts": "30a93c8b6b6c5b269e96a3e95d2c045d86a496814a8737443b77cad941d6a0b5", + "https://deno.land/std@0.132.0/async/abortable.ts": "87aa7230be8360c24ad437212311c9e8d4328854baec27b4c7abb26e85515c06", + "https://deno.land/std@0.132.0/async/deadline.ts": "48ac998d7564969f3e6ec6b6f9bf0217ebd00239b1b2292feba61272d5dd58d0", + "https://deno.land/std@0.132.0/async/debounce.ts": "564273ef242bcfcda19a439132f940db8694173abffc159ea34f07d18fc42620", + "https://deno.land/std@0.132.0/async/deferred.ts": "bc18e28108252c9f67dfca2bbc4587c3cbf3aeb6e155f8c864ca8ecff992b98a", + "https://deno.land/std@0.132.0/async/delay.ts": "cbbdf1c87d1aed8edc7bae13592fb3e27e3106e0748f089c263390d4f49e5f6c", + "https://deno.land/std@0.132.0/async/mod.ts": "2240c6841157738414331f47dee09bb8c0482c5b1980b6e3234dd03515c8132f", + "https://deno.land/std@0.132.0/async/mux_async_iterator.ts": "f4d1d259b0c694d381770ddaaa4b799a94843eba80c17f4a2ec2949168e52d1e", + "https://deno.land/std@0.132.0/async/pool.ts": "97b0dd27c69544e374df857a40902e74e39532f226005543eabacb551e277082", + "https://deno.land/std@0.132.0/async/tee.ts": "1341feb1f5b1a96f8628d0f8fc07d8c43d3813423f18a63bf1b4785568d21b1f", + "https://deno.land/std@0.132.0/bytes/bytes_list.ts": "67eb118e0b7891d2f389dad4add35856f4ad5faab46318ff99653456c23b025d", + "https://deno.land/std@0.132.0/bytes/equals.ts": "fc16dff2090cced02497f16483de123dfa91e591029f985029193dfaa9d894c9", + "https://deno.land/std@0.132.0/bytes/mod.ts": "d3b455c0dbd4804644159d1e25946ade5ee385d2359894de49e2c6101b18b7a9", + "https://deno.land/std@0.132.0/encoding/base64.ts": "c8c16b4adaa60d7a8eee047c73ece26844435e8f7f1328d74593dbb2dd58ea4f", + "https://deno.land/std@0.132.0/encoding/base64url.ts": "55f9d13df02efac10c6f96169daa3e702606a64e8aa27c0295f645f198c27130", + "https://deno.land/std@0.132.0/encoding/hex.ts": "7f023e1e51cfd6b189682e602e8640939e7be71a300a2fcf3daf8f84dc609bbc", + "https://deno.land/std@0.132.0/flags/mod.ts": "430cf2d1c26e00286373b2647ebdca637f7558505e88e9c108a4742cd184c916", + "https://deno.land/std@0.132.0/fmt/colors.ts": "30455035d6d728394781c10755351742dd731e3db6771b1843f9b9e490104d37", + "https://deno.land/std@0.132.0/fmt/printf.ts": "e2c0f72146aed1efecf0c39ab928b26ae493a2278f670a871a0fbdcf36ff3379", + "https://deno.land/std@0.132.0/fs/eol.ts": "b92f0b88036de507e7e6fbedbe8f666835ea9dcbf5ac85917fa1fadc919f83a5", + "https://deno.land/std@0.132.0/fs/exists.ts": "cb734d872f8554ea40b8bff77ad33d4143c1187eac621a55bf37781a43c56f6d", + "https://deno.land/std@0.132.0/hash/sha256.ts": "803846c7a5a8a5a97f31defeb37d72f519086c880837129934f5d6f72102a8e8", + "https://deno.land/std@0.132.0/io/buffer.ts": "bd0c4bf53db4b4be916ca5963e454bddfd3fcd45039041ea161dbf826817822b", + "https://deno.land/std@0.132.0/node/_buffer.mjs": "f4a7df481d4eed06dc0151b833177d8ef74fc3a96dd4d2b073e690b6ced9474d", + "https://deno.land/std@0.132.0/node/_core.ts": "568d277be2e086af996cbdd599fec569f5280e9a494335ca23ad392b130d7bb9", + "https://deno.land/std@0.132.0/node/_crypto/constants.ts": "49011c87be4e45407ef5e99e96bde3f08656ebd8e6dfc99048c703dd0ce53952", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/buffer.js": "73beb8294eb29bd61458bbaaeeb51dfad4ec9c9868a62207a061d908f1637261", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/node.js": "4b777980d2a23088698fd2ff065bb311a2c713497d359e674cb6ef6baf267a0f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/base/reporter.js": "8e4886e8ae311c9a92caf58bbbd8670326ceeae97430f4884e558e4acf8e8598", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/constants/der.js": "354b255479bff22a31d25bf08b217a295071700e37d0991cc05cac9f95e5e7ca", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/decoders/der.js": "c6faf66761daa43fbf79221308443893587c317774047b508a04c570713b76fb", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/decoders/pem.js": "8316ef7ce2ce478bc3dc1e9df1b75225d1eb8fb5d1378f8adf0cf19ecea5b501", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/encoders/der.js": "408336c88d17c5605ea64081261cf42267d8f9fda90098cb560aa6635bb00877", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/encoders/pem.js": "42a00c925b68c0858d6de0ba41ab89935b39fae9117bbf72a9abb2f4b755a2e7", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/asn1.js/mod.js": "7b78859707be10a0a1e4faccdd28cd5a4f71ad74a3e7bebda030757da97cd232", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/bn.js/bn.js": "abd1badd659fd0ae54e6a421a573a25aef4e795edc392178360cf716b144286d", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/aes.js": "1cf4c354c5bb341ffc9ab7207f471229835b021947225bce2e1642f26643847a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/auth_cipher.js": "19b4dbb903e8406eb733176e6318d5e1a3bd382b67b72f7cf8e1c46cc6321ba4", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/decrypter.js": "05c1676942fd8e95837115bc2d1371bcf62e9bf19f6c3348870961fc64ddad0b", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/encrypter.js": "93ec98ab26fbeb5969eae2943e42fb66780f377b9b0ff0ecc32a9ed11201b142", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/ghash.js": "667b64845764a84f0096ef8cf7debed1a5f15ac9af26b379848237be57da399a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/incr32.js": "4a7f0107753e4390b4ccc4dbd5200c5527d43f894f768e131903df30a09dfd67", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/mod.js": "d8eb88e7a317467831473621f32e60d7db9d981f6a2ae45d2fb2af170eab2d22", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cbc.js": "9790799cff181a074686c885708cb8eb473aeb3c86ff2e8d0ff911ae6c1e4431", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb.js": "a4e36ede6f26d8559d8f0528a134592761c706145a641bd9ad1100763e831cdb", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb1.js": "c6372f4973a68ca742682e81d1165e8869aaabf0091a8b963d4d60e5ee8e6f6a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/cfb8.js": "bd29eebb89199b056ff2441f7fb5e0300f458e13dcaaddbb8bc00cbdb199db67", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ctr.js": "9c2cbac1fc8f9b58334faacb98e6c57e8c3712f673ea4cf2d528a2894998ab2f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ecb.js": "9629d193433688f0cfc432eca52838db0fb28d9eb4f45563df952bde50b59763", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/mod.js": "7d8516ef8a20565539eb17cad5bb70add02ac06d1891e8f47cb981c22821787e", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/modes/ofb.js": "c23abaa6f1ec5343e9d7ba61d702acb3d81a0bd3d34dd2004e36975dc043d6ff", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/stream_cipher.js": "a533a03a2214c6b5934ce85a59eb1e04239fd6f429017c7ca3c443ec7e07e68f", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_aes/xor.ts": "4417711c026eb9a07475067cd31fa601e88c2d6ababd606d33d1e74da6fcfd09", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/browserify_rsa.js": "de8c98d2379a70d8c239b4886e2b3a11c7204eec39ae6b65d978d0d516ee6b08", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/cipher_base.js": "f565ad9daf3b3dd3b68381bed848da94fb093a9e4e5a48c92f47e26cc229df39", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/evp_bytes_to_key.ts": "8bd9fa445576b3e39586bdbef7c907f1dfda201bf22602d2ca1c6d760366311e", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/asn1.js": "4f33b0197ffbe9cff62e5bad266e6b40d55874ea653552bb32ed251ad091f70a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/certificate.js": "aab306870830a81ad188db8fa8e037d7f5dd6c5abdabbd9739558245d1a12224", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/fix_proc.js": "af3052b76f441878e102ffcfc7420692e65777af765e96f786310ae1acf7f76a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/parse_asn1/mod.js": "e923a13b27089a99eeb578d2ffb9b4cfe8ce690918fec05d0024fa126f3e1ce3", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/mgf.js": "5b81dc1680829b564fc5a00b842fb9c88916e4639b4fa27fa8bb6b759d272371", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/mod.js": "eb8b64d7a58ee3823c1b642e799cc7ed1257d99f4d4aefa2b4796dd112ec094a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/private_decrypt.js": "0050df879f7c1338132c45056835f64e32140e2a2d5d03c1366ccce64855f632", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/public_encrypt.js": "0132cb4fb8f72593278474884195b9c52b4e9ba33d8ddd22116d07a07f47005a", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/with_public.js": "7373dac9b53b8331ccf3521c854a131dcb304a2e4d34cd116649118f7919ed0c", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/public_encrypt/xor.js": "900c6fc8b95e1861d796193c41988f5f70a09c7059e42887a243d0113ecaf0fd", + "https://deno.land/std@0.132.0/node/_crypto/crypto_browserify/randombytes.ts": "f465cd8e114a3c110297e0143445b12125d729b25bada5bd88d5b30cf612d7dd", + "https://deno.land/std@0.132.0/node/_crypto/hash.ts": "6a84a079412d09ead27b900590f0bede9924bc7ce522b8b7d55183a2aaf63a68", + "https://deno.land/std@0.132.0/node/_crypto/pbkdf2.ts": "00af38578729b3060371dfee70dae502a5848b4cc4787c48f634195cab1ce89a", + "https://deno.land/std@0.132.0/node/_crypto/randomBytes.ts": "04e276bcbfa55b3502c7169deab3f2bf58bbc5e9727634f8a150eff734338e90", + "https://deno.land/std@0.132.0/node/_crypto/randomFill.ts": "019ff2a8330c3ede6e65af28c5a8e3dee9d404975749c8dadf6ba11ccc28528e", + "https://deno.land/std@0.132.0/node/_crypto/randomInt.ts": "2db981c2baf4ddac07b6da71f90677f4acf4dc2d93f351563fdd084d645b8413", + "https://deno.land/std@0.132.0/node/_crypto/scrypt.ts": "caf07a6b8afa6ac582f80f99ed7dc7fefd5476fcd2aad771b8440e5b883d6d70", + "https://deno.land/std@0.132.0/node/_crypto/timingSafeEqual.ts": "4a4ef17e482889d9d82138d5ffc0e787c32c04b1f12b28d076b1a69ceca46af1", + "https://deno.land/std@0.132.0/node/_crypto/types.ts": "d3fae758c5b62f63d8126c76eec31a5559a2f34305defb5fe2a7d9034057ff54", + "https://deno.land/std@0.132.0/node/_dns/_utils.ts": "42494c8b8fa1c13eb134c5696744f77197717fa857e4d05147f2395a739b0a40", + "https://deno.land/std@0.132.0/node/_events.mjs": "d7d56df4b9f69e445064bad5e5558978fb18c18c439bbb62fa13149b40d7fb99", + "https://deno.land/std@0.132.0/node/_fixed_queue.ts": "455b3c484de48e810b13bdf95cd1658ecb1ba6bcb8b9315ffe994efcde3ba5f5", + "https://deno.land/std@0.132.0/node/_fs/_fs_access.ts": "0700488320d37208d000b94767ab37208d469550767edab69b65b09a330f245d", + "https://deno.land/std@0.132.0/node/_fs/_fs_appendFile.ts": "5dca59d7f2ec33316d75da3d6a12d39f5c35b429bddf83f4b2c030b3a289d4b3", + "https://deno.land/std@0.132.0/node/_fs/_fs_chmod.ts": "8fc25677b82a2643686e6f8270a8f1bee87dd60986334591450699e199dac7d5", + "https://deno.land/std@0.132.0/node/_fs/_fs_chown.ts": "57858c54d376648fc3c8cf5a8ad4f7f19fb153b75fac3ed41df0332d757e7de9", + "https://deno.land/std@0.132.0/node/_fs/_fs_close.ts": "785a9d1a6d615e8aa9f5a4ac50c9a131931f8b0e17b3d4671cd1fd25a5c10f2b", + "https://deno.land/std@0.132.0/node/_fs/_fs_common.ts": "6a373d1583d9ec5cc7a8ff1072d77dc999e35282a320b7477038a2b209c304d3", + "https://deno.land/std@0.132.0/node/_fs/_fs_constants.ts": "5c20b190fc6b7cfdaf12a30ba545fc787db2c7bbe87ed5b890da99578116a339", + "https://deno.land/std@0.132.0/node/_fs/_fs_copy.ts": "675eb02a2dfc20dab1186bf6ed0a33b1abae656f440bc0a3ce74f385e0052eef", + "https://deno.land/std@0.132.0/node/_fs/_fs_dir.ts": "8a05f72e32dd568b41ef45f8f55f1f54e9a306a7588475fa7014289cd12872d9", + "https://deno.land/std@0.132.0/node/_fs/_fs_dirent.ts": "649c0a794e7b8d930cdd7e6a168b404aa0448bf784e0cfbe1bd6d25b99052273", + "https://deno.land/std@0.132.0/node/_fs/_fs_exists.ts": "83e9ca6ea1ab3c6c7c3fc45f3c1287ee88839f08140ac11056441537450055bb", + "https://deno.land/std@0.132.0/node/_fs/_fs_fdatasync.ts": "bbd078fea6c62c64d898101d697aefbfbb722797a75e328a82c2a4f2e7eb963d", + "https://deno.land/std@0.132.0/node/_fs/_fs_fstat.ts": "559ff6ff094337db37b0f3108aeaecf42672795af45b206adbd90105afebf9c6", + "https://deno.land/std@0.132.0/node/_fs/_fs_fsync.ts": "590be69ce5363dd4f8867f244cfabe8df89d40f86bbbe44fd00d69411d0b798e", + "https://deno.land/std@0.132.0/node/_fs/_fs_ftruncate.ts": "8eb2a9fcf026bd9b85dc07a22bc452c48db4be05ab83f5f2b6a0549e15c1f75f", + "https://deno.land/std@0.132.0/node/_fs/_fs_futimes.ts": "c753cb9e9f129a11d1110ed43905b8966ac2a1d362ed69d5a34bb44513b00082", + "https://deno.land/std@0.132.0/node/_fs/_fs_link.ts": "3f9ccce31c2e56284fbcf2c65ec2e6fed1d9e67a9997410223486ac5092888e3", + "https://deno.land/std@0.132.0/node/_fs/_fs_lstat.ts": "571cea559d270e3b2e7fc585b0eb051899f6d0e54b1786f5e2cee3e9f71e7f27", + "https://deno.land/std@0.132.0/node/_fs/_fs_mkdir.ts": "68421a23b6d3c2d0142a6d0b3ccdd87903f9c8f98d6754aba554ab4c6b435bb8", + "https://deno.land/std@0.132.0/node/_fs/_fs_mkdtemp.ts": "86eaec96c63ea178c749fa856115a345e9797baecad22297b9ef98e3d62b90e2", + "https://deno.land/std@0.132.0/node/_fs/_fs_open.ts": "b1ca72addd2723b2a5a876378e72609fbe168adad2006f5d7b4f1868beef65ca", + "https://deno.land/std@0.132.0/node/_fs/_fs_read.ts": "3b4ef96aad20f3f29a859125ebeac8c9461574743f70c2a7ef301b8505f7d036", + "https://deno.land/std@0.132.0/node/_fs/_fs_readFile.ts": "3eae6c930e08c1279d400c0f5a008e6d96949ff3a4f5bf7d43e1b94b94ce3854", + "https://deno.land/std@0.132.0/node/_fs/_fs_readdir.ts": "a546f01387b7c49ddc1bd78d0e123a9668c710c56cffb4d9577ef46703cab463", + "https://deno.land/std@0.132.0/node/_fs/_fs_readlink.ts": "00553cd155f3bea565ffe43d7f0c10d75e895455562e1e8ea153e8f4e7ac04c7", + "https://deno.land/std@0.132.0/node/_fs/_fs_realpath.ts": "3ec236e4ad3c171203043422939973b6a948200ec4802425db41fa60c860dde9", + "https://deno.land/std@0.132.0/node/_fs/_fs_rename.ts": "3be71e8f43275c349b7abb9343b6e6764df09fabcbd2d316f8ac170ea556c645", + "https://deno.land/std@0.132.0/node/_fs/_fs_rm.ts": "a9328f99d925d7c74d31361d466ca33475aa7c6d1d6f037a49ce1ed996f0a0b4", + "https://deno.land/std@0.132.0/node/_fs/_fs_rmdir.ts": "b74007891357e709b37e6721eb355a1c4f25575995bb7c961a3c40f03ebc624c", + "https://deno.land/std@0.132.0/node/_fs/_fs_stat.ts": "bd47ce0bfc2b867392abc6ec95878ab4f6dddb94af73903d6fa1a02ba3e26af8", + "https://deno.land/std@0.132.0/node/_fs/_fs_streams.ts": "0e54bd4e41b462a701d6729ea17db01624aa48109e402fea8eecf13be324cf16", + "https://deno.land/std@0.132.0/node/_fs/_fs_symlink.ts": "0bddc37c5092f847634bd41cee0b643b9c03fc541c0e635cf35da1fcb4d0f7fa", + "https://deno.land/std@0.132.0/node/_fs/_fs_truncate.ts": "e2d380f7a81f69c4d4db30c442558ba8d8dea561e5097af41022bb5724e494e5", + "https://deno.land/std@0.132.0/node/_fs/_fs_unlink.ts": "c537ca98e507972d65f0b113a179b5f5083f0da3e6f9fae29895fd2a9660c18a", + "https://deno.land/std@0.132.0/node/_fs/_fs_utimes.ts": "c4446b7e39bf6977eca4364360501a97b96db9ea41e0cdf49abddab73481a175", + "https://deno.land/std@0.132.0/node/_fs/_fs_watch.ts": "2338de777458021d39cb9f0a5f3ea1bd9109a7ca2c2ad6ec41029df1753838f8", + "https://deno.land/std@0.132.0/node/_fs/_fs_write.mjs": "8c130b8b9522e1e4b08e687eb27939240260c115fda1e38e99c57b4f3af6481f", + "https://deno.land/std@0.132.0/node/_fs/_fs_writeFile.ts": "79d176021c8ceae0d956763a33834166ebc3f1691ed9219a21674b2374f115c3", + "https://deno.land/std@0.132.0/node/_fs/_fs_writev.mjs": "274df0a109010862c8f8b320dc7784de9bd9425fe2a6afd05f1f06f547a25cba", + "https://deno.land/std@0.132.0/node/_next_tick.ts": "64c361f6bca21df2a72dd77b84bd49d80d97a694dd3080703bc78f52146351d1", + "https://deno.land/std@0.132.0/node/_options.ts": "27f3c1269a700d330cc046cf748aa9178b8fc39d1473de625688e07cb0eb9d28", + "https://deno.land/std@0.132.0/node/_process/exiting.ts": "bc9694769139ffc596f962087155a8bfef10101d03423b9dcbc51ce6e1f88fce", + "https://deno.land/std@0.132.0/node/_process/process.ts": "84644b184053835670f79652d1ce3312c9ad079c211e6207ebefeedf159352a3", + "https://deno.land/std@0.132.0/node/_process/stdio.mjs": "971c3b086040d8521562155db13f22f9971d5c42c852b2081d4d2f0d8b6ab6bd", + "https://deno.land/std@0.132.0/node/_process/streams.mjs": "555062e177ad05f887147651fdda25fa55098475fcf142c8d162b8fe14097bbb", + "https://deno.land/std@0.132.0/node/_stream.mjs": "07f6cbabaad0382fb4b9a25e70ac3093a44022b859247f64726746e6373f1c91", + "https://deno.land/std@0.132.0/node/_util/_util_callbackify.ts": "79928ad80df3e469f7dcdb198118a7436d18a9f6c08bd7a4382332ad25a718cf", + "https://deno.land/std@0.132.0/node/_utils.ts": "c2c352e83c4c96f5ff994b1c8246bff2abcb21bfc3f1c06162cb3af1d201e615", + "https://deno.land/std@0.132.0/node/buffer.ts": "fbecbf3f237fa49bec96e97ecf56a7b92d48037b3d11219288e68943cc921600", + "https://deno.land/std@0.132.0/node/crypto.ts": "fffbc3fc3dcc16ea986d3e89eed5f70db7dfef2c18d1205a8c8fe5327ee0192d", + "https://deno.land/std@0.132.0/node/dns.ts": "ae2abd1bc8ac79543fe4d702f2aa3607101dc788b6eeba06e06436cb42ee3779", + "https://deno.land/std@0.132.0/node/events.ts": "a1d40fc0dbccc944379ef968b80ea08f9fce579e88b5057fdb64e4f0812476dd", + "https://deno.land/std@0.132.0/node/fs.ts": "21a3189c460bd37ac3f6734e040587125b7c8435c0a9da4e6c57544a3aca81c2", + "https://deno.land/std@0.132.0/node/internal/assert.mjs": "118327c8866266534b30d3a36ad978204af7336dc2db3158b8167192918d4e06", + "https://deno.land/std@0.132.0/node/internal/async_hooks.ts": "8eca5b80f58ffb259e9b3a73536dc2fe2e67d07fd24bfe2aee325a4aa435edb3", + "https://deno.land/std@0.132.0/node/internal/blob.mjs": "52080b2f40b114203df67f8a6650f9fe3c653912b8b3ef2f31f029853df4db53", + "https://deno.land/std@0.132.0/node/internal/buffer.mjs": "6662fe7fe517329453545be34cea27a24f8ccd6d09afd4f609f11ade2b6dfca7", + "https://deno.land/std@0.132.0/node/internal/crypto/keys.ts": "16ce7b15a9fc5e4e3dee8fde75dae12f3d722558d5a1a6e65a9b4f86d64a21e9", + "https://deno.land/std@0.132.0/node/internal/crypto/util.mjs": "1de55a47fdbed6721b467a77ba48fdd1550c10b5eee77bbdb602eaffee365a5e", + "https://deno.land/std@0.132.0/node/internal/dtrace.ts": "50dd0e77b0269e47ff673bdb9ad0ef0ea3a3c53ac30c1695883ce4748e04ca14", + "https://deno.land/std@0.132.0/node/internal/error_codes.ts": "ac03c4eae33de3a69d6c98e8678003207eecf75a6900eb847e3fea3c8c9e6d8f", + "https://deno.land/std@0.132.0/node/internal/errors.ts": "25f91691225b001660e6e64745ecd336fbf562cf0185e8896ff013c2d0226794", + "https://deno.land/std@0.132.0/node/internal/fs/streams.ts": "c925db185efdf56c35cde8270c07d61698b80603a90e07caf1cb4ff80abf195b", + "https://deno.land/std@0.132.0/node/internal/fs/utils.mjs": "2a571ecbd169b444f07b7193306f108fdcb4bfd9b394b33716ad05edf30e899e", + "https://deno.land/std@0.132.0/node/internal/hide_stack_frames.ts": "a91962ec84610bc7ec86022c4593cdf688156a5910c07b5bcd71994225c13a03", + "https://deno.land/std@0.132.0/node/internal/idna.ts": "a8bdd28431f06630d8aad85d3cb8fd862459107af228c8805373ad2080f1c587", + "https://deno.land/std@0.132.0/node/internal/net.ts": "1239886cd2508a68624c2dae8abf895e8aa3bb15a748955349f9ac5539032238", + "https://deno.land/std@0.132.0/node/internal/normalize_encoding.mjs": "3779ec8a7adf5d963b0224f9b85d1bc974a2ec2db0e858396b5d3c2c92138a0a", + "https://deno.land/std@0.132.0/node/internal/process/per_thread.mjs": "a42b1dcfb009ad5039144a999a35a429e76112f9322febbe353eda9d1879d936", + "https://deno.land/std@0.132.0/node/internal/querystring.ts": "c3b23674a379f696e505606ddce9c6feabe9fc497b280c56705c340f4028fe74", + "https://deno.land/std@0.132.0/node/internal/stream_base_commons.ts": "934a9e69f46f2de644956edfa9fb040af7861e326fe5325dab38ef9caf2940bc", + "https://deno.land/std@0.132.0/node/internal/streams/_utils.ts": "77fceaa766679847e4d4c3c96b2573c00a790298d90551e8e4df1d5e0fdaad3b", + "https://deno.land/std@0.132.0/node/internal/streams/add-abort-signal.mjs": "5623b83fa64d439cc4a1f09ae47ec1db29512cc03479389614d8f62a37902f5e", + "https://deno.land/std@0.132.0/node/internal/streams/buffer_list.mjs": "c6a7b29204fae025ff5e9383332acaea5d44bc7c522a407a79b8f7a6bc6c312d", + "https://deno.land/std@0.132.0/node/internal/streams/compose.mjs": "b522daab35a80ae62296012a4254fd7edfc0366080ffe63ddda4e38fe6b6803e", + "https://deno.land/std@0.132.0/node/internal/streams/destroy.mjs": "9c9bbeb172a437041d529829f433df72cf0b63ae49f3ee6080a55ffbef7572ad", + "https://deno.land/std@0.132.0/node/internal/streams/duplex.mjs": "b014087cd04f79b8a4028d8b9423b987e07bbfacf3b5df518cb752ac3657580f", + "https://deno.land/std@0.132.0/node/internal/streams/end-of-stream.mjs": "38be76eaceac231dfde643e72bc0940625446bf6d1dbd995c91c5ba9fd59b338", + "https://deno.land/std@0.132.0/node/internal/streams/from.mjs": "134255c698ed63b33199911eb8e042f8f67e9682409bb11552e6120041ed1872", + "https://deno.land/std@0.132.0/node/internal/streams/legacy.mjs": "6ea28db95d4503447473e62f0b23ff473bfe1751223c33a3c5816652e93b257a", + "https://deno.land/std@0.132.0/node/internal/streams/passthrough.mjs": "a51074193b959f3103d94de41e23a78dfcff532bdba53af9146b86340d85eded", + "https://deno.land/std@0.132.0/node/internal/streams/pipeline.mjs": "9890b121759ede869174ef70c011fde964ca94d81f2ed97b8622d7cb17b49285", + "https://deno.land/std@0.132.0/node/internal/streams/readable.mjs": "a70c41171ae25c556b52785b0c178328014bd33d8c0e4d229d4adaac7414b6ca", + "https://deno.land/std@0.132.0/node/internal/streams/state.mjs": "9ef917392a9d8005a6e038260c5fd31518d2753aea0bc9e39824c199310434cb", + "https://deno.land/std@0.132.0/node/internal/streams/transform.mjs": "3b361abad2ac78f7ccb6f305012bafdc0e983dfa4bb6ecddb4626e34a781a5f5", + "https://deno.land/std@0.132.0/node/internal/streams/utils.mjs": "06c21d0db0d51f1bf1e3225a661c3c29909be80355d268e64ee5922fc5eb6c5e", + "https://deno.land/std@0.132.0/node/internal/streams/writable.mjs": "ad4e2b176ffdf752c8e678ead3a514679a5a8d652f4acf797115dceb798744d5", + "https://deno.land/std@0.132.0/node/internal/timers.mjs": "b43e24580cec2dd50f795e4342251a79515c0db21630c25b40fdc380a78b74e7", + "https://deno.land/std@0.132.0/node/internal/url.ts": "eacef0ace4f4c5394e9818a81499f4871b2a993d1bd3b902047e44a381ef0e22", + "https://deno.land/std@0.132.0/node/internal/util.mjs": "2f0c8ff553c175ea6e4ed13d7cd7cd6b86dc093dc2f783c6c3dfc63f60a0943e", + "https://deno.land/std@0.132.0/node/internal/util/comparisons.ts": "680b55fe8bdf1613633bc469fa0440f43162c76dbe36af9aa2966310e1bb9f6e", + "https://deno.land/std@0.132.0/node/internal/util/debuglog.ts": "99e91bdf26f6c67861031f684817e1705a5bc300e81346585b396f413387edfb", + "https://deno.land/std@0.132.0/node/internal/util/inspect.mjs": "d1c2569c66a3dab45eec03208f22ad4351482527859c0011a28a6c797288a0aa", + "https://deno.land/std@0.132.0/node/internal/util/types.ts": "b2dacb8f1f5d28a51c4da5c5b75172b7fcf694073ce95ca141323657e18b0c60", + "https://deno.land/std@0.132.0/node/internal/validators.mjs": "a7e82eafb7deb85c332d5f8d9ffef052f46a42d4a121eada4a54232451acc49a", + "https://deno.land/std@0.132.0/node/internal_binding/_libuv_winerror.ts": "801e05c2742ae6cd42a5f0fd555a255a7308a65732551e962e5345f55eedc519", + "https://deno.land/std@0.132.0/node/internal_binding/_node.ts": "e4075ba8a37aef4eb5b592c8e3807c39cb49ca8653faf8e01a43421938076c1b", + "https://deno.land/std@0.132.0/node/internal_binding/_utils.ts": "1c50883b5751a9ea1b38951e62ed63bacfdc9d69ea665292edfa28e1b1c5bd94", + "https://deno.land/std@0.132.0/node/internal_binding/_winerror.ts": "8811d4be66f918c165370b619259c1f35e8c3e458b8539db64c704fbde0a7cd2", + "https://deno.land/std@0.132.0/node/internal_binding/async_wrap.ts": "f06b8a403ad871248eb064190d27bf6fefdbe948991e71a18d7077390d5773f9", + "https://deno.land/std@0.132.0/node/internal_binding/buffer.ts": "722c62b85f966e0777b2d98c021b60e75d7f2c2dabc43413ef37d60dbd13a5d9", + "https://deno.land/std@0.132.0/node/internal_binding/cares_wrap.ts": "25b7b5d56612b2985260b673021828d6511a1c83b4c1927f5732cad2f2a718af", + "https://deno.land/std@0.132.0/node/internal_binding/config.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/connection_wrap.ts": "0380444ee94d5bd7b0b09921223d16729c9762a94e80b7f51eda49c7f42e6d0a", + "https://deno.land/std@0.132.0/node/internal_binding/constants.ts": "aff06aac49eda4234bd3a2b0b8e1fbfc67824e281c532ff9960831ab503014cc", + "https://deno.land/std@0.132.0/node/internal_binding/contextify.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/credentials.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/crypto.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/errors.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs_dir.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/fs_event_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/handle_wrap.ts": "e59df84b1fb1b9823b09774b3e512d9c0029b4557400d09dd02cd7661c2c4830", + "https://deno.land/std@0.132.0/node/internal_binding/heap_utils.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/http_parser.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/icu.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/inspector.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/js_stream.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/messaging.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/mod.ts": "f68e74e8eed84eaa6b0de24f0f4c47735ed46866d7ee1c5a5e7c0667b4f0540f", + "https://deno.land/std@0.132.0/node/internal_binding/module_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/native_module.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/natives.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/node_file.ts": "c96ee0b2af319a3916de950a6c4b0d5fb00d09395c51cd239c54d95d62567aaf", + "https://deno.land/std@0.132.0/node/internal_binding/node_options.ts": "3cd5706153d28a4f5944b8b162c1c61b7b8e368a448fb1a2cff9f7957d3db360", + "https://deno.land/std@0.132.0/node/internal_binding/options.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/os.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/performance.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/pipe_wrap.ts": "00e942327f8e1c4b74a5888a82f0e16ba775cd09af804f96b6f6849b7eab1719", + "https://deno.land/std@0.132.0/node/internal_binding/process_methods.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/report.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/serdes.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/signal_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/spawn_sync.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/stream_wrap.ts": "d6e96f4b89d82ad5cc9b243c3d3880c9d85086165da54a7d85821a63491e5abf", + "https://deno.land/std@0.132.0/node/internal_binding/string_decoder.ts": "5cb1863763d1e9b458bc21d6f976f16d9c18b3b3f57eaf0ade120aee38fba227", + "https://deno.land/std@0.132.0/node/internal_binding/symbols.ts": "51cfca9bb6132d42071d4e9e6b68a340a7f274041cfcba3ad02900886e972a6c", + "https://deno.land/std@0.132.0/node/internal_binding/task_queue.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tcp_wrap.ts": "10c64d5e092a8bff99cfe05adea716e4e52f4158662a5821790953e47e2cc21c", + "https://deno.land/std@0.132.0/node/internal_binding/timers.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tls_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/trace_events.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/tty_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/types.ts": "4c26fb74ba2e45de553c15014c916df6789529a93171e450d5afb016b4c765e7", + "https://deno.land/std@0.132.0/node/internal_binding/udp_wrap.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/url.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/util.ts": "90364292e2bd598ab5d105b48ca49817b6708f2d1d9cbaf08b2b3ab5ca4c90a7", + "https://deno.land/std@0.132.0/node/internal_binding/uv.ts": "3821bc5e676d6955d68f581988c961d77dd28190aba5a9c59f16001a4deb34ba", + "https://deno.land/std@0.132.0/node/internal_binding/v8.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/worker.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/internal_binding/zlib.ts": "e292217d048a33573966b7d25352828d3282921fbcadce8735a20fb3da370cc4", + "https://deno.land/std@0.132.0/node/net.ts": "dfcb7e412abb3d5c55edde7d823b0ccb9601f7d40555ae3c862810c78b176185", + "https://deno.land/std@0.132.0/node/os.ts": "943d3294a7a00f39491148cd2097cdbf101233a421262223bb20ae702c059df5", + "https://deno.land/std@0.132.0/node/path.ts": "c65858e9cbb52dbc0dd348eefcdc41e82906c39cfa7982f2d4d805e828414b8c", + "https://deno.land/std@0.132.0/node/path/_constants.ts": "bd26f24a052b7d6b746151f4a236d29ab3c2096883bb6449c2fa499494406672", + "https://deno.land/std@0.132.0/node/path/_interface.ts": "6034ee29f6f295460ec82db1a94df9269aecbb0eceb81be72e9d843f8e8a97e6", + "https://deno.land/std@0.132.0/node/path/_util.ts": "9d4735fc05f8f1fb94406450e84e23fd201dc3fef5298b009e44cfa4e797b8f0", + "https://deno.land/std@0.132.0/node/path/common.ts": "f41a38a0719a1e85aa11c6ba3bea5e37c15dd009d705bd8873f94c833568cbc4", + "https://deno.land/std@0.132.0/node/path/glob.ts": "d6b64a24f148855a6e8057a171a2f9910c39e492e4ccec482005205b28eb4533", + "https://deno.land/std@0.132.0/node/path/mod.ts": "62e21dc6e1fe2e9742fce85de631a7b067d968544fe66954578e6d73c97369a2", + "https://deno.land/std@0.132.0/node/path/posix.ts": "9dd5fc83c4ae0e0b700bef43c88c67e276840c187a66d4d6a661440cf1fecc52", + "https://deno.land/std@0.132.0/node/path/separator.ts": "c908c9c28ebe7f1fea67daaccf84b63af90d882fe986f9fa03af9563a852723a", + "https://deno.land/std@0.132.0/node/path/win32.ts": "f869ee449b6dee69b13e2d1f8f7f1d01c7ae1e67fa573eab789429929f7a3864", + "https://deno.land/std@0.132.0/node/process.ts": "699f47f2f177556e17e2f7d0dcd3705ff5065cbdf72029e534c1540404d6f501", + "https://deno.land/std@0.132.0/node/querystring.ts": "967b8a7b00a73ebe373666deb3a7e501f164bac27bb342fde7221ecbb3522689", + "https://deno.land/std@0.132.0/node/stream.ts": "d127faa074a9e3886e4a01dcfe9f9a6a4b5641f76f6acc356e8ded7da5dc2c81", + "https://deno.land/std@0.132.0/node/stream/promises.mjs": "b263c09f2d6bd715dc514fab3f99cca84f442e2d23e87adbe76e32ea46fc87e6", + "https://deno.land/std@0.132.0/node/string_decoder.ts": "51ce85a173d2e36ac580d418bb48b804adb41732fc8bd85f7d5d27b7accbc61f", + "https://deno.land/std@0.132.0/node/timers.ts": "2d66fcd21e37acf76c3a699a97230da57cc21382c8e885b3c5377b37efd0f06c", + "https://deno.land/std@0.132.0/node/url.ts": "bc0bde2774854b6a377c4c61fa73e5a28283cbeb7f8703479f44e471219c33a8", + "https://deno.land/std@0.132.0/node/util.ts": "7fd6933b37af89a8e64d73dc6ee1732455a59e7e6d0965311fbd73cd634ea630", + "https://deno.land/std@0.132.0/node/util/types.mjs": "f9288198cacd374b41bae7e92a23179d3160f4c0eaf14e19be3a4e7057219a60", + "https://deno.land/std@0.132.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", + "https://deno.land/std@0.132.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", + "https://deno.land/std@0.132.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", + "https://deno.land/std@0.132.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", + "https://deno.land/std@0.132.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", + "https://deno.land/std@0.132.0/path/mod.ts": "4275129bb766f0e475ecc5246aa35689eeade419d72a48355203f31802640be7", + "https://deno.land/std@0.132.0/path/posix.ts": "663e4a6fe30a145f56aa41a22d95114c4c5582d8b57d2d7c9ed27ad2c47636bb", + "https://deno.land/std@0.132.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", + "https://deno.land/std@0.132.0/path/win32.ts": "e7bdf63e8d9982b4d8a01ef5689425c93310ece950e517476e22af10f41a136e", + "https://deno.land/std@0.132.0/streams/conversion.ts": "712585bfa0172a97fb68dd46e784ae8ad59d11b88079d6a4ab098ff42e697d21", + "https://deno.land/std@0.132.0/testing/_diff.ts": "9d849cd6877694152e01775b2d93f9d6b7aef7e24bfe3bfafc4d7a1ac8e9f392", + "https://deno.land/std@0.132.0/testing/asserts.ts": "b0ef969032882b1f7eb1c7571e313214baa1485f7b61cf35807b2434e254365c", + "https://deno.land/std@0.177.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", + "https://deno.land/std@0.177.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", + "https://deno.land/std@0.177.0/async/abortable.ts": "73acfb3ed7261ce0d930dbe89e43db8d34e017b063cf0eaa7d215477bf53442e", + "https://deno.land/std@0.177.0/async/deadline.ts": "c5facb0b404eede83e38bd2717ea8ab34faa2ffb20ef87fd261fcba32ba307aa", + "https://deno.land/std@0.177.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332", + "https://deno.land/std@0.177.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", + "https://deno.land/std@0.177.0/async/delay.ts": "73aa04cec034c84fc748c7be49bb15cac3dd43a57174bfdb7a4aec22c248f0dd", + "https://deno.land/std@0.177.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576", + "https://deno.land/std@0.177.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9", + "https://deno.land/std@0.177.0/async/pool.ts": "fd082bd4aaf26445909889435a5c74334c017847842ec035739b4ae637ae8260", + "https://deno.land/std@0.177.0/async/retry.ts": "5efa3ba450ac0c07a40a82e2df296287b5013755d232049efd7ea2244f15b20f", + "https://deno.land/std@0.177.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757", + "https://deno.land/std@0.177.0/bytes/index_of_needle.ts": "65c939607df609374c4415598fa4dad04a2f14c4d98cd15775216f0aaf597f24", + "https://deno.land/std@0.177.0/crypto/timing_safe_equal.ts": "8d69ab611c67fe51b6127d97fcfb4d8e7d0e1b6b4f3e0cc4ab86744c3691f965", + "https://deno.land/std@0.177.0/encoding/base64.ts": "7de04c2f8aeeb41453b09b186480be90f2ff357613b988e99fabb91d2eeceba1", + "https://deno.land/std@0.177.0/encoding/base64url.ts": "3f1178f6446834457b16bfde8b559c1cd3481727fe384d3385e4a9995dc2d851", + "https://deno.land/std@0.177.0/flags/mod.ts": "d1cdefa18472ef69858a17df5cf7c98445ed27ac10e1460183081303b0ebc270", + "https://deno.land/std@0.177.0/fs/eol.ts": "f1f2eb348a750c34500741987b21d65607f352cf7205f48f4319d417fff42842", + "https://deno.land/std@0.177.0/node/_core.ts": "9a58c0ef98ee77e9b8fcc405511d1b37a003a705eb6a9b6e95f75434d8009adc", + "https://deno.land/std@0.177.0/node/_events.mjs": "d4ba4e629abe3db9f1b14659fd5c282b7da8b2b95eaf13238eee4ebb142a2448", + "https://deno.land/std@0.177.0/node/_next_tick.ts": "9a3cf107d59b019a355d3cf32275b4c6157282e4b68ea85b46a799cb1d379305", + "https://deno.land/std@0.177.0/node/_process/exiting.ts": "6e336180aaabd1192bf99ffeb0d14b689116a3dec1dfb34a2afbacd6766e98ab", + "https://deno.land/std@0.177.0/node/_process/process.ts": "c96bb1f6253824c372f4866ee006dcefda02b7050d46759736e403f862d91051", + "https://deno.land/std@0.177.0/node/_process/stdio.mjs": "cf17727eac8da3a665851df700b5aca6a12bacc3ebbf33e63e4b919f80ba44a6", + "https://deno.land/std@0.177.0/node/_process/streams.mjs": "408777fba99580567f3ee82ee584ca79012cc550f8dacb8c5ec633b58cd0c1ca", + "https://deno.land/std@0.177.0/node/_stream.mjs": "d6e2c86c1158ac65b4c2ca4fa019d7e84374ff12e21e2175345fe68c0823efe3", + "https://deno.land/std@0.177.0/node/_utils.ts": "7fd55872a0cf9275e3c080a60e2fa6d45b8de9e956ebcde9053e72a344185884", + "https://deno.land/std@0.177.0/node/buffer.ts": "85617be2063eccaf177dbb84c7580d1e32023724ed14bd9df4e453b152a26167", + "https://deno.land/std@0.177.0/node/events.ts": "d2de352d509de11a375e2cb397d6b98f5fed4e562fc1d41be33214903a38e6b0", + "https://deno.land/std@0.177.0/node/internal/buffer.mjs": "e92303a3cc6d9aaabcd270a937ad9319825d9ba08cb332650944df4562029b27", + "https://deno.land/std@0.177.0/node/internal/crypto/_keys.ts": "8f3c3b5a141aa0331a53c205e9338655f1b3b307a08085fd6ff6dda6f7c4190b", + "https://deno.land/std@0.177.0/node/internal/crypto/constants.ts": "544d605703053218499b08214f2e25cf4310651d535b7ab995891c4b7a217693", + "https://deno.land/std@0.177.0/node/internal/error_codes.ts": "8495e33f448a484518d76fa3d41d34fc20fe03c14b30130ad8e936b0035d4b8b", + "https://deno.land/std@0.177.0/node/internal/errors.ts": "1c699b8a3cb93174f697a348c004b1c6d576b66688eac8a48ebb78e65c720aae", + "https://deno.land/std@0.177.0/node/internal/fixed_queue.ts": "62bb119afa5b5ae8fc0c7048b50502347bec82e2588017d0b250c4671d6eff8f", + "https://deno.land/std@0.177.0/node/internal/hide_stack_frames.ts": "9dd1bad0a6e62a1042ce3a51eb1b1ecee2f246907bff44835f86e8f021de679a", + "https://deno.land/std@0.177.0/node/internal/net.ts": "5538d31b595ac63d4b3e90393168bc65ace2f332c3317cffa2fd780070b2d86c", + "https://deno.land/std@0.177.0/node/internal/normalize_encoding.mjs": "fd1d9df61c44d7196432f6e8244621468715131d18cc79cd299fc78ac549f707", + "https://deno.land/std@0.177.0/node/internal/options.ts": "888f267c3fe8f18dc7b2f2fbdbe7e4a0fd3302ff3e99f5d6645601e924f3e3fb", + "https://deno.land/std@0.177.0/node/internal/primordials.mjs": "a72d86b5aa55d3d50b8e916b6a59b7cc0dc5a31da8937114b4a113ad5aa08c74", + "https://deno.land/std@0.177.0/node/internal/process/per_thread.mjs": "10142bbb13978c2f8f79778ad90f3a67a8ea6d8d2970f3dfc6bf2c6fff0162a2", + "https://deno.land/std@0.177.0/node/internal/readline/callbacks.mjs": "bdb129b140c3b21b5e08cdc3d8e43517ad818ac03f75197338d665cca1cbaed3", + "https://deno.land/std@0.177.0/node/internal/readline/utils.mjs": "c3dbf3a97c01ed14052cca3848f09e2fc24818c1822ceed57c33b9f0840f3b87", + "https://deno.land/std@0.177.0/node/internal/streams/destroy.mjs": "b665fc71178919a34ddeac8389d162a81b4bc693ff7dc2557fa41b3a91011967", + "https://deno.land/std@0.177.0/node/internal/streams/end-of-stream.mjs": "a4fb1c2e32d58dff440d4e716e2c4daaa403b3095304a028bb428575cfeed716", + "https://deno.land/std@0.177.0/node/internal/streams/utils.mjs": "f2fe2e6bdc506da24c758970890cc2a21642045b129dee618bd3827c60dd9e33", + "https://deno.land/std@0.177.0/node/internal/util.mjs": "f7fe2e1ca5e66f550ad0856b9f5ee4d666f0c071fe212ea7fc7f37cfa81f97a5", + "https://deno.land/std@0.177.0/node/internal/util/inspect.mjs": "11d7c9cab514b8e485acc3978c74b837263ff9c08ae4537fa18ad56bae633259", + "https://deno.land/std@0.177.0/node/internal/util/types.ts": "0e587b44ec5e017cf228589fc5ce9983b75beece6c39409c34170cfad49d6417", + "https://deno.land/std@0.177.0/node/internal/validators.mjs": "e02f2b02dd072a5d623970292588d541204dc82207b4c58985d933a5f4b382e6", + "https://deno.land/std@0.177.0/node/internal_binding/_libuv_winerror.ts": "30c9569603d4b97a1f1a034d88a3f74800d5ea1f12fcc3d225c9899d4e1a518b", + "https://deno.land/std@0.177.0/node/internal_binding/_listen.ts": "c6038be47116f7755c01fd98340a0d1e8e66ef874710ab59ed3f5607d50d7a25", + "https://deno.land/std@0.177.0/node/internal_binding/_node.ts": "cb2389b0eab121df99853eb6a5e3a684e4537e065fb8bf2cca0cbf219ce4e32e", + "https://deno.land/std@0.177.0/node/internal_binding/_timingSafeEqual.ts": "7d9732464d3c669ff07713868ce5d25bc974a06112edbfb5f017fc3c70c0853e", + "https://deno.land/std@0.177.0/node/internal_binding/_utils.ts": "7c58a2fbb031a204dee9583ba211cf9c67922112fe77e7f0b3226112469e9fe1", + "https://deno.land/std@0.177.0/node/internal_binding/_winerror.ts": "3e8cfdfe22e89f13d2b28529bab35155e6b1730c0221ec5a6fc7077dc037be13", + "https://deno.land/std@0.177.0/node/internal_binding/ares.ts": "bdd34c679265a6c115a8cfdde000656837a0a0dcdb0e4c258e622e136e9c31b8", + "https://deno.land/std@0.177.0/node/internal_binding/async_wrap.ts": "0dc5ae64eea2c9e57ab17887ef1573922245167ffe38e3685c28d636f487f1b7", + "https://deno.land/std@0.177.0/node/internal_binding/buffer.ts": "31729e0537921d6c730ad0afea44a7e8a0a1044d070ade8368226cb6f7390c8b", + "https://deno.land/std@0.177.0/node/internal_binding/cares_wrap.ts": "9b7247772167f8ed56acd0244a232d9d50e8d7c9cfc379f77f3d54cecc2f32ab", + "https://deno.land/std@0.177.0/node/internal_binding/config.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/connection_wrap.ts": "7dd089ea46de38e4992d0f43a09b586e4cf04878fb06863c1cb8cb2ece7da521", + "https://deno.land/std@0.177.0/node/internal_binding/constants.ts": "21ff9d1ee71d0a2086541083a7711842fc6ae25e264dbf45c73815aadce06f4c", + "https://deno.land/std@0.177.0/node/internal_binding/contextify.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/credentials.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/crypto.ts": "29e8f94f283a2e7d4229d3551369c6a40c2af9737fad948cb9be56bef6c468cd", + "https://deno.land/std@0.177.0/node/internal_binding/errors.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/fs.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/fs_dir.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/fs_event_wrap.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/handle_wrap.ts": "adf0b8063da2c54f26edd5e8ec50296a4d38e42716a70a229f14654b17a071d9", + "https://deno.land/std@0.177.0/node/internal_binding/heap_utils.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/http_parser.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/icu.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/inspector.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/js_stream.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/messaging.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/mod.ts": "9fc65f7af1d35e2d3557539a558ea9ad7a9954eefafe614ad82d94bddfe25845", + "https://deno.land/std@0.177.0/node/internal_binding/module_wrap.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/native_module.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/natives.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/node_file.ts": "21edbbc95653e45514aff252b6cae7bf127a4338cbc5f090557d258aa205d8a5", + "https://deno.land/std@0.177.0/node/internal_binding/node_options.ts": "0b5cb0bf4379a39278d7b7bb6bb2c2751baf428fe437abe5ed3e8441fae1f18b", + "https://deno.land/std@0.177.0/node/internal_binding/options.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/os.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/performance.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/pipe_wrap.ts": "30e3a63954313f9d5bbc2ac02c7f9be4b1204c493e47f6e1b9c7366994e6ea6d", + "https://deno.land/std@0.177.0/node/internal_binding/process_methods.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/report.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/serdes.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/signal_wrap.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/spawn_sync.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/stream_wrap.ts": "452bff74d1db280a0cd78c75a95bb6d163e849e06e9638c4af405d40296bd050", + "https://deno.land/std@0.177.0/node/internal_binding/string_decoder.ts": "54c3c1cbd5a9254881be58bf22637965dc69535483014dab60487e299cb95445", + "https://deno.land/std@0.177.0/node/internal_binding/symbols.ts": "4dee2f3a400d711fd57fa3430b8de1fdb011e08e260b81fef5b81cc06ed77129", + "https://deno.land/std@0.177.0/node/internal_binding/task_queue.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/tcp_wrap.ts": "d298d855e862fc9a5c94e13ad982fde99f6d8a56620a4772681b7226f5a15c91", + "https://deno.land/std@0.177.0/node/internal_binding/timers.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/tls_wrap.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/trace_events.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/tty_wrap.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/types.ts": "2187595a58d2cf0134f4db6cc2a12bf777f452f52b15b6c3aed73fa072aa5fc3", + "https://deno.land/std@0.177.0/node/internal_binding/udp_wrap.ts": "b77d7024aef1282b9fe6e1f6c8064ab8a7b9ecbae0bc08a36f2b30dcbb1d2752", + "https://deno.land/std@0.177.0/node/internal_binding/url.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/util.ts": "808ff3b92740284184ab824adfc420e75398c88c8bccf5111f0c24ac18c48f10", + "https://deno.land/std@0.177.0/node/internal_binding/uv.ts": "eb0048e30af4db407fb3f95563e30d70efd6187051c033713b0a5b768593a3a3", + "https://deno.land/std@0.177.0/node/internal_binding/v8.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/worker.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/internal_binding/zlib.ts": "37d293009d1718205bf28e878e54a9f1ca24c1c320cee2416c20dc054104c6ea", + "https://deno.land/std@0.177.0/node/os.ts": "176bec1386765464b4aac2f47c31d221a491b610dd4d87732e6f47e63153b5b9", + "https://deno.land/std@0.177.0/node/process.ts": "6608012d6d51a17a7346f36079c574b9b9f81f1b5c35436489ad089f39757466", + "https://deno.land/std@0.177.0/node/stream.ts": "09e348302af40dcc7dc58aa5e40fdff868d11d8d6b0cfb85cbb9c75b9fe450c7", + "https://deno.land/std@0.177.0/node/string_decoder.ts": "1a17e3572037c512cc5fc4b29076613e90f225474362d18da908cb7e5ccb7e88", + "https://deno.land/std@0.177.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", + "https://deno.land/std@0.177.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", + "https://deno.land/std@0.177.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", + "https://deno.land/std@0.177.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", + "https://deno.land/std@0.177.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", + "https://deno.land/std@0.177.0/path/mod.ts": "4b83694ac500d7d31b0cdafc927080a53dc0c3027eb2895790fb155082b0d232", + "https://deno.land/std@0.177.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", + "https://deno.land/std@0.177.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", + "https://deno.land/std@0.177.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", + "https://deno.land/std@0.177.0/streams/write_all.ts": "3b2e1ce44913f966348ce353d02fa5369e94115181037cd8b602510853ec3033", + "https://deno.land/std@0.194.0/_util/asserts.ts": "178dfc49a464aee693a7e285567b3d0b555dc805ff490505a8aae34f9cfb1462", + "https://deno.land/std@0.194.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", + "https://deno.land/std@0.194.0/async/abortable.ts": "fd682fa46f3b7b16b4606a5ab52a7ce309434b76f820d3221bdfb862719a15d7", + "https://deno.land/std@0.194.0/async/deadline.ts": "58f72a3cc0fcb731b2cc055ba046f4b5be3349ff6bf98f2e793c3b969354aab2", + "https://deno.land/std@0.194.0/async/debounce.ts": "adab11d04ca38d699444ac8a9d9856b4155e8dda2afd07ce78276c01ea5a4332", + "https://deno.land/std@0.194.0/async/deferred.ts": "42790112f36a75a57db4a96d33974a936deb7b04d25c6084a9fa8a49f135def8", + "https://deno.land/std@0.194.0/async/delay.ts": "73aa04cec034c84fc748c7be49bb15cac3dd43a57174bfdb7a4aec22c248f0dd", + "https://deno.land/std@0.194.0/async/mod.ts": "f04344fa21738e5ad6bea37a6bfffd57c617c2d372bb9f9dcfd118a1b622e576", + "https://deno.land/std@0.194.0/async/mux_async_iterator.ts": "70c7f2ee4e9466161350473ad61cac0b9f115cff4c552eaa7ef9d50c4cbb4cc9", + "https://deno.land/std@0.194.0/async/pool.ts": "f1b8d3df4d7fd3c73f8cbc91cc2e8b8e950910f1eab94230b443944d7584c657", + "https://deno.land/std@0.194.0/async/retry.ts": "b1ccf653954a4e52b3d9731e57d18b864e689a7462e78fb20440b11be9905080", + "https://deno.land/std@0.194.0/async/tee.ts": "47e42d35f622650b02234d43803d0383a89eb4387e1b83b5a40106d18ae36757", + "https://deno.land/std@0.194.0/collections/_utils.ts": "5114abc026ddef71207a79609b984614e66a63a4bda17d819d56b0e72c51527e", + "https://deno.land/std@0.194.0/collections/deep_merge.ts": "d4628270ec6325055b95162df05b8543961b6f5b2a56f7cc46b730cc2c7b84ab", + "https://deno.land/std@0.194.0/encoding/base64.ts": "144ae6234c1fbe5b68666c711dc15b1e9ee2aef6d42b3b4345bf9a6c91d70d0d", + "https://deno.land/std@0.194.0/flags/mod.ts": "17f444ddbee43c5487568de0c6a076c7729cfe90d96d2ffcd2b8f8adadafb6e8", + "https://deno.land/std@0.194.0/fmt/bytes.ts": "f29cf69e0791d375f9f5d94ae1f0641e5a03b975f32ddf86d70f70fdf37e7b6a", + "https://deno.land/std@0.194.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", + "https://deno.land/std@0.194.0/http/etag.ts": "6ad8abbbb1045aabf2307959a2c5565054a8bf01c9824ddee836b1ff22706a58", + "https://deno.land/std@0.194.0/http/file_server.ts": "2349d927be838b32a965ba435d0e8351932b79186fa582ea2d7168b6b53ba36e", + "https://deno.land/std@0.194.0/http/http_status.ts": "8a7bcfe3ac025199ad804075385e57f63d055b2aed539d943ccc277616d6f932", + "https://deno.land/std@0.194.0/http/server.ts": "1b23463b5b36e4eebc495417f6af47a6f7d52e3294827a1226d2a1aab23d9d20", + "https://deno.land/std@0.194.0/http/util.ts": "4cf044067febaa26d0830e356b0f3a5f76d701a60d7ff7a516fad7b192f4c3a7", + "https://deno.land/std@0.194.0/media_types/_db.ts": "7606d83e31f23ce1a7968cbaee852810c2cf477903a095696cdc62eaab7ce570", + "https://deno.land/std@0.194.0/media_types/_util.ts": "916efbd30b6148a716f110e67a4db29d6949bf4048997b754415dd7e42c52378", + "https://deno.land/std@0.194.0/media_types/content_type.ts": "ad98a5aa2d95f5965b2796072284258710a25e520952376ed432b0937ce743bc", + "https://deno.land/std@0.194.0/media_types/format_media_type.ts": "f5e1073c05526a6f5a516ac5c5587a1abd043bf1039c71cde1166aa4328c8baf", + "https://deno.land/std@0.194.0/media_types/get_charset.ts": "18b88274796fda5d353806bf409eb1d2ddb3f004eb4bd311662c4cdd8ac173db", + "https://deno.land/std@0.194.0/media_types/parse_media_type.ts": "835c4112e1357e95b4f10d7cdea5ae1801967e444f48673ff8f1cb4d32af9920", + "https://deno.land/std@0.194.0/media_types/type_by_extension.ts": "daa801eb0f11cdf199445d0f1b656cf116d47dcf9e5b85cc1e6b4469f5ee0432", + "https://deno.land/std@0.194.0/media_types/vendor/mime-db.v1.52.0.ts": "6925bbcae81ca37241e3f55908d0505724358cda3384eaea707773b2c7e99586", + "https://deno.land/std@0.194.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", + "https://deno.land/std@0.194.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", + "https://deno.land/std@0.194.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", + "https://deno.land/std@0.194.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", + "https://deno.land/std@0.194.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", + "https://deno.land/std@0.194.0/path/mod.ts": "f065032a7189404fdac3ad1a1551a9ac84751d2f25c431e101787846c86c79ef", + "https://deno.land/std@0.194.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", + "https://deno.land/std@0.194.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", + "https://deno.land/std@0.194.0/path/win32.ts": "d186344e5583bcbf8b18af416d13d82b35a317116e6460a5a3953508c3de5bba", + "https://deno.land/std@0.194.0/streams/byte_slice_stream.ts": "225d57263a34325d7c96cb3dafeb478eec0e6fd05cd0458d678752eadd132bb4", + "https://deno.land/std@0.194.0/version.ts": "04e5fc461ac4ab1f4d2d0bdc814fbbed940319e9939096f4334b1db8216f102d", + "https://deno.land/std@0.201.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.201.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.201.0/crypto/_fnv/fnv32.ts": "e4649dfdefc5c987ed53c3c25db62db771a06d9d1b9c36d2b5cf0853b8e82153", + "https://deno.land/std@0.201.0/crypto/_fnv/fnv64.ts": "bfa0e4702061fdb490a14e6bf5f9168a22fb022b307c5723499469bfefca555e", + "https://deno.land/std@0.201.0/crypto/_fnv/mod.ts": "f956a95f58910f223e420340b7404702ecd429603acd4491fa77af84f746040c", + "https://deno.land/std@0.201.0/crypto/_fnv/util.ts": "accba12bfd80a352e32a872f87df2a195e75561f1b1304a4cb4f5a4648d288f9", + "https://deno.land/std@0.201.0/crypto/_wasm/lib/deno_std_wasm_crypto.generated.mjs": "85b50eee2e511584698c04f1d84155e57452ea963106fee64987c326e9e5d25d", + "https://deno.land/std@0.201.0/crypto/_wasm/mod.ts": "973058e70052c98292b567d1c8396dffc28d6dfc6a44f0763032f6fbdf5222f5", + "https://deno.land/std@0.201.0/crypto/crypto.ts": "c1fac13f11e5150e7690a4d6f09bc09b39d0a13fc5cf129f13617656fea7379e", + "https://deno.land/std@0.201.0/crypto/keystack.ts": "877ab0f19eb7d37ad6495190d3c3e39f58e9c52e0b6a966f82fd6df67ca55f90", + "https://deno.land/std@0.201.0/crypto/mod.ts": "ae384519e85eca9aeff4e7111ed153df8f3dbda7b35b70850ed4b3e9c8cec4d5", + "https://deno.land/std@0.201.0/crypto/timing_safe_equal.ts": "f6edc08d702f660b1ab3505b74d53a9d499e34a1351f6ab70f5ce8653fee8fb7", + "https://deno.land/std@0.201.0/crypto/to_hash_string.ts": "6927c768f3e373a1be4a31555a45ccecf7bd413105455cc334ad3f908cfa986f", + "https://deno.land/std@0.201.0/encoding/base64.ts": "144ae6234c1fbe5b68666c711dc15b1e9ee2aef6d42b3b4345bf9a6c91d70d0d", + "https://deno.land/std@0.201.0/encoding/base64url.ts": "2ed4ba122b20fedf226c5d337cf22ee2024fa73a8f85d915d442af7e9ce1fae1", + "https://deno.land/std@0.201.0/encoding/hex.ts": "7894f92cd271a3df42012798310fe011ae8780d551b6538189937d1712094f14", + "https://deno.land/std@0.202.0/dotenv/mod.ts": "1da8c6d0e7f7d8a5c2b19400b763bc11739df24acec235dda7ea2cfd3d300057", + "https://deno.land/x/postgresjs@v3.3.5/mod.js": "cb68f17d6d90df318934deccdb469d740be0888e7a597a9e7eea7100ce36a252", + "https://deno.land/x/postgresjs@v3.3.5/polyfills.js": "09f3447e912e8b2abe285cdd06be849a1fa4898032ff0a633bbea892000d4ba3", + "https://deno.land/x/postgresjs@v3.3.5/src/bytes.js": "f2de43bdc8fa5dc4b169f2c70d5d8b053a3dea8f85ef011d7b27dec69e14ebb7", + "https://deno.land/x/postgresjs@v3.3.5/src/connection.js": "ee818dfbf2dee197eab624204db0d788db35ab973ad42a3ce2ccd56ba9bf9573", + "https://deno.land/x/postgresjs@v3.3.5/src/errors.js": "85cfbed9a5ab0db41ab8e97b806c881af29807dfe99bc656fdf1a18c1c13b6c6", + "https://deno.land/x/postgresjs@v3.3.5/src/index.js": "585c8c1bf46151c9dfd2d1853c628017d230f70519ec1cfe56bee9be4b7ccc07", + "https://deno.land/x/postgresjs@v3.3.5/src/large.js": "f3e770cdb7cc695f7b50687b4c6c4b7252129515486ec8def98b7582ee7c54ef", + "https://deno.land/x/postgresjs@v3.3.5/src/query.js": "600a8492b98d9dfc4cfaa5fe2d673ab49a2e2c960da732bbee21a4b8ea0f2e1c", + "https://deno.land/x/postgresjs@v3.3.5/src/queue.js": "15e6345adb6708bf3b99ad39fc2231c2fb61de5f6cba4b7a7a6be881482a4ec3", + "https://deno.land/x/postgresjs@v3.3.5/src/result.js": "001ff5e0c8d634674f483d07fbcd620a797e3101f842d6c20ca3ace936260465", + "https://deno.land/x/postgresjs@v3.3.5/src/subscribe.js": "47d7edb9e8be1d7912338371d3310fd70e819dc00d1be5dd0c2ac8ad3f18293b", + "https://deno.land/x/postgresjs@v3.3.5/src/types.js": "14088a11a1b76ca3d3b6b78086544bfe2142a4352663639449a36712b22eab56", + "https://deno.land/x/ulid@v0.3.0/mod.ts": "f7ff065b66abd485051fc68af23becef6ccc7e81f7774d7fcfd894a4b2da1984", + "https://esm.sh/linkedom@0.18.5": "10ffc41f957a8f26e18caeb14a35f4831adc3896781fb698b83d1a3f942af9ca", + "https://esm.sh/v135/boolbase@1.0.0/denonext/boolbase.mjs": "4e3bd67e9b1c5c55094eae98345d0107c6a44ef57bd3d4b9579698fa44722280", + "https://esm.sh/v135/canvas@2.11.2/denonext/canvas.mjs": "4245b1d01d91b5e807b85e40e98efe28c93634260bd8cb5ac0da71c42098a1a4", + "https://esm.sh/v135/css-select@5.1.0/denonext/css-select.mjs": "7f4fb680eff2223a68fb5a1efa12e905077d7e6c44ae66c01fc437fe7af58f8b", + "https://esm.sh/v135/css-what@6.1.0/denonext/css-what.mjs": "283d02df6fef73d3223b55324b559b363dd0e4c008ea1efbcf9f14b8f2642202", + "https://esm.sh/v135/cssom@0.5.0/denonext/cssom.mjs": "c4216df78cba2c7be94853258b6b28c681e60ff89d4aeb3149b0ac91302be428", + "https://esm.sh/v135/dom-serializer@2.0.0/denonext/dom-serializer.mjs": "700001f5fdb9f72fc7d1f169be700489ddd7f19489b58b6e8691ff1fca9000fe", + "https://esm.sh/v135/domelementtype@2.3.0/denonext/domelementtype.mjs": "371936c356d5ac797f2ce3a66b98dfc73e6fff0e095b2858b85668e6ad7d10e0", + "https://esm.sh/v135/domhandler@5.0.3/denonext/domhandler.mjs": "8c6e56c4596bbe7e9fd9d615f8fcdec7f11075f217bdc966a02ebe89c01b9f6f", + "https://esm.sh/v135/domutils@3.1.0/denonext/domutils.mjs": "2a86554cc5f543a068bbf6ea6ed0647f4ad4c3ccb555f0da9fae09180cd7b611", + "https://esm.sh/v135/entities@4.5.0/denonext/entities.mjs": "a9e8f9c22022c34755d1189030ac30c68545ccf8532fa32654c50fe9d90a13a1", + "https://esm.sh/v135/entities@4.5.0/denonext/lib/decode.js": "7fea6d8bd725edbbf7ea05031d2ea1bbbc1166dc11e3345d541198dd2dc16f1e", + "https://esm.sh/v135/entities@4.5.0/denonext/lib/escape.js": "7ebdc622bf3618bab25db40da4a49e2b9d03f044745f125f0bc3359f2d060def", + "https://esm.sh/v135/htmlparser2@9.1.0/denonext/htmlparser2.mjs": "e5186144ca1dd8829bda984fd778500356f241597c67e2c674213c684168e985", + "https://esm.sh/v135/linkedom@0.18.5/denonext/linkedom.mjs": "687bbbe4150cab7ee44e3781ea3f122cf60be57d679a34bf9de44f87ded97f60", + "https://esm.sh/v135/nth-check@2.1.1/denonext/nth-check.mjs": "638b4f5a22236cd05c7d1d43e5c6ea719695c4a8bc7beccdf8d97a434bea96dc", + "https://esm.sh/v135/uhyphen@0.2.0/denonext/uhyphen.mjs": "53c707ad31488ef2f131e2ac9257d91b7b590a777e60288a34b3a04f1e65ad5a" + }, + "workspace": { + "dependencies": [ + "npm:crypto-js@4.2.0", + "npm:parse5@7.1.2", + "npm:xss@1.0.14" + ], + "packageJson": { + "dependencies": [ + "npm:crypto-js@^4.2.0" + ] + } + } +} diff --git a/docs/assets/book-toc.png b/docs/assets/book-toc.png new file mode 100644 index 0000000..704f32e Binary files /dev/null and b/docs/assets/book-toc.png differ diff --git a/docs/assets/html-style.png b/docs/assets/html-style.png new file mode 100644 index 0000000..511c48e Binary files /dev/null and b/docs/assets/html-style.png differ diff --git a/docs/principle.md b/docs/principle.md new file mode 100644 index 0000000..60a82d0 --- /dev/null +++ b/docs/principle.md @@ -0,0 +1,104 @@ +# 实现原理 + +微信读书里面的书大概分2类: epub 和 txt,另外还有一种 pdf 格式的比较特殊,后面单独说明。 + +每本书都是按照章节进行阅读和下载的,比如下面这本书的目录: + +![目录结构](assets/book-toc.png) + +每一行都是一个章节,总的章节数据可以通过下面这个接口获取: +```http request +POST /web/book/publicchapterInfos +Host: https://weread.qq.com +Content-Type: application/json;charset=UTF-8 + +{"bookIds":["3300076204"]} +``` +返回的 json 里面,`data.updated`字段即章节数组,比如第一章: +```json +{ + "chapterUid": 1, + "chapterIdx": 1, + "updateTime": 1698825146, + "tar": "https://res.weread.qq.com/wrco/tar_CB_3300076204_1", + "title": "封面", + "wordCount": 2, + "price": 0, + "isMPChapter": 0, + "level": 1, + "files": [ + "Text/coverpage.xhtml" + ] +} +``` + +> 注意里面有一个`tar`字段,是指向一个文件,打包了这一章里面的所有图片资源。 +> 这个`tar`包文件的下载,是需要登录信息的。 + +第一章通常是封面,但是一般不显示在 web 版的目录里面,这一章的图片资源通常只有一张,也就是封面图。 + +有的章节比较特殊,比如下面这个: +```json +{ + "chapterUid": 5, + "chapterIdx": 5, + "updateTime": 1698825146, + "tar": "", + "title": "第一部分 全能自恋及其变化", + "wordCount": 761, + "price": 0, + "isMPChapter": 0, + "level": 1, + "files": [ + "Text/chaper003.xhtml" + ], + "anchors": [ + { + "title": "引言 如何看全能感", + "anchor": "sigil_toc_id_1", + "level": 2 + } + ] +} +``` +内部有一个`anchors`数组,这个数组里面的部分也属于目录的一部分,但是却没有单独的`chapterUid`等信息,也就是说,同一章节里面包含了多条目录数据。 + +有了目录数据,我们就可以用下载接口下载章节数据了。 + +前面已经说了,不同格式的书需要用不同接口进行下载,其中`epub`格式的书下载接口如下: +``` +https://weread.qq.com/web/book/chapter/e_0 (html 片段) +https://weread.qq.com/web/book/chapter/e_1 (html 片段) +https://weread.qq.com/web/book/chapter/e_2 (style) +https://weread.qq.com/web/book/chapter/e_3 (html 片段) +``` +`txt`格式的书的下载接口如下: +``` +https://weread.qq.com/web/book/chapter/t_0 (text 片段) +https://weread.qq.com/web/book/chapter/t_1 (text 片段) +``` + +每一本`epub`格式的书的章节都分成了 4 部分,其中 0、1、3 是`html`片段,下载完之后需要拼起来才是完整的`html`数据,2 是`style`。 +`txt`格式的书分2个部分,都是`html`数据,没有样式。 + +每一章的下载参数如下: +```json5 +{ + "b": "bb432f60813ab8444g014d61", // bookId 的编码值 + "c": "ecc32f3013eccbc87e4b62e", // chapterUid 的编码值 + "r": 97344, // 随机数 + "st": 0, // 0表示html,1表示style + "ct": 1699415043, // 当前时间戳 + "ps": "57d32ab07a2119e6g017bd2", // 打开这本书时服务端时间戳的编码值 + "pc": "a8f324b07a2119e7g017cec", // 打开这本书时客户端时间戳的编码值 + "sc": 0, + "prevChapter": false, // 是否是点击顶部的"上一章"按钮进行获取的 + "s": "d97170d6" // 以上这些数据的签名 +} +``` + +下载的数据是加密的,经过解密拼接之后,就是这个章节的 html 文档和 style 样式了,如下图所示: +![解密后的html和style](assets/html-style.png) + +通过遍历章节列表,把所有的章节数据都下载下来,我们把 style 部分内嵌到 html 中,这样每一个章节都是一个单独的 html 文档,然后我们再把 html 文档合并成一个 html 文档,这就是下载 html 格式的原理。 +我们把 html 格式里面的图片单独下载下来,然后替换图片的 src 属性,并把所有内容打包到 epub 里面,这就是下载 epub 格式的原理。 diff --git a/examples/jdread/index.ts b/examples/jdread/index.ts new file mode 100644 index 0000000..cde6480 --- /dev/null +++ b/examples/jdread/index.ts @@ -0,0 +1,229 @@ +import {md5} from "../../src/utils/encode.ts"; +import {cryptoJS} from "../../src/deps.ts" +import {sleep} from "../../src/utils/index.ts"; + +const crypto = cryptoJS.default + +const referer = 'https://m-tob.jd.com/readertob/reader?ebookId=30846299&team_id=371_371&return_url=https%3A%2F%2Fm-tob.jd.com%2Fuser_login' +const ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36' + +const token = 'jdd03BVOWWZRSBIDBXC2RP66GXRQPKWIAPS3OFJUVD76A7QRUBNNDYMK6FVHHIVRAZMSHIRWR7KGYJAGVJV74AIJLZI2U2AAAAAMLOBZC35QAAAAADC2SHN66SLFNIEX' +const h5st = '20231027172551748;1679513456279505;7e98a;tk03wb6be1c3e18nvGhEEkHlYcrv20e6eUkWpQBk9g5BkoLukdj2-tgK_oA5EapHdEDCm8IUZeCnvlPV4XYCKoqIFr4O;84a242549c846d8483b17c728ff1ff914b1f09b5b63343d935f52208997ccda6;3.1;1698398751748;76dcb804add1320a126905907ff5ddbfe6354a3d8eb09a6164035064d003aab8d0dd2ba3365155923e199a44208113eec7f7a35fb6a2a0bce4a65fb65e5bc08161cb418a3c22b4d73e5fd15e76d3a125288ef01c5635c277272c32eb8d4ac304' + +function t() { + return (65536 * (1 + Math.random()) | 0).toString(16).substring(1) +} + + +class EncUtil { + app: string + time: number + origin = 'https://m-tob.jd.com' + + constructor() { + this.app = 'tob-web' + this.time = new Date().getTime() + } + + getUuid() { + return 'h5' + t() + t() + t() + t() + t() + t() + t() + t() + } + + sortString(data: Record) { + const sortedKeys = Object.keys(data).sort() + let result = sortedKeys[0] + "=" + data[sortedKeys[0]] + for (let i = 1; i < sortedKeys.length; i++) { + result = result + "&" + sortedKeys[i] + "=" + data[sortedKeys[i]] + } + return result + } + + addSign(url: string, payload: Record, sign: string) { + const keys = Object.keys(payload) + let result = url.split("?")[0] + "?" + keys[0] + "=" + payload[keys[0]] + for (let i = 1; i < keys.length; i++) { + result = result + "&" + keys[i] + "=" + payload[keys[i]] + } + return result + "&sign=" + sign + } + + getKey(timestamp: number) { + return timestamp.toString() + this.app + } + + enData(url: string) { + const key = this.getKey(this.time) + let n = this.encrypt(url.split("?")[1], key, this.time) + n = n.replace(/\+/g, "-").replace(/\//g, "_") + url = url.split("?")[0] + "?enc=1&app=" + this.app + "&tm=" + this.time + "¶ms=" + encodeURIComponent(n) + return url + } + + encrypt(data: string, key: string, time: number) { + return time % 2 == 0 ? this.AESEncrypt(data, key) : this.DESEncrypt(data, key) + } + + AESEncrypt(data: string, key: string) { + const _data = crypto.enc.Utf8.parse(data) + const _key = crypto.MD5(crypto.enc.Utf8.parse(key)) + + return crypto.AES.encrypt(_data, _key, { + mode: crypto.mode.ECB, + padding: crypto.pad.Pkcs7 + }).toString() + } + + DESEncrypt(data: string, key: string) { + const _data = crypto.enc.Utf8.parse(data) + const _key = crypto.MD5(crypto.enc.Utf8.parse(key)) + + return crypto.DES.encrypt(_data, _key, { + mode: crypto.mode.ECB, + padding: crypto.pad.Pkcs7 + }).toString() + } + + decrypt(data: string, key: string, time: number) { + return time % 2 == 0 ? this.AESDecrypt(data, key) : this.DESDecrypt(data, key) + } + + AESDecrypt(data: string, key: string) { + const _data = crypto.MD5(crypto.enc.Utf8.parse(key)) + const _key = crypto.AES.decrypt(data, _data, { + mode: crypto.mode.ECB, + padding: crypto.pad.Pkcs7 + }) + + return crypto.enc.Utf8.stringify(_key).toString() + } + + DESDecrypt(data: string, key: string) { + const n = crypto.MD5(crypto.enc.Utf8.parse(key)) + const r = crypto.DES.decrypt(data, n, { + mode: crypto.mode.ECB, + padding: crypto.pad.Pkcs7 + }) + + return crypto.enc.Utf8.stringify(r).toString() + } + + getUrl(bookId: string | number) { + const requestUrl = '/jdread/api/download/chapter/' + bookId + const payload = { + app: this.app, + tm: this.time, + team_id: '371_371', + uuid: this.getUuid(), + client: 'pc', + os: 'web', + } + const sign = md5(md5(payload.app + payload.tm + payload.uuid) + requestUrl + this.sortString(payload)) + + return this.enData(this.addSign(requestUrl, payload, sign)) + } + + async request(url: string) { + if (!url.startsWith('http')) { + url = this.origin + url + } + + return await fetch(url, { + headers: { + Referer: referer, + 'User-Agent': ua, + } + }).then(resp => resp.text()) + } + + /** + * 获取章节目录 + * @param bookId + */ + async fetchToc(bookId: string | number) { + const t = new Date().getTime() + const body = { + app: 'tob-web', + tm: t, + os: 'web', + client: 'pc', + team_id: '371_371', + uuid: this.getUuid(), + ebookId: bookId.toString(), + $ebookId: bookId.toString(), + } + const payload = { + appid: 'jdread-m', + t: t.toString(), + client: 'web', + clientVersion: '1.0.0', + body: JSON.stringify(body), + 'x-api-eid-token': token, + h5st: h5st, + } + const data = new URLSearchParams(payload).toString() + + return await fetch('https://api.m.jd.com/api?functionId=jdread_api_ebook_catalog_v2_ebookId', { + method: 'post', + body: data, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + } + }).then(resp => resp.json()) + } + + /** + * 下载章节内容 + * @param bookId + * @param chapterIdx + */ + async fetchChapterContent(bookId: string | number, chapterIdx: string | number) { + let url = this.getUrl(bookId) + // 加上章节编号 + url += '&enc_pin=&indexes=' + chapterIdx + const resp = await this.request(url) + + const data = this.decrypt(resp, this.getKey(this.time), this.time) + try { + const respJson = JSON.parse(data) + if (respJson['result_code'] === 0) { + // 下载成功 + return respJson['data']['chapter'][0]['content'] + } + } catch (e) { + throw e + } + } +} + + +async function downloadBook(bookId: string | number) { + const encUtil = new EncUtil() + const resp = await encUtil.fetchToc(bookId) + if (resp['result_code'] === 0) { + try { + // 确保目录存在 + const path = `./examples/jdread/${bookId}` + Deno.mkdirSync(path, {recursive: true}) + } catch (_) { + // no op + console.log(_) + } + + for (const chapter of resp.data.chapter_info) { + const {chapter_name, chapter_index, is_try, is_buy} = chapter + if (!is_try && !is_buy) { + console.warn(`章节: 《${chapter_name}》 无法阅读,跳过下载`) + continue + } + console.log(`开始下载: 《${chapter_name}》`) + const data = await encUtil.fetchChapterContent(bookId, chapter_index) + Deno.writeTextFileSync(`./examples/jdread/${bookId}/${chapter_index}.html`, data) + + await sleep(1000) + } + } else { + console.warn(`获取目录(${bookId})失败: `, resp) + } +} + +await downloadBook('30846310') diff --git a/extension/content.js b/extension/content.js new file mode 100644 index 0000000..a422803 --- /dev/null +++ b/extension/content.js @@ -0,0 +1,14 @@ +document.addEventListener('DOMContentLoaded', () => { + const btnEl = document.querySelector('button') + + if (btnEl) { + btnEl.addEventListener('click', async () => { + await downloadImage('https://res.weread.qq.com/wrepub/CB_43168703_cover.jpg') + }) + } +}) + +async function downloadImage(url) { + const resp = await chrome.runtime.sendMessage({ url: url }) + console.log('下载结果:', resp) +} diff --git a/extension/manifest.json b/extension/manifest.json new file mode 100644 index 0000000..010d1fa --- /dev/null +++ b/extension/manifest.json @@ -0,0 +1,14 @@ +{ + "manifest_version": 3, + "name": "Hello Extensions", + "description": "Base Level Extension", + "version": "1.0", + "action": { + "default_popup": "popup.html" + }, + "background": { + "service_worker": "sw.js", + "type": "module" + }, + "host_permissions": ["*://*/*"] +} diff --git a/extension/popup.html b/extension/popup.html new file mode 100644 index 0000000..045ac2d --- /dev/null +++ b/extension/popup.html @@ -0,0 +1,12 @@ + + + + + Hello Extension + + + +

Hello Extensions

+ + + diff --git a/extension/sw.js b/extension/sw.js new file mode 100644 index 0000000..fb0de9d --- /dev/null +++ b/extension/sw.js @@ -0,0 +1,27 @@ +chrome.runtime.onMessage.addListener(({url}, sender, sendResponse) => { + download(url, sendResponse) + return true +}) + +async function download(url, sendResponse) { + console.log('开始下载:', url) + const resp = await fetch(url, { + method: 'GET', + cache: 'no-store', + redirect: 'follow', + }) + const blob = await resp.blob() + const base64 = await convertBlobToBase64(blob) + sendResponse(base64) +} + +function convertBlobToBase64(blob) { + return new Promise(resolve => { + const reader = new FileReader() + reader.readAsDataURL(blob) + reader.onloadend = () => { + const base64data = reader.result + resolve(base64data) + } + }) +} diff --git a/options.ini b/options.ini new file mode 100644 index 0000000..7192bbe --- /dev/null +++ b/options.ini @@ -0,0 +1,15 @@ +[System] +path = C:\Users\wesly1/Videos +firststartup = True +usegpuaccel = True +deleteoriginalmedia = False +torecyclebin = True + +[Convert] +outputfolder = C:\Users\wesly1/Videos/Output +outputformat = Mp4 +overwriteoutputfile = False +maxtaskcount = 4 +autoloadsubtitle = True +embedcover = True + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..03b0d9d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "weread", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "crypto-js": "^4.2.0" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + } + }, + "dependencies": { + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + } + } +} diff --git a/package.json b/package.json index a3be980..e544b4a 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,13 @@ { - "name": "weread", - "version": "1.0.1", - "repository": "git@github.com:champkeh/weread.git", - "author": "champkeh ", - "license": "MIT", "scripts": { - "dev": "deno run -A --unstable src/server.ts", - "style": "deno run -A test/style.ts", - "html": "deno run -A test/html.ts", - "clean": "deno run -A --unstable scripts/clean.ts", - "read": "deno run -A --unstable scripts/read.ts", + "dev": "deno run -A --unstable src/server.ts local", + "serve": "deno run -A --unstable src/server.ts", "check:type": "deno check --unstable src/**/*.ts", "lint": "deno lint src/**/*.ts", "fmt": "deno fmt src/**/*.ts", - "logs": "deno run -A scripts/logs.ts", - "compile:pre-push": "deno compile -A --output .husky/pre-push scripts/pre-push.ts", - "prepare": "husky install", - "webnovel": "deno run -A --unstable src/apis/webnovel/chapter.ts" + "example:jdread": "deno run -A --unstable examples/jdread/index.ts" }, - "devDependencies": { - "husky": "^8.0.0" + "dependencies": { + "crypto-js": "^4.2.0" } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 84e95de..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,15 +0,0 @@ -lockfileVersion: 5.4 - -specifiers: - husky: ^8.0.0 - -devDependencies: - husky: 8.0.3 - -packages: - - /husky/8.0.3: - resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} - engines: {node: '>=14'} - hasBin: true - dev: true diff --git a/scripts/clean.ts b/scripts/clean.ts new file mode 100644 index 0000000..59e2006 --- /dev/null +++ b/scripts/clean.ts @@ -0,0 +1,42 @@ +import {dotenv} from "../src/deps.ts" + + +const env = await dotenv.load() +Deno.env.set('DENO_KV_ACCESS_TOKEN', env["DENO_KV_ACCESS_TOKEN"]) + +const kv = await Deno.openKv( + "https://api.deno.com/databases/df3a6e8b-c7c3-4705-a66a-d69aa58e117e/connect", +); + + +/** + * 清理无效用户 Credentials 数据 + */ +async function removeUnusedCredentials() { + const validTokens = [] + for await (const res of kv.list({prefix: ["vid"]})) { + validTokens.push(res.value) + } + + for await (const res of kv.list({prefix: ["credentials"]})) { + if (!validTokens.includes(res.key[1])) { + console.log('delete', res.key) + await kv.delete(res.key); + } + } +} + +/** + * 清理下载凭证 (有时候有些数据没有自动被清理掉) + */ +async function removeDownload() { + for await (const entry of kv.list({prefix: ["download"]})) { + if (typeof entry.key[1] !== 'number') { + await kv.delete(entry.key) + } + } +} + + +await removeUnusedCredentials() +// await removeDownload() diff --git a/scripts/logs.ts b/scripts/logs.ts new file mode 100644 index 0000000..86f94c6 --- /dev/null +++ b/scripts/logs.ts @@ -0,0 +1,35 @@ +// deno-lint-ignore-file no-explicit-any +import {get} from "../src/utils/request.ts"; +import {load} from "https://deno.land/std@0.202.0/dotenv/mod.ts"; + + +const env = await load() +const projectID = env['PROJECT_ID'] +const cookie = env['DENO_DEPLOY_COOKIE'] + + +/** + * 获取日志 + * @param nextCursor + * @param since + */ +export async function getLogs(nextCursor: Record | null = null, since = "2023-09-26T05:23:24.929Z") { + const payload: Record = { + since: since, + levels: [], + regions: [], + } + if (nextCursor) { + payload.cursor = nextCursor + } + const resp = await get(`https://dash.deno.com/_api/projects/${projectID}/deployments/latest/query_logs`, { + params: JSON.stringify(payload), + }, {cookie}) + + const contentType = resp.headers.get("Content-Type") || "text/html" + if (contentType.includes("text/html")) { + return resp.text() + } else if (contentType.includes("json")) { + return resp.json() + } +} diff --git a/scripts/pre-push.ts b/scripts/pre-push.ts new file mode 100644 index 0000000..6c2a5b4 --- /dev/null +++ b/scripts/pre-push.ts @@ -0,0 +1,47 @@ +// deno-lint-ignore-file no-explicit-any +import {getLogs} from "./logs.ts"; +import {insertLogRecords} from "../src/database/log.ts"; +import {md5} from "../src/utils/encode.ts"; + +// 这里可以在 pre-push 钩子中拉取日志,并上传到 supabase 上面 + +let count = 0 + +async function tick(cursor: Record | null = null) { + const resp = await getLogs(cursor) + if (typeof resp === 'string') { + console.log(resp) + console.warn('需要重新登录') + Deno.exit(-1) + } + + const logs = resp.logs + .map((_: any) => ({ + subhoster_id: _.subhosterId, + deployment_id: _.deploymentId, + isolate_id: _.isolateId, + region: _.region, + level: _.level, + timestamp: _.timestamp, + message: _.message, + hash: md5(_.timestamp + _.message), // 计算一个 Hash 用于作为唯一键 + })) + // 只备份 warning/error 级别的日志 + .filter((log: any) => ['info', 'warning', 'error'].includes(log.level)) + // console.log(logs) + await insertLogRecords(logs) + count += logs.length + console.log(`upload ${count} log records`) + + if (resp.nextCursor) { + // 下一轮 + await tick(resp.nextCursor) + } +} + +console.log(`开始备份日志..`) + +await tick() + +console.log('日志备份完成\n') +Deno.exit(0) diff --git a/src/apis/app/book.ts b/src/apis/app/book.ts index 079ca88..379d0e2 100644 --- a/src/apis/app/book.ts +++ b/src/apis/app/book.ts @@ -1,5 +1,6 @@ import {postJSON, get} from "../../utils/request.ts"; import {UserAgentForApp} from "../../config.ts"; +import {checkErrCode} from "../err-code.ts"; enum ReadingStatus { /** @@ -37,6 +38,7 @@ export async function book_markstatus(bookId: string, status: ReadingStatus, isC "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } @@ -61,5 +63,26 @@ export async function book_chapter_download(vid: number | string, skey: string) v: '7.4.2.23' }) console.log(resp.headers) + await checkErrCode(resp, vid) return resp.text() } + +/** + * 获取书籍章节 + * @param bookId + * @param vid + * @param skey + */ +export async function book_chapterInfos(bookId: string, vid: number | string, skey: string) { + const resp = await postJSON("https://i.weread.qq.com/book/chapterInfos", { + bookIds: [bookId], + synckeys: [0], + }, { + vid: vid.toString(), + skey: skey, + "User-Agent": UserAgentForApp, + v: '7.4.2.23' + }) + await checkErrCode(resp, vid) + return resp.json() +} diff --git a/src/apis/app/friend.ts b/src/apis/app/friend.ts index ba9ff06..8ba24a0 100644 --- a/src/apis/app/friend.ts +++ b/src/apis/app/friend.ts @@ -1,5 +1,6 @@ import {get} from "../../utils/request.ts"; import {UserAgentForApp} from "../../config.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 查询阅读排名 @@ -16,5 +17,6 @@ export async function friend_ranking(vid: string | number, skey: string) { skey: skey, "User-Agent": UserAgentForApp, }) + await checkErrCode(resp, vid) return resp.json() } diff --git a/src/apis/app/readdata.ts b/src/apis/app/readdata.ts index 9ee2021..0a6ec0c 100644 --- a/src/apis/app/readdata.ts +++ b/src/apis/app/readdata.ts @@ -1,5 +1,6 @@ import {get} from "../../utils/request.ts"; import {UserAgentForApp} from "../../config.ts"; +import {checkErrCode} from "../err-code.ts"; type ReadDataMode = "weekly" | "monthly" | "anually" | "overall" @@ -14,6 +15,7 @@ export async function readdata_detail(vid: number | string, skey: string, mode = "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } @@ -26,5 +28,6 @@ export async function challenge_detail(vid: number | string, skey: string) { "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } diff --git a/src/apis/app/user.ts b/src/apis/app/user.ts index ad6e3ea..3233c68 100644 --- a/src/apis/app/user.ts +++ b/src/apis/app/user.ts @@ -1,5 +1,6 @@ import {get, postJSON} from "../../utils/request.ts"; import {UserAgentForApp} from "../../config.ts"; +import {checkErrCode} from "../err-code.ts"; /** * @example 返回示例 @@ -13,6 +14,7 @@ export async function login(refreshToken: string) { }, { "User-Agent": UserAgentForApp, }) + await checkErrCode(resp, refreshToken) return resp.json() } @@ -64,6 +66,7 @@ export async function profile(vid: number | string, skey: string) { "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } @@ -77,6 +80,7 @@ export async function device_sessionlist(deviceId: string, vid: number | string, "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } @@ -90,6 +94,7 @@ export async function device_sessionremove(currentDeviceId: string, removeDevice "User-Agent": UserAgentForApp, v: '7.4.2.23' }) + await checkErrCode(resp, vid) return resp.json() } @@ -99,5 +104,6 @@ export async function phoneCheck(phone: string) { }, { }) + await checkErrCode(resp, phone) return resp.json() } diff --git a/src/apis/app/weekly.ts b/src/apis/app/weekly.ts index 878857d..e7a31fd 100644 --- a/src/apis/app/weekly.ts +++ b/src/apis/app/weekly.ts @@ -2,6 +2,7 @@ import {postJSON} from "../../utils/request.ts"; import {UserAgentForApp} from "../../config.ts"; +import {checkErrCode} from "../err-code.ts"; const platform = "weread_wx-2001-iap-2001-iphone" @@ -21,6 +22,7 @@ export async function queryAllAwards(vid: string | number, skey: string) { skey: skey, "User-Agent": UserAgentForApp, }) + await checkErrCode(resp, vid) return resp.json() } @@ -62,6 +64,7 @@ async function exchangeAward(id: number | string, vid: string | number, skey: st skey: skey, "User-Agent": UserAgentForApp, }) + await checkErrCode(resp, vid) return resp.json() } diff --git a/src/apis/err-code.ts b/src/apis/err-code.ts index 76d0a01..bcadab3 100644 --- a/src/apis/err-code.ts +++ b/src/apis/err-code.ts @@ -1,26 +1,93 @@ +import { ErrLogRecord, insertErrLogRecords } from "../database/errlog.ts"; +import { now } from "../utils/index.ts"; + export enum ErrCode { - /** - * 用户不存在 - */ - UserNotExist = -2010, - - /** - * 会话超时 - */ - SessionTimeout = -2012, - - /** - * 鉴权失败 - */ - AuthenticationFailed = -2013, - - /** - * 微信授权已过期,需重新登录 - */ - AuthenticationTimeout = -12013, - - /** - * 无权限下载 - */ - NoPermissionDownload = -2038, + /** + * 用户不存在 + */ + UserNotExist = -2010, + + /** + * 会话超时 + */ + SessionTimeout = -2012, + + /** + * 鉴权失败 + */ + AuthenticationFailed = -2013, + + /** + * 请求频率过高 + */ + HighFrequency = -2014, + + /** + * 微信授权已过期,需重新登录 + */ + AuthenticationTimeout = -12013, + + /** + * 无权限下载 + */ + NoPermissionDownload = -2038, +} + +/** + * 检查错误码 + * @param resp + * @param user + */ +export async function checkErrCode(resp: Response, user: number | string) { + const clonedResp = resp.clone(); + try { + const contentType = clonedResp.headers.get("Content-Type") || "text/html"; + if (contentType.includes("json")) { + const respData = await clonedResp.json(); + const errCode = respData.errCode || respData.errcode; + const errMsg = respData.errMsg || respData.errmsg; + + // 针对特殊错误进行的特殊处理 + switch (errCode) { + // 用户不存在 + case ErrCode.UserNotExist: + break; + // 会话超时 + case ErrCode.SessionTimeout: + break; + // 鉴权失败 + case ErrCode.AuthenticationFailed: + break; + // 请求频率过高 + case ErrCode.HighFrequency: + break; + // 授权超时,需重新登录 + case ErrCode.AuthenticationTimeout: + break; + // 无权限下载 + case ErrCode.NoPermissionDownload: + break; + default: + break; + } + + const errlog: ErrLogRecord = { + user_info: user.toString(), + err_code: errCode, + err_msg: errMsg, + timestamp: now(), + }; + + if (errCode) { + // 可能没有配置,所以包在 try catch 里面执行 + try { + await insertErrLogRecords([errlog]); + } catch (e) { + console.warn(e.message); + } + } + } + } catch (_) { + // no op + } } diff --git a/src/apis/web/book.ts b/src/apis/web/book.ts index eaada82..1d8c9a4 100644 --- a/src/apis/web/book.ts +++ b/src/apis/web/book.ts @@ -4,8 +4,11 @@ import {UserAgentForWeb} from "../../config.ts"; import {chk, dH, dS, dT} from "../../utils/decrypt.ts"; import styleParser from "../../utils/style.ts"; import htmlParser from "../../utils/html.ts"; -import {processHtmls, processStyles} from "../../utils/process.ts"; +import {mergeSpanInHtml, processHtmls, processStyles} from "../../utils/process.ts"; import {sha256} from "../../utils/encode.ts"; +import {chapterTitleText, M278, showChapterTitle} from "./utils.ts"; +import type {BookInfo, ChapterInfo} from "./utils.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 获取图书详情 @@ -13,12 +16,13 @@ import {sha256} from "../../utils/encode.ts"; * @param cookie */ export async function web_book_info(bookId: string, cookie = "") { - const resp = await get("https://weread.qq.com/web/book/info", { - bookId: bookId, - }, { - cookie: cookie, - }); - return resp.json(); + const resp = await get("https://weread.qq.com/web/book/info", { + bookId: bookId, + }, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json(); } /** @@ -26,21 +30,23 @@ export async function web_book_info(bookId: string, cookie = "") { * 不需要登录 */ export async function web_book_publicinfos(bookIds: string[]) { - const resp = await postJSON("https://weread.qq.com/web/book/publicinfos", { - bookIds, - }) - try { - return resp.json() - } catch (e) { - console.log(e) - console.log(resp) - throw e - } + const resp = await postJSON("https://weread.qq.com/web/book/publicinfos", { + bookIds, + }) + await checkErrCode(resp, "anonymous") + try { + return resp.json() + } catch (e) { + console.log(e) + console.log(resp) + throw e + } } export async function web_book_search(cookie = "") { - const resp = await get("https://weread.qq.com/web/book/search", {}, {cookie}) - return resp.json() + const resp = await get("https://weread.qq.com/web/book/search", {}, {cookie}) + await checkErrCode(resp, cookie) + return resp.json() } /** @@ -49,12 +55,13 @@ export async function web_book_search(cookie = "") { * @param cookie */ export async function web_book_chapterInfos(bookIds: string[], cookie = "") { - const resp = await postJSON("https://weread.qq.com/web/book/chapterInfos", { - bookIds, - }, { - cookie: cookie, - }); - return resp.json(); + const resp = await postJSON("https://weread.qq.com/web/book/chapterInfos", { + bookIds, + }, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json(); } /** @@ -63,12 +70,13 @@ export async function web_book_chapterInfos(bookIds: string[], cookie = "") { * @param cookie */ export async function web_book_getProgress(bookId: string, cookie = "") { - const resp = await get("https://weread.qq.com/web/book/getProgress", { - bookId, - }, { - cookie: cookie, - }); - return resp.json(); + const resp = await get("https://weread.qq.com/web/book/getProgress", { + bookId, + }, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json(); } /** @@ -83,35 +91,36 @@ export async function web_book_getProgress(bookId: string, cookie = "") { * @param cookie */ export async function web_book_read_init( - bookId: string, - chapterUid: number, - percent = 0, - chapterOffset = 0, - pc: number, - ps: number, - format = "epub", - cookie = "", + bookId: string, + chapterUid: number, + percent = 0, + chapterOffset = 0, + pc: number, + ps: number, + format = "epub", + cookie = "", ) { - const payload: Record = { - "appId": getAppId(UserAgentForWeb), - "b": calcHash(bookId), - "c": calcHash(chapterUid || 0), - "ci": chapterUid || 0, - "co": chapterOffset, - "ct": currentTime(), - "dy": 0, - "fm": format, - "pc": calcHash(pc), - "pr": percent, - "ps": calcHash(ps), - "sm": "", - } - payload.s = sign(payload) - - const resp = await postJSON("https://weread.qq.com/web/book/read", payload, { - cookie: cookie, - }); - return resp.json() + const payload: Record = { + "appId": getAppId(UserAgentForWeb), + "b": calcHash(bookId), + "c": calcHash(chapterUid || 0), + "ci": chapterUid || 0, + "co": chapterOffset, + "ct": currentTime(), + "dy": 0, + "fm": format, + "pc": calcHash(pc), + "pr": percent, + "ps": calcHash(ps), + "sm": "", + } + payload.s = sign(payload) + + const resp = await postJSON("https://weread.qq.com/web/book/read", payload, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json() } /** @@ -139,297 +148,322 @@ export async function web_book_read( cookie = "", rt = 60, ) { - const ts = timestamp() - const rnd = Math.floor(1000 * Math.random()) - - const payload: Record = { - "appId": getAppId(UserAgentForWeb), - "b": calcHash(bookId), - "c": calcHash(chapterUid || 0), - "ci": chapterUid || 0, - "co": chapterOffset, - "ct": currentTime(), - "dy": 0, - "fm": format, - "pc": calcHash(pc), - "pr": percent, - "ps": calcHash(ps), - "sm": "", - rt: rt, // 最大只能为 60 - ts: ts, - rn: rnd, - sg: sha256("" + ts + rnd + readerToken), - } - payload.s = sign(payload) - - const resp = await postJSON("https://weread.qq.com/web/book/read", payload, { - cookie: cookie, - }); - return resp.json() + const ts = timestamp() + const rnd = Math.floor(1000 * Math.random()) + + const payload: Record = { + "appId": getAppId(UserAgentForWeb), + "b": calcHash(bookId), + "c": calcHash(chapterUid || 0), + "ci": chapterUid || 0, + "co": chapterOffset, + "ct": currentTime(), + "dy": 0, + "fm": format, + "pc": calcHash(pc), + "pr": percent, + "ps": calcHash(ps), + "sm": "", + rt: rt, // 最大只能为 60 + ts: ts, + rn: rnd, + sg: sha256("" + ts + rnd + readerToken), + } + payload.s = sign(payload) + + const resp = await postJSON("https://weread.qq.com/web/book/read", payload, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json() } export async function web_book_bookmarklist(bookId: string, cookie = "") { - const resp = await get("https://weread.qq.com/web/book/bookmarklist", { - bookId: bookId, - }, { - cookie: cookie, - }); - return resp.json(); + const resp = await get("https://weread.qq.com/web/book/bookmarklist", { + bookId: bookId, + }, { + cookie: cookie, + }); + await checkErrCode(resp, cookie) + return resp.json(); } export async function web_book_chapter_e0( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 0, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/e_0", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 0, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/e_0", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } export async function web_book_chapter_e1( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 0, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/e_1", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 0, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/e_1", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } export async function web_book_chapter_e2( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 1, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/e_2", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 1, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/e_2", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } export async function web_book_chapter_e3( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 0, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/e_3", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 0, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/e_3", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } export async function web_book_chapter_t0( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 0, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/t_0", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 0, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/t_0", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } export async function web_book_chapter_t1( - bookId: string, - chapterUid: number, - cookie = "", + bookId: string, + chapterUid: number, + cookie = "", ) { - const payload: Record = { - "b": calcHash(bookId), - "c": calcHash(chapterUid), - "r": Math.pow(Math.floor(10_000 * Math.random()), 2), - "st": 1, - "ct": currentTime(), - "ps": "a2b325707a19e580g0186a2", - "pc": "430321207a19e581g013ab0", - }; - payload.s = sign(payload); - - const resp = await postJSON( - "https://weread.qq.com/web/book/chapter/t_1", - payload, - { - cookie: cookie, - }, - ); - const data = await resp.text(); - return data && "string" === typeof data ? chk(data) : ""; + const payload: Record = { + "b": calcHash(bookId), + "c": calcHash(chapterUid), + "r": Math.pow(Math.floor(10_000 * Math.random()), 2), + "st": 1, + "ct": currentTime(), + "ps": "a2b325707a19e580g0186a2", + "pc": "430321207a19e581g013ab0", + }; + payload.s = sign(payload); + + const resp = await postJSON( + "https://weread.qq.com/web/book/chapter/t_1", + payload, + { + cookie: cookie, + }, + ); + await checkErrCode(resp, cookie) + const data = await resp.text(); + return data && "string" === typeof data ? chk(data) : ""; } /** * 获取章节内容 - * @param bookId - * @param chapterUid + * @param bookInfo + * @param chapter * @param cookie */ export async function web_book_chapter_e( - bookId: string, - chapterUid: number, - cookie = "", -): Promise { - let promise: Promise<[string[], string | null]>; - const { format } = await web_book_info(bookId, cookie); - if (format === "epub" || format === "pdf") { - promise = Promise.all([ - web_book_chapter_e0(bookId, chapterUid, cookie), - web_book_chapter_e1(bookId, chapterUid, cookie), - web_book_chapter_e2(bookId, chapterUid, cookie), - web_book_chapter_e3(bookId, chapterUid, cookie), - ]).then((results) => { - if ( - "string" == typeof results[0] && results[0].length > 0 && - "string" == typeof results[1] && results[1].length > 0 && - "string" == typeof results[3] && results[3].length > 0 - ) { - let styles = dS(results[2]); - styles = styleParser.parse(styles, { - removeFontSizes: true, - enableTranslate: false, + bookInfo: BookInfo, + chapter: ChapterInfo, + cookie = "", +): Promise<[string, string, string]> { + let promise: Promise<[string[], string]>; + + const bookId = bookInfo.bookId + + if (M278.isEPub(bookInfo)) { + // epub 格式 + promise = Promise.all([ + web_book_chapter_e0(bookId, chapter.chapterUid, cookie), + web_book_chapter_e1(bookId, chapter.chapterUid, cookie), + web_book_chapter_e2(bookId, chapter.chapterUid, cookie), + web_book_chapter_e3(bookId, chapter.chapterUid, cookie), + ]).then((results) => { + if ( + "string" == typeof results[0] && results[0].length > 0 && + "string" == typeof results[1] && results[1].length > 0 && + "string" == typeof results[3] && results[3].length > 0 + ) { + let style = dS(results[2]); + style = styleParser.parse(style, { + removeFontSizes: true, + enableTranslate: false, + }); + + const html = dH(results[0] + results[1] + results[3]); + const htmls = htmlParser.parse(html, style, 10000); + return [htmls, style]; + } else { + console.log(results); + throw Error(`下载失败(${bookId})`); + } }); + } else { + // txt 格式 + promise = Promise.all([ + web_book_chapter_t0(bookId, chapter.chapterUid, cookie), + web_book_chapter_t1(bookId, chapter.chapterUid, cookie), + ]).then((results) => { + if ( + "string" === typeof results[0] && results[0].length > 0 && + "string" == typeof results[1] && results[1].length > 0 + ) { + const html = dT(results[0] + results[1]); + const htmls = htmlParser.parseTxt(html, 10000); + return [htmls, '']; + } else { + console.log(results); + throw Error(`下载失败(${bookId})`); + } + }); + } - const html = dH(results[0] + results[1] + results[3]); - const htmls = htmlParser.parse(html, styles, 10000); - return [htmls, styles]; - } else { - console.log(results); - throw Error(`下载失败(${bookId})`); - } - }); - } else if (format === "txt") { - promise = Promise.all([ - web_book_chapter_t0(bookId, chapterUid, cookie), - web_book_chapter_t1(bookId, chapterUid, cookie), - ]).then((results) => { - if ( - "string" === typeof results[0] && results[0].length > 0 && - "string" == typeof results[1] && results[1].length > 0 - ) { - const html = dT(results[0] + results[1]); - const htmls = htmlParser.parseTxt(html, 10000); - return [htmls, null]; - } else { - console.log(results); - throw Error("下载失败"); - } - }); - } else { - throw Error(`暂不支持${format}格式(${bookId})`); - } - - let [htmls, styles] = await promise; - - // 处理style - if (styles) { - styles = processStyles(styles, bookId); - } - - // 处理html - htmls = processHtmls(htmls, bookId); - - // 对 html 进行一些处理 - const sections = htmls.map((html) => { - // 图片的处理 - // 去掉 base64 图片地址(该图片是占位符) - html = html.replaceAll(/(]+?)(src="data:[^"]+")/gs, "$1"); - // 将 data-src 替换成 src - html = html.replaceAll(/(]+?)data-src="/gs, '$1src="'); - - // 剥离body外壳 - const bodyRe = /^<\/head>(?.*)<\/body><\/html>$/s; - const match = html.match(bodyRe); - if (match) { - return match.groups!.body; + let [htmls, style] = await promise; + + // 处理style + if (style) { + style = processStyles(style, bookId); } - return html; - }).join(""); - - return ` -
- -${sections} -
-`; + + // 处理html + htmls = processHtmls(htmls, bookId); + + // 封面图替换成高清图片 + const re = /(.+)\/s_([^/]+)$/ + if (re.test(bookInfo.cover)) { + bookInfo.cover = bookInfo.cover.replace(/(.+)\/s_([^/]+)$/, '$1/t9_$2') + } + + // 对 html 进行一些处理 + const sections = htmls.map((html) => { + // 图片的处理 + // 去掉 base64 图片地址(该图片是占位符) + html = html.replaceAll(/(]+?)(src="data:[^"]+")/gs, "$1"); + // 将 data-src 替换成 src + html = html.replaceAll(/(]+?)data-src="/gs, '$1src="'); + + // 替换不存在的封面图 + // https://res.weread.qq.com/wrepub/web/908872/device_phone_frontcover.jpg + // https://wfqqreader-1252317822.image.myqcloud.com/cover/872/908872/t9_908872.jpg (bookInfo.cover) + html = html.replaceAll(/(]+?src=")([^"]+?device_phone_frontcover.jpg)("[^>]*?>)/gs, `$1${bookInfo.cover}$3`) + + // 剥离body外壳 + const bodyRe = /^<\/head>(?.*)<\/body><\/html>$/s; + const match = html.match(bodyRe); + if (match) { + return match.groups!.body; + } + return html; + }).join(""); + + let html = `
` + // 判断是否添加章节标题 + if (showChapterTitle(bookInfo)) { + html += `
${chapterTitleText(bookInfo, chapter)}
` + } + html += `${sections}
` + html = mergeSpanInHtml(html) + const title = chapterTitleText(bookInfo, chapter) || chapter.title + + return [title, html, style] } diff --git a/src/apis/web/category.ts b/src/apis/web/category.ts index fb252cb..52e0d73 100644 --- a/src/apis/web/category.ts +++ b/src/apis/web/category.ts @@ -1,4 +1,5 @@ import {get} from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 图书分类 @@ -56,6 +57,7 @@ export async function bookListInCategory( `https://weread.qq.com/web/bookListInCategory/${categoryId}`, query, ); + await checkErrCode(resp, "anonymous") return resp.json(); } @@ -75,6 +77,7 @@ export async function categoryinfo(categoryId: BookCategory, cookie = "") { }, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } @@ -83,6 +86,7 @@ export async function categoryinfo(categoryId: BookCategory, cookie = "") { */ export async function categories() { const resp = await get("https://weread.qq.com/web/categories", {synckey: 0}); + await checkErrCode(resp, "anonymous") return resp.json(); } @@ -93,6 +97,7 @@ export async function recommendBooks(cookie = "") { const resp = await get("https://weread.qq.com/web/recommend_books", {}, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } diff --git a/src/apis/web/login.ts b/src/apis/web/login.ts index 47a6560..c45f1c6 100644 --- a/src/apis/web/login.ts +++ b/src/apis/web/login.ts @@ -1,4 +1,5 @@ import {get, postJSON} from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 获取uid @@ -71,6 +72,8 @@ export async function web_login_renewal(url: string, cookie = "") { cookie, }); + await checkErrCode(resp, cookie) + const data = await resp.json(); if (data.succ === 1) { return resp.headers.getSetCookie().reduce( @@ -103,5 +106,6 @@ export async function web_login_renewal(url: string, cookie = "") { */ export async function web_login_notify(cookie = "") { const resp = await get("https://weread.qq.com/web/login/notify", {}, {cookie}) + await checkErrCode(resp, cookie) return resp.json() } diff --git a/src/apis/web/misc.ts b/src/apis/web/misc.ts index a607bf1..e9bfe2c 100644 --- a/src/apis/web/misc.ts +++ b/src/apis/web/misc.ts @@ -1,4 +1,5 @@ import {get} from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 获取pdf书籍的下载地址 @@ -12,6 +13,7 @@ export async function getPDFUrl(bookId: string, cookie = "") { }, { cookie, }) + await checkErrCode(resp, cookie) return resp.json() } @@ -21,6 +23,7 @@ export async function getPDFUrl(bookId: string, cookie = "") { */ export async function getConfig(cookie = "") { const resp = await get("https://weread.qq.com/web/getConfig", {}, {cookie}) + await checkErrCode(resp, cookie) return resp.json() } @@ -33,5 +36,6 @@ export async function pdf2epub(bookId: string, cookie = "") { const resp = await get("https://weread.qq.com/web/pdf2epub/notify", { cbid: bookId, }, {cookie}) + await checkErrCode(resp, cookie) return resp.json() } diff --git a/src/apis/web/pay.ts b/src/apis/web/pay.ts index 0389020..4b4279a 100644 --- a/src/apis/web/pay.ts +++ b/src/apis/web/pay.ts @@ -1,4 +1,5 @@ import {get, postJSON} from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 获取账户余额 @@ -11,6 +12,7 @@ export async function web_pay_balance(pf = "ios", cookie = "") { }, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } @@ -25,5 +27,6 @@ export async function web_pay_memberCardSummary(pf = "ios", cookie = "") { }, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } diff --git a/src/apis/web/review.ts b/src/apis/web/review.ts index ae13778..510be3f 100644 --- a/src/apis/web/review.ts +++ b/src/apis/web/review.ts @@ -1,4 +1,5 @@ import {get, postJSON} from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; // 评分 export enum ReviewRatingLevel { @@ -55,6 +56,7 @@ export async function web_review_list_myself(bookId: string, startIdx = 0, count listMode: 2, synckey: synckey, }, {cookie}) + await checkErrCode(resp, cookie) return resp.json() } @@ -83,6 +85,7 @@ export async function web_review_list(bookId: string, startIdx = 0, count = 20, listMode: 2, synckey: synckey, }) + await checkErrCode(resp, "anonymous") return resp.json() } @@ -93,6 +96,7 @@ export async function web_review_single(reviewId: string, cookie = "") { }, { cookie, }) + await checkErrCode(resp, cookie) return resp.json() } @@ -125,5 +129,6 @@ export async function web_review_add( } const resp = await postJSON("https://weread.qq.com/web/review/add", payload, {cookie}) + await checkErrCode(resp, cookie) return resp.json() } diff --git a/src/apis/web/shelf.ts b/src/apis/web/shelf.ts index 4668a4b..995b89b 100644 --- a/src/apis/web/shelf.ts +++ b/src/apis/web/shelf.ts @@ -1,4 +1,5 @@ import { get, postJSON } from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 获取书架上的书 @@ -14,6 +15,7 @@ export async function web_shelf_sync( const resp = await get("https://weread.qq.com/web/shelf/sync", query, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } @@ -28,6 +30,7 @@ export async function web_shelf_syncBook(bookIds: string[] = [], cookie = "") { }, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } @@ -42,6 +45,7 @@ export async function web_shelf_bookIds(bookIds: string[] = [], cookie = "") { }, { cookie: cookie, }) + await checkErrCode(resp, cookie) return resp.json() } @@ -56,6 +60,7 @@ export async function web_shelf_addToShelf(bookIds: string[] = [], cookie = "") }, { cookie: cookie, }) + await checkErrCode(resp, cookie) return resp.json() } @@ -70,5 +75,6 @@ export async function web_shelf_add(bookIds: string[] = [], cookie = "") { }, { cookie, }) + await checkErrCode(resp, cookie) return resp.json() } diff --git a/src/apis/web/upload.ts b/src/apis/web/upload.ts index 4e2c6c9..dfd35bc 100644 --- a/src/apis/web/upload.ts +++ b/src/apis/web/upload.ts @@ -1,4 +1,5 @@ import { get } from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 查询书架是否已满 @@ -7,5 +8,6 @@ export async function mp_shelf_shelfFull(cookie = "") { const resp = await get("https://weread.qq.com/mp/shelf/shelfFull", {}, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } diff --git a/src/apis/web/user.ts b/src/apis/web/user.ts index d7e161b..78ab605 100644 --- a/src/apis/web/user.ts +++ b/src/apis/web/user.ts @@ -1,4 +1,5 @@ import { get } from "../../utils/request.ts"; +import {checkErrCode} from "../err-code.ts"; /** * 查询用户信息 @@ -11,5 +12,6 @@ export async function web_user(vid: number | string, cookie = "") { }, { cookie: cookie, }); + await checkErrCode(resp, cookie) return resp.json(); } diff --git a/src/apis/web/utils.ts b/src/apis/web/utils.ts new file mode 100644 index 0000000..0506519 --- /dev/null +++ b/src/apis/web/utils.ts @@ -0,0 +1,229 @@ +// deno-lint-ignore-file no-explicit-any + +interface BookType { + type: string + showType: boolean + translateDone: boolean + translateStatus: string +} + +interface PaperBook { + skuId: string +} + +export interface BookInfo { + bookId: string + otherType: BookType[] + format: string + type: number + payType: number + originalPrice: number + price: number + payingStatus: number + author: string + soldout: number + paperBook: PaperBook + paid: number + cover: string +} + +export interface ChapterInfo { + chapterIdx: number + chapterUid: number + isMPChapter: number + level: number + paid: number + price: number + readAhead: number + title: string + wordCount: number +} + +function isObject(obj: any) { + return typeof obj === 'object' && obj !== null +} + +export class M278 { + static hasOtherType(bookInfo: BookInfo): boolean { + return isObject(bookInfo) && bookInfo.otherType && bookInfo.otherType.length > 0 + } + + static otherType(bookInfo: BookInfo): string | null { + if (this.hasOtherType(bookInfo) && isObject(bookInfo)) { + return bookInfo.otherType[0].type + } else { + return null + } + } + + static isHasTranslate(bookInfo: BookInfo) { + if (!this.hasOtherType(bookInfo) || !isObject(bookInfo) || !this.otherType(bookInfo)) { + return false + } + const otherType = bookInfo.otherType || [] + return !!Array.isArray(otherType) && otherType.some((bookType) => { + return bookType && undefined !== bookType.translateStatus && bookType.showType && bookType.translateDone + }) + } + + static isTranslationEnabled(bookInfo: BookInfo) { + if (!this.hasOtherType(bookInfo) || !isObject(bookInfo) || !this.otherType(bookInfo)) { + return false + } + const otherType = bookInfo.otherType || [] + return !!Array.isArray(otherType) && otherType.some((bookType) => { + return bookType && 'open' === bookType.translateStatus && bookType.showType && bookType.translateDone + }) + } + + static showOtherType(bookInfo: BookInfo) { + if (this.hasOtherType(bookInfo) && isObject(bookInfo) && this.otherType(bookInfo)) { + return bookInfo.otherType[0].showType + } else { + return false + } + } + + static actualTreatBookFormatAs(bookInfo: BookInfo): string | null { + if (this.hasOtherType(bookInfo) && this.showOtherType(bookInfo)) { + return this.otherType(bookInfo) + } else { + return bookInfo.format + } + } + + static actualTreatBookAsEpub(bookInfo: BookInfo) { + return 'epub' === this.actualTreatBookFormatAs(bookInfo) + } + + static actualTreatBookAsPdf(bookInfo: BookInfo) { + return 'pdf' === this.actualTreatBookFormatAs(bookInfo) + } + + static isSupportedBookType(type: number) { + return 0 === type || 8 === type + } + + static isLegacyReaderSupportBook(bookInfo: BookInfo) { + const type = bookInfo.type + return this.isSupportedBookType(type) || this.actualTreatBookAsEpub(bookInfo) + } + + static isPDFBookType(type: number) { + return 11 === type + } + + static isMPBookType(type: number) { + return type === 3 + } + + static isComicType(type: number) { + return 5 === type + } + + static isSelfBookType(type: number) { + return 8 === type + } + + static isImportedBook(bookId: string | number) { + return 'string' === typeof bookId && bookId.startsWith('CB_') + } + + static isBuyUnitWholeBook(bookInfo: BookInfo) { + return isObject(bookInfo) && 0 !== (1 & bookInfo.payType) + } + + static isBuyUnitChapter(bookInfo: BookInfo) { + return isObject(bookInfo) && 0 !== (2 & bookInfo.payType) + } + + static isFree(bookInfo: BookInfo) { + return isObject(bookInfo) && 0 != (0x20 & bookInfo.payType) + } + + static isLimitFree(bookInfo: BookInfo) { + return isObject(bookInfo) && 0x0 != (0x40 & bookInfo.payType) + } + + static isLimitedSalesPromotion(bookInfo: BookInfo) { + return isObject(bookInfo) && bookInfo.originalPrice > 0 && bookInfo.originalPrice > bookInfo.price + } + + static isSupportFreeMemberShip(bookInfo: BookInfo) { + return isObject(bookInfo) && !(0x2 === bookInfo.payingStatus || 0x4 === bookInfo.payingStatus) + } + + static isSupportMemberShip(bookInfo: BookInfo) { + return isObject(bookInfo) && 0 != (0x1000 & bookInfo.payType) + } + + static isPaidCoinPurchaseOnly(bookInfo: BookInfo) { + return isObject(bookInfo) && 0x0 != (bookInfo.payType & 0x1 << 0x15) + } + + static isEPub(bookInfo: BookInfo) { + return isObject(bookInfo) && this.actualTreatBookFormatAs(bookInfo) === 'epub' + } + + static isSupportReaderProgress(bookInfo: BookInfo) { + return isObject(bookInfo) + } + + static isOuterBook(bookId: string | number) { + return 'string' == typeof bookId && bookId.startsWith('W') + } + + static isSoldOut(bookInfo: BookInfo) { + return isObject(bookInfo) && (0x1 === bookInfo.soldout || 0x2 === bookInfo.soldout) + } + + static isPaperBook(bookInfo: BookInfo) { + return isObject(bookInfo) && bookInfo.paperBook && Number(bookInfo.paperBook.skuId) > 0 + } + + static isTrialReadBook(bookInfo: BookInfo) { + return isObject(bookInfo) && !bookInfo.paid && 0 != (bookInfo.payType & 0x1 << 0x13) + } + + static isCopyRightForbiddenRead(bookInfo: BookInfo) { + return isObject(bookInfo) && '金庸' === bookInfo.author + } + + static isPoliticalSensitive(bookInfo: BookInfo) { + if (!isObject(bookInfo)) { + return false + } + const payType = bookInfo.payType + return Boolean(0x8000 & payType || 0x10000 & payType || payType & 0x1 << 0x11 || payType & 0x1 << 0x12) + } + + static isSinglePurchaseBook(bookInfo: BookInfo) { + return (bookInfo) && 0 != (bookInfo.payType & 0x1 << 0x1a) + } + + static copyRightForbiddenReadToast = '因版权原因,本书不支持在网页端阅读。请至微信读书 App 阅读本书' +} + +/** + * 获取章节标题 + * @param bookInfo + * @param chapter + */ +export function chapterTitleText(bookInfo: BookInfo, chapter: ChapterInfo) { + if (!M278.isSupportedBookType(bookInfo.type)) { + return '' + } + if (!chapter) { + return '' + } + const title = chapter.title + return [M278.isEPub(bookInfo) ? '' : '第' + (chapter.chapterIdx || '') + '章', title].join(' ') +} + +/** + * 是否显示章节标题 + * @param bookInfo + */ +export function showChapterTitle(bookInfo: BookInfo) { + return !(M278.isEPub(bookInfo) || M278.actualTreatBookAsEpub(bookInfo)) || M278.isTrialReadBook(bookInfo) +} diff --git a/src/config.ts b/src/config.ts index d598833..b0c0fbb 100644 --- a/src/config.ts +++ b/src/config.ts @@ -2,5 +2,7 @@ export const UserAgentForWeb = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) export const UserAgentForApp = "WeRead/7.4.2 (iPhone; iOS 17.1; Scale/3.00)" +export const Referer = "https://weread.qq.com/web/reader/bb432f60813ab8444g014d61" + // 每月下载限额 -export const MAX_DOWNLOAD_COUNT_PER_MONTH = 30; +export const MAX_DOWNLOAD_COUNT_PER_MONTH = 10000; diff --git a/src/cron/common.ts b/src/cron/common.ts index 109a4a9..9d22b3c 100644 --- a/src/cron/common.ts +++ b/src/cron/common.ts @@ -1,10 +1,9 @@ // deno-lint-ignore-file no-explicit-any import * as credentialUtil from "../kv/credential.ts"; -import {Credential} from "../kv/credential.ts"; -import {ApiCallResponse, ResponseCode} from "../frontend/apis/common.ts"; -import {web_login_renewal} from "../apis/web/login.ts"; - +import { Credential } from "../kv/credential.ts"; +import { ApiCallResponse, ResponseCode } from "../frontend/apis/common.ts"; +import { web_login_renewal } from "../apis/web/login.ts"; /** * 带有重试功能的 api 调用 @@ -14,48 +13,60 @@ import {web_login_renewal} from "../apis/web/login.ts"; * @param retry 重试次数,默认3次 * @return api调用结果 */ -export async function executeApiCallWithRetry(apiCall: (credential: Credential) => Promise, token: string, retry = 3): Promise { - async function executor(retry: number) { - const credential = await credentialUtil.getByToken(token) - if (!credential) { - return {code: ResponseCode.ParamError, msg: `token(${token})未查询到用户信息`} - } - const cookie = credentialUtil.getCookieByCredential(credential) - - const resp = await apiCall(credential) - if (resp && - ( - // -2010: 用户不存在 - // -2012: 登录超时 - // -2013: 鉴权失败 - [-2010, -2012, -2013].includes(resp.errCode) || - [-2010, -2012, -2013].includes(resp.errcode) - ) && - retry > 0) { - // skey过期,重新刷新 - // console.debug() - try { - const credentialInfo = await web_login_renewal("/web/shelf/sync", cookie); - const {accessToken, refreshToken} = credentialInfo; - credential.skey = accessToken - credential.rt = refreshToken - credential.updatedAt = Date.now() - await credentialUtil.update(credential) +export async function executeApiCallWithRetry( + apiCall: (credential: Credential) => Promise, + token: string, + retry = 3, +): Promise { + async function executor(retry: number) { + const credential = await credentialUtil.getByToken(token); + if (!credential) { + return { + code: ResponseCode.ParamError, + msg: `token(${token})未查询到用户信息`, + }; + } + const cookie = credentialUtil.getCookieByCredential(credential); - // 重新调用原始接口 - return executor(--retry); - } catch (e) { - console.error(e); - // 可能是鉴权失败,需要重新登录 - return {code: ResponseCode.CredentialError, msg: e.message} - } - } else if (resp && resp.needRepeat) { - // 重新调用原始接口 - return executor(--retry); - } + const resp = await apiCall(credential); + if ( + resp && + ( + // -2010: 用户不存在 + // -2012: 登录超时 + // -2013: 鉴权失败 + [-2010, -2012, -2013].includes(resp.errCode) || + [-2010, -2012, -2013].includes(resp.errcode) + ) && + retry > 0 + ) { + // skey过期,重新刷新 + // console.debug() + try { + const credentialInfo = await web_login_renewal( + "/web/shelf/sync", + cookie, + ); + const { accessToken, refreshToken } = credentialInfo; + credential.skey = accessToken; + credential.rt = refreshToken; + credential.updatedAt = Date.now(); + await credentialUtil.update(credential); - return {code: ResponseCode.Success, data: resp, msg: 'success'} + // 重新调用原始接口 + return executor(--retry); + } catch (e) { + console.error(e); + // 可能是鉴权失败,需要重新登录 + return { code: ResponseCode.CredentialError, msg: e.message }; + } + } else if (resp && resp.needRepeat) { + // 重新调用原始接口 + return executor(--retry); } - return await executor(retry) + return { code: ResponseCode.Success, data: resp, msg: "success" }; + } + + return await executor(retry); } diff --git a/src/cron/exchange.ts b/src/cron/exchange.ts index d1fdcf9..18ce192 100644 --- a/src/cron/exchange.ts +++ b/src/cron/exchange.ts @@ -1,10 +1,10 @@ import * as credentialUtil from "../kv/credential.ts"; -import {exchangeAllAward} from "../apis/app/weekly.ts"; -import {jsonResponse} from "../utils/index.ts"; -import {ResponseCode} from "../frontend/apis/common.ts"; -import {executeApiCallWithRetry} from "./common.ts"; -import type {Credential} from "../kv/credential.ts"; - +import { exchangeAllAward } from "../apis/app/weekly.ts"; +import { jsonResponse } from "../utils/index.ts"; +import { ResponseCode } from "../frontend/apis/common.ts"; +import { executeApiCallWithRetry } from "./common.ts"; +import type { Credential } from "../kv/credential.ts"; +import runtime from "../runtime.ts"; /** * 执行兑换体验卡任务 @@ -12,24 +12,34 @@ import type {Credential} from "../kv/credential.ts"; * todo: 等 deno 原生支持 cron 后,可以切换为 deno cron */ export async function runExchangeTask(_: Request) { - console.debug('触发 cron::runExchangeTask 任务') + const key = new URL(_.url).searchParams.get("key"); + if (key !== runtime.cronKey) { + console.warn(`外部触发 cron::runExchangeTask 任务,已忽略(${_.url} <- ${_.headers.get('referer')})`) + return jsonResponse({code: ResponseCode.Error, msg: '非正常触发,已忽略'}) + } + - // 从配置中读取有哪些用户需要兑换 - const users: number[] = [] + console.debug("触发 cron::runExchangeTask 任务"); - for (const vid of users) { - const token = await credentialUtil.getTokenByVid(vid) - if (!token) { - continue - } + // 从配置中读取有哪些用户需要兑换 + const users: number[] = []; + + for (const vid of users) { + const token = await credentialUtil.getTokenByVid(vid); + if (!token) { + continue; + } - const resp = await executeApiCallWithRetry(async (credential: Credential) => { - return await exchangeAllAward(credential.vid, credential.skey) - }, token) - if (resp.code !== ResponseCode.Success) { - // 重试失败 - } + const resp = await executeApiCallWithRetry( + async (credential: Credential) => { + return await exchangeAllAward(credential.vid, credential.skey); + }, + token, + ); + if (resp.code !== ResponseCode.Success) { + // 重试失败 } + } - return jsonResponse({code: ResponseCode.Success, msg: '兑换任务执行完成'}) + return jsonResponse({ code: ResponseCode.Success, msg: "兑换任务执行完成" }); } diff --git a/src/cron/read.ts b/src/cron/read.ts index 3fa2328..aaba41e 100644 --- a/src/cron/read.ts +++ b/src/cron/read.ts @@ -1,104 +1,155 @@ import * as taskManager from "../kv/task.ts"; import * as credentialUtil from "../kv/credential.ts"; import type {Credential} from "../kv/credential.ts"; -import {jsonResponse, randomInteger, sleep, formatSeconds} from "../utils/index.ts"; +import { + formatSeconds, + jsonResponse, + randomInteger, + sleep, +} from "../utils/index.ts"; import {ResponseCode} from "../frontend/apis/common.ts"; import {web_book_read} from "../apis/web/book.ts"; import {friend_ranking} from "../apis/app/friend.ts"; import {ErrCode} from "../apis/err-code.ts"; import {web_login_renewal} from "../apis/web/login.ts"; - +import {pauseReadTask} from "../kv/task.ts"; +import runtime from "../runtime.ts"; /** * 执行自动阅读任务 * 由外部的 cron 触发,每 **30分钟** 触发一次 */ export async function runReadTask(_: Request) { - console.debug('%c触发 cron::runReadTask 任务', 'color: green') - const start = Date.now() + const key = new URL(_.url).searchParams.get("key"); + if (key !== runtime.cronKey) { + console.warn(`外部触发 cron::runReadTask 任务,已忽略(${_.url} <- ${_.headers.get('referer')})`) + return jsonResponse({code: ResponseCode.Error, msg: '非正常触发,已忽略'}) + } - const tasks = await taskManager.getAllReadingTask() - const readerToken = await taskManager.getReaderToken() || '' + console.debug("%c触发 cron::runReadTask 任务", "color: green"); + const start = Date.now(); + const tasks = await taskManager.getAllReadingTask(); + const readerToken = await taskManager.getReaderToken() || ""; + + let taskRunCount = 0; for (const task of tasks) { - const taskStartTime = Date.now() + if (!task.isActive) { + continue; + } + taskRunCount++; + + const taskStartTime = Date.now(); // 准备这个任务的相关参数 - const bookId = task.book.bookId - const token = task.credential.token - let credential = await credentialUtil.getByToken(token) + const bookId = task.book.bookId; + const token = task.credential.token; + let credential = await credentialUtil.getByToken(token); // 先检查 cookie 是不是可能过期 - if (Date.now() - credential.updatedAt >= 1000 * (5400 - 30) /* 留30秒空隙 */) { + if ( + Date.now() - credential.updatedAt >= 1000 * (5400 - 30) /* 留30秒空隙 */ + ) { // cookie 可能已经过期,尝试刷新 - const refreshCookieSuccess = await refreshCookie(task.credential) + const refreshCookieSuccess = await refreshCookie(task.credential); if (!refreshCookieSuccess) { // 刷新失败,就没必要执行下去了 - console.log(`cookie刷新失败,跳过任务(${task.credential.name}:${task.credential.vid}:${task.book.title})`) - continue + console.log( + `cookie刷新失败,跳过任务(${task.credential.name}:${task.credential.vid}:${task.book.title})`, + ); + await pauseReadTask(task); + // todo: 发送通知 + continue; } // 刷新之后获取最新的 cookie - credential = await credentialUtil.getByToken(token) + credential = await credentialUtil.getByToken(token); } - // 计算服务器及客户端加载的时间戳 - const pc = Math.floor(new Date('2023-10-09T15:10+08:00').getTime() / 1000) - const ps = pc - randomInteger(2, 10) + const pc = Math.floor(new Date("2023-10-09T15:10+08:00").getTime() / 1000); + const ps = pc - randomInteger(2, 10); // 查询最新的阅读进度 - let latestSeconds = await getReadingTime(credential) + let latestSeconds = await getReadingTime(credential); if (latestSeconds === -1) { // 获取失败,跳过这个任务 - console.log(`获取进度失败,跳过任务(${task.credential.name}:${task.credential.vid}:${task.book.title})`) - continue + console.log( + `获取进度失败,跳过任务(${task.credential.name}:${task.credential.vid}:${task.book.title})`, + ); + continue; } - let stop = false - let totalSeconds = 0 - const readTime = 60 // 每次更新的阅读时长,单位为秒 + let stop = false; + let totalSeconds = 0; + const readTime = 60; // 每次更新的阅读时长,单位为秒 while (!stop) { - const resp = await updateRead(bookId, pc, ps, readerToken, credential, readTime) + const resp = await updateRead( + bookId, + pc, + ps, + readerToken, + credential, + readTime, + ); if (resp.succ === 1) { // 更新进度成功,查询本次增加的阅读时长 - const seconds = await getReadingTime(credential) + const seconds = await getReadingTime(credential); if (seconds === -1) { // 获取进度数据失败,结束本次任务 - stop = true + stop = true; } else { // 更新成功 - const delta = seconds - latestSeconds - totalSeconds += delta - latestSeconds = seconds + const delta = seconds - latestSeconds; + totalSeconds += delta; + latestSeconds = seconds; if (delta !== readTime) { // 实际更新数值不等于发起的请求,循环结束 - stop = true + stop = true; } else { - await sleep(2000) + await sleep(2000); } } } else { // 更新进度失败 - stop = true + stop = true; } } - console.log(`任务(${task.credential.name}:${task.credential.vid}:${task.book.title})成功更新: %c${formatSeconds(totalSeconds)}%c,耗时: ${((Date.now() - taskStartTime) / 1000).toFixed(1)}s`, 'color: green;font-weight: bold;', '') + console.log( + `任务(${task.credential.name}:${task.credential.vid}:${task.book.title})成功更新: %c${ + formatSeconds(totalSeconds) + }%c,耗时: ${((Date.now() - taskStartTime) / 1000).toFixed(1)}s`, + "color: green;font-weight: bold;", + "", + ); // 写入 - await taskManager.updateReadingTask(credential, totalSeconds) + await taskManager.updateReadingTask(credential, totalSeconds); } - console.log(`全部任务(${tasks.length})执行完毕,耗时: %c${((Date.now() - start) / 1000).toFixed(1)}s`, 'color: red; font-weight: bold;') - return jsonResponse({code: ResponseCode.Success, msg: '阅读任务执行完成'}) + console.log( + `全部任务(${taskRunCount}/${tasks.length})执行完毕,耗时: %c${ + ((Date.now() - start) / 1000).toFixed(1) + }s`, + "color: red; font-weight: bold;", + ); + + return jsonResponse({code: ResponseCode.Success, msg: "阅读任务执行完成"}); } /** * 更新阅读进度 */ -async function updateRead(bookId: string, pc: number, ps: number, readerToken: string, credential: Credential, readTime: number) { +async function updateRead( + bookId: string, + pc: number, + ps: number, + readerToken: string, + credential: Credential, + readTime: number, +) { const resp = await web_book_read( bookId, 2, @@ -110,43 +161,47 @@ async function updateRead(bookId: string, pc: number, ps: number, readerToken: s readerToken, credentialUtil.getCookieByCredential(credential), readTime, - ) + ); if (resp.succ !== 1) { - console.warn('更新阅读进度接口失败: ', resp, credential) + console.warn("更新阅读进度接口失败: ", resp, credential); // 如果出现cookie过期,则刷新cookie if (resp.errCode === ErrCode.SessionTimeout) { - await refreshCookie(credential) + await refreshCookie(credential); } else { // 其他类型的错误暂不处理 } } - return resp + return resp; } /** * 获取阅读时长(秒) */ async function getReadingTime(credential: Credential): Promise { - const resp = await friend_ranking(credential.vid, credential.skey) + const resp = await friend_ranking(credential.vid, credential.skey); if (resp && resp.ranking && Array.isArray(resp.ranking)) { // deno-lint-ignore no-explicit-any - const targetRank = resp.ranking.find((_: any) => _.user.userVid === credential.vid) + const targetRank = resp.ranking.find((_: any) => + _.user.userVid === credential.vid + ); if (targetRank) { - return targetRank.readingTime + return targetRank.readingTime; } else { - console.warn(`没有找到目标用户排名数据(vid:${credential.vid}, name:${credential.name}, skey:${credential.skey})`) - return -1 + console.warn( + `没有找到目标用户排名数据(vid:${credential.vid}, name:${credential.name}, skey:${credential.skey})`, + ); + return -1; } } else { - console.warn('获取阅读时长接口失败: ', resp, credential) + console.warn("获取阅读时长接口失败: ", resp, credential); if (resp.errcode === ErrCode.SessionTimeout) { - await refreshCookie(credential) + await refreshCookie(credential); } - return -1 + return -1; } } @@ -156,18 +211,21 @@ async function getReadingTime(credential: Credential): Promise { */ export async function refreshCookie(credential: Credential) { try { - const oldCookie = credentialUtil.getCookieByCredential(credential) - const credentialInfo = await web_login_renewal("/web/shelf/sync", oldCookie); + const oldCookie = credentialUtil.getCookieByCredential(credential); + const credentialInfo = await web_login_renewal( + "/web/shelf/sync", + oldCookie, + ); const {accessToken, refreshToken} = credentialInfo; - credential.skey = accessToken - credential.rt = refreshToken - credential.updatedAt = Date.now() - await credentialUtil.update(credential) - return true + credential.skey = accessToken; + credential.rt = refreshToken; + credential.updatedAt = Date.now(); + await credentialUtil.update(credential); + return true; } catch (e) { - if (e.message !== '微信登录授权已过期,继续购买需跳转到微信重新登录') { + if (e.message !== "微信登录授权已过期,继续购买需跳转到微信重新登录") { console.error(e); } - return false + return false; } } diff --git a/src/database/bookid.ts b/src/database/bookid.ts index 1a9307c..5dd01c7 100644 --- a/src/database/bookid.ts +++ b/src/database/bookid.ts @@ -1,12 +1,11 @@ import sql from "./db.ts"; -import {calcHash} from "../utils/index.ts"; - +import { calcHash } from "../utils/index.ts"; /** * 创建 bookid 表 */ export async function createBookIdTable(): Promise { - await sql` + await sql` CREATE TABLE IF NOT EXISTS bookid ( book_id text PRIMARY KEY, hash text NOT NULL @@ -19,28 +18,31 @@ export async function createBookIdTable(): Promise { * @param bookIds */ export async function insertBookIds(bookIds: string[]): Promise { - let count = 0 + let count = 0; - for (const bookId of bookIds) { - const hash = calcHash(bookId) - try { - await sql` + for (const bookId of bookIds) { + const hash = calcHash(bookId); + try { + await sql` INSERT INTO bookid (book_id, hash) VALUES (${bookId}, ${hash}) `; - console.log(++count) - } catch (e) { - if (e.message === 'duplicate key value violates unique constraint "bookid_pkey"') { - // 重复插入 - } else { - console.log(e) - } - } + console.log(++count); + } catch (e) { + if ( + e.message === + 'duplicate key value violates unique constraint "bookid_pkey"' + ) { + // 重复插入 + } else { + console.log(e); + } } + } } interface BookIdEntry { - book_id: string + book_id: string; } /** @@ -48,13 +50,15 @@ interface BookIdEntry { * @param hash */ export async function search(hash: string): Promise { - const result = await sql`SELECT book_id FROM bookid WHERE hash = ${hash}` - if (result.count === 0) { - return '' - } else if (result.count === 1) { - return result[0].book_id - } + const result = await sql< + BookIdEntry[] + >`SELECT book_id FROM bookid WHERE hash = ${hash}`; + if (result.count === 0) { + return ""; + } else if (result.count === 1) { + return result[0].book_id; + } - console.warn(result) - throw Error(`hash(${hash}) 搜索异常`) + console.warn(result); + throw Error(`hash(${hash}) 搜索异常`); } diff --git a/src/database/db.ts b/src/database/db.ts index d2488e7..e838e5c 100644 --- a/src/database/db.ts +++ b/src/database/db.ts @@ -1,19 +1,11 @@ -import {runInDenoDeploy} from "../utils/index.ts"; -import {dotenv, postgres} from "../deps.ts" +import { postgres } from "../deps.ts"; +import runtime from "../runtime.ts"; - -const env = await dotenv.load() - -let databaseUrl: string - -if (runInDenoDeploy()) { - databaseUrl = Deno.env.get("DATABASE_URL")!; -} else { - databaseUrl = env["DATABASE_URL"]; -} - -const sql = postgres.default(databaseUrl, { +var sql = "" +if(runtime.databaseUrl.length) { + sql = postgres.default(runtime.databaseUrl, { onnotice: () => {}, -}) + }); +} -export default sql +export default sql; diff --git a/src/database/download.ts b/src/database/download.ts index 6971bfc..966fe90 100644 --- a/src/database/download.ts +++ b/src/database/download.ts @@ -1,11 +1,10 @@ import sql from "./db.ts"; - /** * 创建 download 表 */ export async function createTable(): Promise { - await sql` + await sql` CREATE TABLE IF NOT EXISTS download ( id serial PRIMARY KEY, vid text NOT NULL, @@ -15,29 +14,33 @@ export async function createTable(): Promise { `; } - export interface DownloadRecord { - vid: string - book_id: string - timestamp: string + vid: string; + book_id: string; + timestamp: string; } /** * 插入数据 * @param records */ -export async function insertDownloadRecords(records: DownloadRecord[]): Promise { - await createTable() +export async function insertDownloadRecords( + records: DownloadRecord[], +): Promise { + await createTable(); - for (const record of records) { - try { - await sql`insert into download ${sql(record)}`; - } catch (e) { - if (e.message === 'duplicate key value violates unique constraint "bookid_pkey"') { - // 重复插入 - } else { - console.warn(e) - } - } + for (const record of records) { + try { + await sql`insert into download ${sql(record)}`; + } catch (e) { + if ( + e.message === + 'duplicate key value violates unique constraint "download_id_pkey"' + ) { + // 重复插入 + } else { + console.warn(e); + } } + } } diff --git a/src/database/errlog.ts b/src/database/errlog.ts new file mode 100644 index 0000000..400f338 --- /dev/null +++ b/src/database/errlog.ts @@ -0,0 +1,48 @@ +import sql from "./db.ts"; + +/** + * 创建 errlog 表 + */ +export async function createTable(): Promise { + await sql` + CREATE TABLE IF NOT EXISTS errlog ( + id serial PRIMARY KEY, + user_info text NOT NULL, + err_code int4 NOT NULL, + err_msg text NOT NULL, + timestamp timestamp NOT NULL + ) + `; +} + +export interface ErrLogRecord { + user_info: string; + err_code: number; + err_msg: string; + timestamp: string; +} + +/** + * 插入数据 + * @param records + */ +export async function insertErrLogRecords( + records: ErrLogRecord[], +): Promise { + await createTable(); + + for (const record of records) { + try { + await sql`insert into errlog ${sql(record)}`; + } catch (e) { + if ( + e.message === + 'duplicate key value violates unique constraint "errlog_id_pkey"' + ) { + // 重复插入 + } else { + console.warn(e); + } + } + } +} diff --git a/src/database/log.ts b/src/database/log.ts index b39b9f8..cbd1055 100644 --- a/src/database/log.ts +++ b/src/database/log.ts @@ -1,11 +1,10 @@ import sql from "./db.ts"; - /** * 创建 log 表 */ export async function createTable(): Promise { - await sql` + await sql` CREATE TABLE IF NOT EXISTS log ( id serial PRIMARY KEY, subhoster_id text, @@ -21,16 +20,15 @@ export async function createTable(): Promise { `; } - interface LogRecord { - subhoster_id: string - deployment_id: string - isolate_id: string - region: string - level: string - timestamp: string - message: string - hash: string + subhoster_id: string; + deployment_id: string; + isolate_id: string; + region: string; + level: string; + timestamp: string; + message: string; + hash: string; } /** @@ -38,17 +36,20 @@ interface LogRecord { * @param records */ export async function insertLogRecords(records: LogRecord[]): Promise { - await createTable() + await createTable(); - for (const record of records) { - try { - await sql`insert into log ${sql(record)}`; - } catch (e) { - if (e.message === 'duplicate key value violates unique constraint "log_hash_key"') { - // 重复插入 - } else { - console.warn(e) - } - } + for (const record of records) { + try { + await sql`insert into log ${sql(record)}`; + } catch (e) { + if ( + e.message === + 'duplicate key value violates unique constraint "log_hash_key"' + ) { + // 重复插入 + } else { + console.warn(e); + } } + } } diff --git a/src/deps.ts b/src/deps.ts index d1c0d9b..1b88535 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -1,3 +1,5 @@ +// @ts-nocheck: 导入 npm:crypto-js 这个npm包会提示错误 + export * as fs from "https://deno.land/std@0.194.0/http/file_server.ts"; export * as crypto from "https://deno.land/std@0.201.0/crypto/mod.ts"; export * as base64 from "https://deno.land/std@0.201.0/encoding/base64.ts"; @@ -7,3 +9,5 @@ export * as postgres from "https://deno.land/x/postgresjs@v3.3.5/mod.js"; export * as parse5 from "npm:parse5@7.1.2"; export * as xss from "npm:xss@1.0.14"; // export * as csstree from "npm:css-tree@2.3.1"; +export * as cryptoJS from "npm:crypto-js"; +export * as os from "https://deno.land/std@0.177.0/node/os.ts"; diff --git a/src/frontend/apis/assets.ts b/src/frontend/apis/assets.ts new file mode 100644 index 0000000..060191e --- /dev/null +++ b/src/frontend/apis/assets.ts @@ -0,0 +1,24 @@ +import {apiCallWithRetry, ParamCheckEntity, ResponseCode} from "./common.ts"; +import {Credential} from "../../kv/credential.ts"; +import {get} from "../../utils/request.ts"; + +export async function downloadAsset(req: Request) { + const params: ParamCheckEntity[] = [ + { + name: "token", + from: "query", + statusCode: ResponseCode.CredentialError, + statusText: "token无效", + }, + { + name: 'url', + from: 'query', + statusCode: ResponseCode.ParamError, + statusText: 'url不能为空', + }, + ]; + + return await apiCallWithRetry(req, params, ({url}, _: Credential) => { + return get(decodeURIComponent(url)) + }) +} diff --git a/src/frontend/apis/common.ts b/src/frontend/apis/common.ts index 6ee670c..01fe436 100644 --- a/src/frontend/apis/common.ts +++ b/src/frontend/apis/common.ts @@ -137,7 +137,7 @@ export async function apiCallWithRetry( const encoder = new TextEncoder(); -export type EventType = "close" | "error" | "progress" | "complete" | "qrcode" | "token" | "expired"; +export type EventType = "close" | "error" | "progress" | "preface" | "complete" | "qrcode" | "token" | "expired"; /** diff --git a/src/frontend/apis/downloadSSE.ts b/src/frontend/apis/downloadSSE.ts index 63b8109..803515d 100644 --- a/src/frontend/apis/downloadSSE.ts +++ b/src/frontend/apis/downloadSSE.ts @@ -1,52 +1,243 @@ import * as credentialUtil from "../../kv/credential.ts"; -import { - web_book_chapter_e, - web_book_chapter_e0, - web_book_chapter_e1, - web_book_chapter_e2, - web_book_chapter_e3, - web_book_chapter_t0, - web_book_chapter_t1, - web_book_info -} from "../../apis/web/book.ts"; -import {sleep} from "../../utils/index.ts"; -import {incrementDownloadCount} from "../../kv/download.ts"; -import {sendEvent} from "./common.ts"; -import {Credential} from "../../kv/credential.ts"; -import {processHtmls, processStyles} from "../../utils/process.ts"; -import styleParser from "../../utils/style.ts"; -import htmlParser from "../../utils/html.ts"; -import {dH, dS, dT} from "../../utils/decrypt.ts"; +import { web_book_chapter_e, web_book_chapterInfos, web_book_info } from "../../apis/web/book.ts"; +import { randomInteger, sleep } from "../../utils/index.ts"; +import { incrementDownloadCount } from "../../kv/download.ts"; +import { sendEvent } from "./common.ts"; +import { Credential } from "../../kv/credential.ts"; +import { os } from "../../deps.ts"; +import { ErrCode } from "../../apis/err-code.ts"; +import { jsonResponse } from "../../utils/index.ts"; +import { apiCallWithRetry, ParamCheckEntity, ResponseCode } from "./common.ts"; + +let isPaused = false; // 新增变量控制暂停状态 + +// 在 detail.js 中添加延迟函数 +function randomDelay(min, max) { + const delay = Math.floor(Math.random() * (max - min + 1)) + min; + return new Promise(resolve => setTimeout(resolve, delay/3.0)); +} + +// 增加非线性的阅读行为模拟 +function createHumanReadingProfile() { + // 基础阅读速度 (字符/分钟) + const baseReadingSpeed = randomInteger(380, 620); + + // 注意力波动程度 (0.1-0.3) + const attentionVariability = 0.1 + Math.random() * 0.2; + + // 用户类型: 0-快速扫读, 1-平均阅读者, 2-仔细阅读者 + const readerType = Math.floor(Math.random() * 3); + + // 是否容易分心 (20-40% 概率暂停思考) + const distractionProbability = 0.2 + Math.random() * 0.2; + + // 眼动模式: 每次停顿阅读的字符数 + const saccadeLength = randomInteger(20, 40); + + return { + baseReadingSpeed, + attentionVariability, + readerType, + distractionProbability, + saccadeLength + }; +} + +// 添加随机浏览器信息生成函数 +function generateRandomBrowserInfo() { + // 随机选择一个常见的浏览器版本 + const chromeMajorVersions = [105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118]; + const chromeMinorVersions = [0, 1, 2, 3]; + const chromePatchVersions = [0, 1, 2, 3, 4, 5]; + + const majorVersion = chromeMajorVersions[Math.floor(Math.random() * chromeMajorVersions.length)]; + const minorVersion = chromeMinorVersions[Math.floor(Math.random() * chromeMinorVersions.length)]; + const patchVersion = chromePatchVersions[Math.floor(Math.random() * chromePatchVersions.length)]; + + // 随机选择操作系统信息 + const osList = [ + "Windows NT 10.0; Win64; x64", + "Windows NT 10.0; WOW64", + "Macintosh; Intel Mac OS X 10_15_7", + "Macintosh; Intel Mac OS X 11_2_3", + "X11; Linux x86_64" + ]; + const os = osList[Math.floor(Math.random() * osList.length)]; + + // 生成用户代理字符串 + return { + userAgent: `Mozilla/5.0 (${os}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${majorVersion}.${minorVersion}.${patchVersion}.${randomInteger(10, 200)} Safari/537.36`, + platform: os.includes("Windows") ? "Windows" : os.includes("Mac") ? "MacIntel" : "Linux x86_64", + viewport: { + width: [1366, 1440, 1536, 1920, 2560][Math.floor(Math.random() * 5)], + height: [768, 900, 864, 1080, 1440][Math.floor(Math.random() * 5)] + } + }; +} + +/** + * 模拟真实请求的重试函数 + */ +async function fetchWithRetry(url, options, maxRetries = 3, retryDelay = 5000) { + let lastError; + + for (let attempt = 0; attempt < maxRetries; attempt++) { + try { + // 每次重试使用稍微不同的请求头 + const modifiedOptions = { ...options }; + + // 增加随机化的请求头 + if (!modifiedOptions.headers) { + modifiedOptions.headers = {}; + } + + // 稍微改变 Accept 和 Accept-Language 头 + const languages = ["en-US,en;q=0.9", "en-US,en;q=0.8", "zh-CN,zh;q=0.9,en;q=0.8"]; + modifiedOptions.headers["Accept-Language"] = languages[Math.floor(Math.random() * languages.length)]; + + // 随机改变 Cache-Control + const cacheControls = ["no-cache", "max-age=0"]; + modifiedOptions.headers["Cache-Control"] = cacheControls[Math.floor(Math.random() * cacheControls.length)]; + + // 随机 Connection 类型 + modifiedOptions.headers["Connection"] = Math.random() > 0.5 ? "keep-alive" : "close"; + + // 添加正常浏览器会有的头部 + if (Math.random() > 0.3) { + modifiedOptions.headers["Sec-Fetch-Dest"] = "empty"; + modifiedOptions.headers["Sec-Fetch-Mode"] = "cors"; + modifiedOptions.headers["Sec-Fetch-Site"] = "same-origin"; + } + + // 非第一次请求添加适当延迟,模拟人在尝试重新加载 + if (attempt > 0) { + const jitter = 0.5 + Math.random(); + await randomDelay(retryDelay * jitter, retryDelay * (jitter + 0.5)); + console.log(`重试请求(${attempt}/${maxRetries})...`); + } + + const response = await fetch(url, modifiedOptions); + return response; + } catch (error) { + console.warn(`请求失败(${attempt+1}/${maxRetries}): ${error.message}`); + lastError = error; + + // 不是最后一次尝试时等待重试 + if (attempt < maxRetries - 1) { + // 指数退避策略 + await randomDelay( + retryDelay * Math.pow(1.5, attempt), + retryDelay * Math.pow(1.8, attempt) + ); + } + } + } + + throw lastError; // 所有重试都失败了,抛出最后一个错误 +} + +/** + * 安全章节下载函数 + */ +async function safeDownloadChapter(bookInfo, chapter, cookie, browserInfo) { + const maxRetries = 3; + let attempts = 0; + let lastError; + + // 为了减轻请求压力,先做一个长时间休息 + await randomDelay(3000, 8000); + + while (attempts < maxRetries) { + try { + // 为每个网络请求添加模拟浏览器信息 + const customHeaders = { + "User-Agent": browserInfo.userAgent, + "Referer": "https://weread.qq.com/web/reader", + "Origin": "https://weread.qq.com", + "Cookie": cookie, + "Accept": "application/json, text/plain, */*", + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", + "Content-Type": "application/json", + "DNT": "1" + }; + + // 使用我们的封装函数而不是直接调用API + const [title, html, style] = await web_book_chapter_e( + bookInfo, + chapter, + cookie + ); + + return [title, html, style]; + } catch (error) { + attempts++; + lastError = error; + console.warn(`下载章节 "${chapter.title}" 失败 (${attempts}/${maxRetries}): ${error.message}`); + + // 错误后采用更长的指数退避延迟 + await randomDelay( + 10000 * Math.pow(2, attempts - 1), + 15000 * Math.pow(2, attempts - 1) + ); + + // 如果是频率过高错误,等待更长时间 + if (error.message && error.message.includes("频率") || + (error.errCode && error.errCode === ErrCode.HighFrequency)) { + console.log("检测到频率限制,等待更长时间..."); + await randomDelay(30000, 60000); + } + } + } + + throw lastError || new Error(`下载章节 "${chapter.title}" 失败,超过最大重试次数`); +} /** * 下载 */ -export function downloadSSE( - bookId: string, - chapterUids: number[], - credential: Credential, -): Response { +export function downloadSSE(bookId: string, credential: Credential): Response { let isClosed = false; + const body = new ReadableStream({ start: async (controller) => { try { - const cookie = credentialUtil.getCookieByCredential(credential) + const cookie = credentialUtil.getCookieByCredential(credential); + + // 生成一个随机浏览器信息,整个会话使用相同的浏览器配置 + const browserInfo = generateRandomBrowserInfo(); + console.log(`使用浏览器信息: ${browserInfo.userAgent}`); - for (const chapterUid of chapterUids) { - if (isClosed) { - return; - } + let bookInfo, chapterInfos; + + try { + // 首先获取书籍信息 + bookInfo = await web_book_info(bookId, cookie); + + // 为下一个请求添加随机延迟,模拟真实用户浏览网页的时间 + await randomDelay(1000, 3000); + + // 然后获取章节信息 + chapterInfos = await web_book_chapterInfos([bookId], cookie); + } catch (error) { + console.error("获取书籍信息失败:", error); + sendEvent(isClosed, controller, "error", `获取书籍信息失败: ${error.message}`); + return; + } - // 单章下载 - const html = await web_book_chapter_e(bookId, chapterUid, cookie); - const data = {total: chapterUids.length, current: chapterUid, content: html} - sendEvent(isClosed, controller, "progress", data); + // todo: 检查是否获取章节失败 + const chapters = chapterInfos.data[0].updated; - await sleep(300); + // Windows 环境下通过 `import.meta.resolve()` 函数获取到的路径为 'file:///C:/Users/...',而 `Deno.readTextFileSync()` 函数 + // 在读取 '/C:/Users/...' 文件会出错,需要去掉开头的 '/' 字符,变为 'C:/Users/...' 才可以正确读取。 + // 详情查看 https://github.com/champkeh/wereadx/issues/17 + let fileRe = /^file:\/\// + const platform = os.platform() + if (platform === "win32") { + fileRe = /^file:\/\/\// } - const fileRe = /^file:\/\// + // 开始下载前,先发送公共样式及脚本 const resetStyle = Deno.readTextFileSync(import.meta.resolve("../assets/styles/reset.css").replace(fileRe, '')) const footerNoteStyle = Deno.readTextFileSync( import.meta.resolve("../assets/styles/footer_note.css").replace(fileRe, ""), @@ -54,9 +245,197 @@ export function downloadSSE( const footerNoteScript = Deno.readTextFileSync( import.meta.resolve("../assets/js/footer_note.js").replace(fileRe, "") ) - const extra = {styles: [resetStyle, footerNoteStyle], scripts: [footerNoteScript]} - sendEvent(isClosed, controller, "complete", extra); + const preface = { styles: [resetStyle, footerNoteStyle], scripts: [footerNoteScript] } + sendEvent(isClosed, controller, "preface", preface); + // 创建人类阅读特征 + const readingProfile = createHumanReadingProfile(); + let accumulatedFatigue = 0; // 累积疲劳度,会随着章节增加 + + // 添加阅读时间跟踪,模拟真实用户的阅读会话时长 + const sessionStartTime = Date.now(); + let sessionDuration = 0; + + // 阅读会话设置上限,真实用户不太可能连续阅读太长时间 + const maxSessionDuration = randomInteger(90, 180) * 60 * 1000; // 90-180分钟 + + // 跟踪连续阅读的章节数,真实用户可能会间歇性地休息 + let continuousChapters = 0; + const maxContinuousChapters = randomInteger(3, 8); // 连续阅读3-8章后可能休息 + + for (let i = 0; i < chapters.length; i++) { + const chapter = chapters[i]; + console.log(`开始下载章节: ${chapter.chapterUid}, 标题: ${chapter.title}`) + + // 检查是否已关闭流 + if (isClosed) { + return; + } + + // 检查是否暂停 + while (isPaused) { + console.log("暂停下载中") + await sleep(100); + } + + // 检查阅读会话时长,如果超过上限则模拟结束整个下载 + sessionDuration = Date.now() - sessionStartTime; + if (sessionDuration > maxSessionDuration) { + console.log(`阅读会话已超过${Math.floor(maxSessionDuration/60000)}分钟,暂停下载`); + await randomDelay(120000, 180000); // 休息2-3分钟 + continuousChapters = 0; // 重置连续章节计数器 + } + + // 检查连续章节数,决定是否需要休息 + if (continuousChapters >= maxContinuousChapters) { + console.log(`已连续阅读${continuousChapters}章,休息一下`); + await randomDelay(30000, 120000); // 休息30秒到2分钟 + continuousChapters = 0; // 重置章节计数器 + } + + // 单章下载——使用安全的下载方法 + let title, html, style; + try { + [title, html, style] = await safeDownloadChapter(bookInfo, chapter, cookie, browserInfo); + } catch (error) { + console.error(`下载章节 "${chapter.title}" 失败:`, error); + + // 如果连续失败,可能被反爬系统盯上,等待更长时间 + await randomDelay(60000, 120000); + + // 尝试继续下一章 + continue; + } + + const data = { + total: chapters.length, + current: chapter.chapterIdx, + chapterUid: chapter.chapterUid, + title: title, + html: html, + style: style, + }; + + // 模拟人类阅读过程 + // 1. 计算内容长度和复杂度 + const contentLength = html.length; + const complexity = Math.min(1.3, 0.8 + (countComplexPatterns(html) / 500)); + + // 2. 基于阅读特征和内容复杂度计算阅读时间 + let effectiveReadingSpeed = readingProfile.baseReadingSpeed; + + // 根据读者类型调整阅读速度 + if (readingProfile.readerType === 0) { + // 快速扫读 + effectiveReadingSpeed *= 1.4; + } else if (readingProfile.readerType === 2) { + // 仔细阅读 + effectiveReadingSpeed *= 0.7; + } + + // 根据内容复杂度调整阅读速度 + effectiveReadingSpeed /= complexity; + + // 根据累积疲劳调整阅读速度 + effectiveReadingSpeed *= (1 - (accumulatedFatigue * 0.02)); + + // 计算基础阅读时间 (毫秒) + const baseReadingTime = Math.max( + 8000, // 最少8秒 + Math.min( + 120000, // 最多2分钟 + (contentLength / effectiveReadingSpeed) * 60000 + ) + ); + + // 模拟当前时间点的阅读速度波动 - 更自然的阅读模式 + const timeOfDay = new Date().getHours(); + let timeBasedSpeedFactor = 1.0; + + // 早上精神好,傍晚疲劳 + if (timeOfDay >= 8 && timeOfDay <= 11) { + timeBasedSpeedFactor = 1.1; // 早上读得快一点 + } else if (timeOfDay >= 13 && timeOfDay <= 15) { + timeBasedSpeedFactor = 0.9; // 午后犯困 + } else if (timeOfDay >= 22 || timeOfDay <= 5) { + timeBasedSpeedFactor = 0.85; // 深夜/凌晨读得慢 + } + + // 3. 模拟阅读过程中的变速和停顿 + const contentChunks = Math.ceil(contentLength / readingProfile.saccadeLength); + + // 章节开头和结尾的特殊处理 + // 一般人阅读会在章节开头花更多时间调整思路 + await randomDelay(1500, 3000); + + // 分段阅读,更真实地模拟人类阅读行为 + for (let chunk = 0; chunk < contentChunks; chunk++) { + // 每个小段使用基于基础速度的小变化 + const chunkSpeedVariation = 1 + (Math.random() * 2 - 1) * readingProfile.attentionVariability; + const chunkReadingTime = (baseReadingTime / contentChunks) * chunkSpeedVariation * timeBasedSpeedFactor; + + // 模拟短暂停顿 (眼动) + await randomDelay(chunkReadingTime * 0.9, chunkReadingTime * 1.1); + + // 偶尔模拟回读行为 (10% 概率) + if (Math.random() < 0.1) { + await randomDelay(300, 800); + } + + // 模拟用户偶尔分心,有一定概率触发长停顿 + if (Math.random() < readingProfile.distractionProbability / contentChunks) { + // 分心暂停时间随机 + await randomDelay(3000, 15000); + } + + // 检查是否被取消或暂停 + if (isClosed) { + return; + } + while (isPaused) { + await sleep(100); + } + } + + // 4. 章节读完后的思考/消化时间 + const chapterImportance = 0.5 + (complexity * 0.5); // 重要/复杂章节需要更多思考 + + if (Math.random() < 0.35 * chapterImportance) { + // 模拟深度思考 + await randomDelay(10000, 30000); + } + + // 5. 每读完几个章节,模拟用户休息 + accumulatedFatigue += 0.05 + (complexity * 0.05); + if (accumulatedFatigue > 0.4 && Math.random() < 0.4) { + // 模拟长休息 + await randomDelay(40000, 120000); + accumulatedFatigue *= 0.5; // 休息后疲劳减半 + } + + // 6. 章节结束额外增加行为变化 + // 如果是章节结尾,可能花更多时间思考和消化 + if (Math.random() < 0.3) { + // 模拟用户在章节结束处翻回去检查一些内容 + await randomDelay(5000, 15000); + } + + // 特殊章节(如序章、尾声等)可能会多停留一会 + if (chapter.title.includes("序") || + chapter.title.includes("前言") || + chapter.title.includes("后记") || + chapter.title.includes("结语")) { + await randomDelay(5000, 20000); + } + + sendEvent(isClosed, controller, "progress", data); + console.log("web_book_chapter_e"); + + // 更新累计变量 + continuousChapters++; + } + + sendEvent(isClosed, controller, "complete", null); await incrementDownloadCount(credential, bookId); } catch (e) { console.error(e); @@ -80,100 +459,31 @@ export function downloadSSE( }); } +// 辅助函数:分析内容复杂度 +function countComplexPatterns(html) { + // 简单的复杂度评估,计算特殊符号、长单词等数量 + const complexPatterns = [ + / { + const matches = html.match(pattern); + return count + (matches ? matches.length : 0); + }, 0); +} -/** - * 下载章节内容 - * @param bookId - * @param chapterUid - * @param cookie - */ -export async function download_chapter( - bookId: string, - chapterUid: number, - cookie = "", -): Promise { - let promise: Promise<[string[], string | null]>; - const resp = await web_book_info(bookId, cookie); - console.log(resp) - const {format} = resp - if (format === "epub" || format === "pdf") { - promise = Promise.all([ - web_book_chapter_e0(bookId, chapterUid, cookie), - web_book_chapter_e1(bookId, chapterUid, cookie), - web_book_chapter_e2(bookId, chapterUid, cookie), - web_book_chapter_e3(bookId, chapterUid, cookie), - ]).then((results) => { - if ( - "string" == typeof results[0] && results[0].length > 0 && - "string" == typeof results[1] && results[1].length > 0 && - "string" == typeof results[3] && results[3].length > 0 - ) { - let styles = dS(results[2]); - styles = styleParser.parse(styles, { - removeFontSizes: true, - enableTranslate: false, - }); - - const html = dH(results[0] + results[1] + results[3]); - const htmls = htmlParser.parse(html, styles, 10000); - return [htmls, styles]; - } else { - console.log(results); - throw Error(`下载失败(${bookId})`); - } - }); - } else if (format === "txt") { - promise = Promise.all([ - web_book_chapter_t0(bookId, chapterUid, cookie), - web_book_chapter_t1(bookId, chapterUid, cookie), - ]).then((results) => { - if ( - "string" === typeof results[0] && results[0].length > 0 && - "string" == typeof results[1] && results[1].length > 0 - ) { - const html = dT(results[0] + results[1]); - const htmls = htmlParser.parseTxt(html, 10000); - return [htmls, null]; - } else { - console.log(results); - throw Error("下载失败"); - } - }); - } else { - throw Error(`暂不支持${format}格式(${bookId})`); - } - - let [htmls, styles] = await promise; - - // 处理style - if (styles) { - styles = processStyles(styles, bookId); - } - - // 处理html - htmls = processHtmls(htmls, bookId); - - // 对 html 进行一些处理 - const sections = htmls.map((html) => { - // 图片的处理 - // 去掉 base64 图片地址(该图片是占位符) - html = html.replaceAll(/(]+?)(src="data:[^"]+")/gs, "$1"); - // 将 data-src 替换成 src - html = html.replaceAll(/(]+?)data-src="/gs, '$1src="'); - - // 剥离body外壳 - const bodyRe = /^<\/head>(?.*)<\/body><\/html>$/s; - const match = html.match(bodyRe); - if (match) { - return match.groups!.body; - } - return html; - }).join(""); - - return ` -
- -${sections} -
-`; +// 新增控制暂停和恢复的函数 +export function pauseDownload() { + isPaused = true; + return jsonResponse({ code: ResponseCode.Success, data: "", msg: '成功' }) } + +export function resumeDownload() { + isPaused = false; + return jsonResponse({ code: ResponseCode.Success, data: "", msg: '成功' }) +} \ No newline at end of file diff --git a/src/frontend/apis/notify.ts b/src/frontend/apis/notify.ts new file mode 100644 index 0000000..cc48e40 --- /dev/null +++ b/src/frontend/apis/notify.ts @@ -0,0 +1,135 @@ +import {apiCallWithRetry, ParamCheckEntity, ResponseCode} from "./common.ts"; +import {getEmailVerifyHtml, sendEmail} from "../../utils/email.ts"; +import {jsonResponse} from "../../utils/index.ts"; +import { + confirmEmailBind, + deleteNotify, + deletePreSetting, + getNotifies, + hasAlreadyBind, + hasAlreadySend, + setupEmailVerifyToken, +} from "../../kv/setting.ts"; +import {Credential} from "../../kv/credential.ts"; +import runtime from "../../runtime.ts"; + + +/** + * 发送验证邮件 + * @param req + */ +export async function sendVerifyEmail(req: Request) { + const params: ParamCheckEntity[] = [ + { + name: "token", + from: "header", + statusCode: ResponseCode.CredentialError, + statusText: "token无效", + }, + { + name: 'email', + from: 'header', + statusCode: ResponseCode.ParamError, + statusText: 'email不能为空', + }, + ]; + + return await apiCallWithRetry(req, params, async ({email}, credential: Credential) => { + if (await hasAlreadyBind(credential, email)) { + return jsonResponse({code: ResponseCode.Error, msg: '该邮箱已绑定,请更换邮箱'}) + } + if (await hasAlreadySend(credential)) { + return jsonResponse({code: ResponseCode.Success, msg: '邮件已发送,请查收邮箱'}) + } + + // 生成一个secret + const secret = crypto.randomUUID(); + const notifyUrl = `${runtime.deployDomain}/api/bind/email?token=${credential.token}&secret=${secret}` + + const result = await sendEmail(email, "绑定邮箱通知", getEmailVerifyHtml(notifyUrl)) + console.log(`${credential.name}发送邮箱绑定邮件${email}`) + if (!result) { + return jsonResponse({code: ResponseCode.Error, msg: '邮件发送失败,请稍后重试'}) + } else { + await setupEmailVerifyToken(credential, email, secret) + return jsonResponse({code: ResponseCode.Success, data: result, msg: '发送成功'}) + } + }) +} + +/** + * 绑定邮箱 + * @param req + */ +export async function bindEmail(req: Request) { + const params: ParamCheckEntity[] = [ + { + name: "token", + from: "query", + statusCode: ResponseCode.CredentialError, + statusText: "token无效", + }, + { + name: 'secret', + from: 'query', + statusCode: ResponseCode.ParamError, + statusText: 'secret不能为空', + }, + ]; + + return await apiCallWithRetry(req, params, async ({secret}, credential: Credential) => { + const ok = await confirmEmailBind(credential.vid, secret) + if (ok) { + // 删除 + await deletePreSetting(credential, secret) + return jsonResponse({code: ResponseCode.Success, msg: '绑定成功'}) + } else { + return jsonResponse({code: ResponseCode.Error, msg: '绑定失败'}) + } + }) +} + +/** + * 获取已绑定的通知配置 + * @param req + */ +export async function getSettings(req: Request) { + const params: ParamCheckEntity[] = [ + { + name: "token", + from: "header", + statusCode: ResponseCode.CredentialError, + statusText: "token无效", + }, + ]; + + return await apiCallWithRetry(req, params, async (_, credential: Credential) => { + return await getNotifies(credential) + }) +} + +export async function deleteNotifyMethod(req: Request) { + const params: ParamCheckEntity[] = [ + { + name: "token", + from: "header", + statusCode: ResponseCode.CredentialError, + statusText: "token无效", + }, + { + name: "id", + from: "header", + statusCode: ResponseCode.CredentialError, + statusText: "id不能为空", + }, + ]; + + return await apiCallWithRetry(req, params, async ({id}, credential: Credential) => { + const [ok, rest] = await deleteNotify(credential, id) + if (ok) { + return jsonResponse({code: ResponseCode.Success, data: rest, msg: '成功'}) + } else { + return jsonResponse({code: ResponseCode.Error, msg: '删除失败'}) + } + }) +} diff --git a/src/frontend/apis/shelf.ts b/src/frontend/apis/shelf.ts index 7da07c9..8c9e8ad 100644 --- a/src/frontend/apis/shelf.ts +++ b/src/frontend/apis/shelf.ts @@ -1,17 +1,12 @@ import {web_shelf_sync} from "../../apis/web/shelf.ts"; import {web_book_chapterInfos, web_book_info} from "../../apis/web/book.ts"; import {downloadSSE} from "./downloadSSE.ts"; -import { - checkDownloadCount, - newDownloadSecret, - useSecret, -} from "../../kv/download.ts"; +import {checkDownloadCount, newDownloadSecret, useSecret,} from "../../kv/download.ts"; import {MAX_DOWNLOAD_COUNT_PER_MONTH} from "../../config.ts"; -import {ResponseCode, ParamCheckEntity, apiCallWithRetry} from "./common.ts"; -import {jsonResponse} from "../../utils/index.ts"; -import {search} from "../../database/bookid.ts"; -import * as credentialUtil from "../../kv/credential.ts"; +import {apiCallWithRetry, ParamCheckEntity, ResponseCode} from "./common.ts"; +import {calcHash, jsonResponse} from "../../utils/index.ts"; import type {Credential} from "../../kv/credential.ts"; +import * as credentialUtil from "../../kv/credential.ts"; /** @@ -104,9 +99,9 @@ export async function bookDownload(req: Request) { ]; return await apiCallWithRetry(req, params, async ({secret}: Record, credential: Credential) => { - const [ok, bookId, chapterUids] = await useSecret(credential, secret); + const [ok, bookId] = await useSecret(credential, secret); if (ok) { - return downloadSSE(bookId, chapterUids, credential); + return downloadSSE(bookId, credential); } else { return jsonResponse({code: ResponseCode.ParamError, msg: 'secret无效'}) } @@ -131,15 +126,9 @@ export async function getDownloadSecret(req: Request) { statusCode: ResponseCode.ParamError, statusText: "bookId不能为空", }, - { - name: "chapterUids", - from: "header", - statusCode: ResponseCode.ParamError, - statusText: "chapterUids不能为空", - }, ]; - return await apiCallWithRetry(req, params, async ({bookId, chapterUids}: Record, credential: Credential) => { + return await apiCallWithRetry(req, params, async ({bookId}: Record, credential: Credential) => { // 验证该用户的月下载量 if (!(await checkDownloadCount(credential))) { // 无法下载 @@ -149,18 +138,13 @@ export async function getDownloadSecret(req: Request) { const secret = await newDownloadSecret( credential, bookId, - chapterUids.split("|").map((uid: string) => Number(uid)), ); return jsonResponse({code: ResponseCode.Success, data: secret, msg: 'success'}) } }) } -/** - * 书籍查询 - * @param req - */ -export async function bookSearch(req: Request) { +export async function bookHash(req: Request) { const params: ParamCheckEntity[] = [ { name: "token", @@ -169,21 +153,13 @@ export async function bookSearch(req: Request) { statusText: "token无效", }, { - name: "hash", + name: "bookId", from: "header", statusCode: ResponseCode.ParamError, - statusText: "hash无效", + statusText: "bookId不能为空", }, - ]; - - return await apiCallWithRetry(req, params, async ({hash}: Record) => { - console.log(hash) - const bookId = await search(hash) - console.log('search bookId: ', bookId) - if (bookId) { - return jsonResponse({code: ResponseCode.Success, data: bookId, msg: 'success'}) - } else { - return jsonResponse({code: ResponseCode.Error, msg: '未找到,欢迎提供反馈'}) - } + ] + return await apiCallWithRetry(req, params, ({bookId}) => { + return Promise.resolve(calcHash(bookId)) }) } diff --git a/src/frontend/assets/js/footer_note.js b/src/frontend/assets/js/footer_note.js index cbf92a5..c6790be 100644 --- a/src/frontend/assets/js/footer_note.js +++ b/src/frontend/assets/js/footer_note.js @@ -1 +1,2 @@ +// footer_note.js console.log(123) diff --git a/src/frontend/assets/styles/footer_note.css b/src/frontend/assets/styles/footer_note.css index fb6e667..227cfa3 100644 --- a/src/frontend/assets/styles/footer_note.css +++ b/src/frontend/assets/styles/footer_note.css @@ -1,40 +1,30 @@ -/* 携带注释信息的元素,下面的样式用来让它显示为一个黑色的圆 */ +/* footer_note.css */ span.reader_footer_note { - text-indent: 0; /* 避免继承段落的缩进样式 */ - text-align: left; /* 文字左对齐 */ - position: relative; /* 用来给伪元素做定位参照 */ - display: inline-block; /* 使宽度和高度指定有效 */ - width: 1em; /* 设定宽度 */ - height: 1em; /* 设定高度 */ - background-color: black; /* 设定背景为黑色 */ - vertical-align: super; /* 设置为上标形式 */ - border-radius: 50%; /* 圆角化为圆形 */ - cursor: pointer; /* 光标样式改为手指 */ + position: relative; + display: inline-block; + width: 19px; + height: 19px; + background-color: black; + vertical-align: sub; + border-radius: 50%; + cursor: pointer; + margin: 0 3px; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAQAAAACNCElAAACuUlEQVR42q2WTWgTQRTHX4v1UNFiDgVFPEmRXETbS0V6yKESpMGLl3rw7MGLBizoTTAXmx78wAUpIvHSFAq7JqbGpjWm1kA/Y2I/qOgam1qbLNbEJDXNPpmuS5PMbJqtu//Lzhveb3fmvZn3ALQfE1jBDg7gwA1u4MABdrCCCXQ+DWCDXhA01As2aKgNVA8W6NcEqeoHC9TvhmqGvl1BqvqguRrKDK6aUUQuMGuhOmBIF4poCDrYf6UfpeDM9F659oRSFttcHsGSbW/xD355sNAVUscnXi3/nFy/P3/UVyUUJZG1lE8+XUZEnPxxyKOML45vFRGzBVtIE2fZSdGKvNr/IpEhuJszqoVbJOOVtDrPyLt/aWyjv9Qzi1iUu0I9s8q4yfv7D2Iyq8xFUsfoJdsUmJOG1QmdwbZAW8ARbfQoujbli1961+hpH81vISYyZwLUIds+zmXGe7E7H86/Vd55kVsa/Ew0/p0sE2VlRHRrlvoFE4C13HQljDLi1Pphb4t/XlKt3ROEVSxWTRErgL3S+GaVODqizz89XtQFswM4Ko2X35MFXZ/OFzqDumAOAI42nxtrH+UWpVydwIJ1T2ikLwfgZk2YvJlNXgQGrDWQKyQyrQGGlxtggAVzfkS8OgnC7TleJAqvKdHkxa9pWZblVO74MOU1wFxmk3cjj/IRHwi69oxjBACEJ0uI4q9SS60BqEiNs2PBVZJpwVXdMDuVtOQYSznESEo3zEodJ6KZJKIsnx7RCduuqFSFjCSJ66MFNuykP5o6NcKopuwrKJ4mri/jLNg+IZJC3Ni8EGJfQdTlmC0Q14cLd6NKlvHi65WYFJOiEi8OfyNvMSm8dtDDuhypa/vG9Fzy2fIBj46iYtEoKHtQX3mrYGCpM7gIG9weGNy4GNxSGdzs7bShTk2Qs/Y29D8a5L99J97IcV5pLgAAAABJRU5ErkJggg=='); + background-size: 100%; + background-repeat: no-repeat; } -/* before 伪元素用来显示“注”这个字 */ -span.reader_footer_note:before { - position: absolute; /* 绝对位置,基准为 span.reader_footer_note */ - content: "注"; /* 显示“注”字 */ - color: white; /* 字颜色为白色 */ - left: 0.15em; /* 微调字的位置 */ - top: 0.1em; /* 微调字的位置 */ - font-size: 0.75em; /* 设定文字大小 */ - font-family: "汉仪楷体"; /* 设定字体 */ -} - -/* after 伪元素用来显示注释内容,只在光标移至“注”上方时才显示 */ span.reader_footer_note:hover:after { - position: fixed; /* 相对于视窗的位置 */ - content: attr(data-wr-footernote); /* 获取并设置注释内容 */ - left: 0; /* 设定相对于视窗的位置 */ - bottom: 0; /* 设定相对于视窗的位置 */ - margin: 1em; /* 设定背景气泡与视窗边缘预留的空间 */ - background: black; /* 设定背景气泡为黑色 */ - border-radius: 0.25em; /* 背景气泡圆角 */ - color: white; /* 设定文字为白色 */ - padding: 0.5em; /* 设定文字内容与背景气泡边缘预留的空间 */ - font-size: 1em; /* 设定文字大小 */ - font-family: "汉仪楷体"; /* 设定字体 */ - z-index: 1; /* 避免被其它元素遮挡 */ + position: fixed; + content: attr(data-wr-footernote); + left: 0; + bottom: 0; + margin: 1em; + background: black; + border-radius: 0.25em; + color: white; + padding: 0.5em; + font-size: 1em; + font-family: "汉仪楷体", sans-serif; + z-index: 10; } diff --git a/src/frontend/assets/styles/reset.css b/src/frontend/assets/styles/reset.css index b663ecb..ef25b3b 100644 --- a/src/frontend/assets/styles/reset.css +++ b/src/frontend/assets/styles/reset.css @@ -1,3 +1,12 @@ -img, picture, video, canvas, svg { - max-width: 100% !important; +/* reset.css */ +body { + line-height: 1.8; + font-size: 16px; + /*font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif;*/ +} +.chapterTitle { + margin-bottom: 18px; + font-size: 24px; + font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; + color: #0d141e; } diff --git a/src/frontend/www/detail.html b/src/frontend/www/detail.html index aeddcd8..7ea50de 100644 --- a/src/frontend/www/detail.html +++ b/src/frontend/www/detail.html @@ -2,31 +2,32 @@ - + 图书详情 + + + @@ -35,19 +36,48 @@
- 书籍封面 -
- + 书籍封面

---

- 作者:--- + 作者:---
- + +
+ +
+ + +
+
+ + +
+
+
简介:---
@@ -57,313 +87,32 @@

---

详细信息

- 出版社 + 出版社
- 出版时间 + 出版时间
- - - -
- 原始格式 -

- - 下载 -

+ 原始格式 +
- 其他可用格式 + 其他可用格式
- ISBN + ISBN
-

章节信息

-
    +

    目录

    +
    - - - + diff --git a/src/frontend/www/epub/epub.js b/src/frontend/www/epub/epub.js new file mode 100644 index 0000000..11ca68c --- /dev/null +++ b/src/frontend/www/epub/epub.js @@ -0,0 +1,197 @@ +import {uuid, zipFile} from "../js/utils.js"; +import getPackage from "./templates/package.js"; +import getChapter from "./templates/chapter.js"; +import getContainer from "./templates/container.js"; +import getToc from "./templates/toc.js"; +import {getImgExt, getUid, slugify, CORS_PROXY} from "./utils.js"; + +/** + * @typedef Book + * @property {string} id + * @property {string} cover 封面 + * @property {string} coverMineType + * @property {string} title 书名 + * @property {string} author 作者 + * @property {string} description 简介 + * @property {string} lang 语言 + * @property {string} isbn ISBN + * @property {string} publisher 出版公司 + * @property {string} publishTime 出版时间 + * @property {{chapterIdx: number, chapterUid: number, title: string, level: number, anchor: string, children: {}[]}[]} toc 目录 + * @property {{chapterIdx: number, chapterUid: number, title: string, html: string, style: string}[]} chapters 章节数据 + * @property {string[]} styles + * @property {string[]} scripts + */ + +export class Book extends EventTarget { + constructor(options) { + super() + + this.id = uuid() + this.cover = options.cover || '' + this.coverMineType = '' + this.isbn = options.isbn || '' + this.author = options.author?.replace(/\s+著$/i, '') || 'anonymous' + this.description = options.description || '' + this.publisher = options.publisher || 'anonymous' + this.publishTime = options.publishTime || '' + this.title = options.title || '[Untitled]' + this.lang = options.lang || "zh" + this.toc = options.toc || [] + this.chapters = options.chapters || [] + this.styles = options.styles || [] + this.scripts = options.scripts || [] + } + + /** + * 解析并下载章节中的图片 + * @return {Promise} + */ + async resolveHtmlImages() { + const chapters = [] + // 解析图片 + let imageCount = 0 + let errorCount = 0 + for (const chapter of this.chapters) { + const $htmlDom = new DOMParser().parseFromString( + chapter.html, + "text/html" + ); + + const chapterImages = [] + const imgEls = Array.from($htmlDom.querySelectorAll("img")) + for (const imgEl of imgEls) { + const src = imgEl.getAttribute("src"); + + if (imgEl.hasAttribute("srcset")) { + imgEl.removeAttribute("srcset"); + } + + // 下载图片并替换图片地址为本地地址 + // todo: 检测重复图片的下载 + try { + const imgBlob = await fetch(CORS_PROXY + encodeURIComponent(src)).then(resp => resp.blob()) + imageCount++ + + const uid = getUid(); + const ext = getImgExt({mimeType: imgBlob.type, fileUrl: src}); + const id = `${uid}.${ext}`; + + imgEl.setAttribute("src", `images/${id}`); + chapterImages.push({ + id: id, + type: imgBlob.type, + blob: imgBlob, + }) + } catch (e) { + // todo: 失败时重试 3 次 + errorCount++ + console.error(e); + console.warn("Failed to fetch (will use placeholder):", src); + imgEl.setAttribute("src", "images/img-placeholder.png"); + } + + this.dispatchEvent( + new CustomEvent('image', { + detail: { + success: imageCount, + error: errorCount, + } + }) + ) + } + + chapters.push({ + chapterIdx: String(chapter.chapterIdx).padStart(3, "0"), + chapterUid: String(chapter.chapterUid).padStart(3, "0"), + title: chapter.title || "[Untitled]", + html: new XMLSerializer().serializeToString($htmlDom.querySelector("body > section")), + style: chapter.style, + images: chapterImages, + }) + } + + this.chapters = chapters + } + + /** + * 导出 html + * @return {Promise} + */ + async export2html() { + const style = this.styles.map(style => ``).join('\n') + const script = this.scripts.map(script => ` + + +`; +} diff --git a/src/frontend/www/epub/templates/container.js b/src/frontend/www/epub/templates/container.js new file mode 100644 index 0000000..aaa1fe4 --- /dev/null +++ b/src/frontend/www/epub/templates/container.js @@ -0,0 +1,8 @@ +export default function getContainer() { + return ` + + + + +`; +} diff --git a/src/frontend/www/epub/templates/package.js b/src/frontend/www/epub/templates/package.js new file mode 100644 index 0000000..199c3db --- /dev/null +++ b/src/frontend/www/epub/templates/package.js @@ -0,0 +1,50 @@ +import {escapeXml} from "../utils.js"; + +/** + * @param {import('../index.js').Epub} book + * @return {string} + */ +export default function getPackage(book) { + const {id, cover, coverMineType, title, description, lang, author, isbn, publisher, publishTime, chapters} = book; + // 微信读书的出版时间是一个字符串,没办法确定时区,比如 2000-01-01T00:00:00Z + // 这里按照北京时间算 + let created + if (publishTime) { + created = new Date(publishTime).toISOString().split(".")[0] + "Z"; + } + const modified = new Date().toISOString().split(".")[0] + "Z"; + + return ` + + + urn:uuid:${id} + ${isbn ? '' + isbn +'' : ''} + ${escapeXml(title)} + ${escapeXml(lang)} + ${escapeXml(author)} + ${created ? '' + created + '' : ''} + ${escapeXml(description)} + ${escapeXml(publisher)} + aut + 22 + ${isbn ? '15' : ''} + ${modified} + BookId + + + + + ${cover && coverMineType ? '' : ''} + +${chapters.map(chapter => ` `).join('\n')} +${chapters.flatMap(chapter => chapter.images).map(({id, type}) => ` `).join('\n')} + + + + + +${chapters.map((chapter) => ` `).join("\n")} + + +`; +} diff --git a/src/frontend/www/epub/templates/toc.js b/src/frontend/www/epub/templates/toc.js new file mode 100644 index 0000000..75efafd --- /dev/null +++ b/src/frontend/www/epub/templates/toc.js @@ -0,0 +1,45 @@ +import {escapeXml} from "../utils.js"; + +/** + * @param {{chapterIdx: number, chapterUid: number, title: string, level: number, anchor: string, children: {}[]}[]} toc + * @return {string} + */ +function renderToc(toc) { + let html = '
      \n' + for (let i = 0; i < toc.length; i++) { + const {title, chapterIdx, anchor, children} = toc[i] + const idx = String(chapterIdx).padStart(3, "0") + if (anchor) { + html += `
    1. ${escapeXml(title)}` + } else { + html += `
    2. ${escapeXml(title)}` + } + if (Array.isArray(children) && children.length > 0) { + html += renderToc(children) + } + html += '
    3. ' + } + html += '
    ' + return html +} + +export default function getToc(epub) { + const {toc} = epub; + const tocHtml = renderToc(toc) + + return ` + + + + 目录 + + + +

    目录

    + + + +`; +} diff --git a/src/frontend/www/epub/utils.js b/src/frontend/www/epub/utils.js new file mode 100644 index 0000000..fd7d31a --- /dev/null +++ b/src/frontend/www/epub/utils.js @@ -0,0 +1,296 @@ +const token = localStorage.getItem('token') + +/** + * Because we fetch things client side, like the HTML of articles at a URL or + * the images at a URL when generating an epub, we have to proxy all these + * requests, or we'll likely get CORS issues. + * + * ROOT/.netlify/functions/proxy?url= + */ +export const CORS_PROXY = `/api/asset/download?token=${token}&url=`; + +/** + * Check if a URL is relative to the current path or not + * https://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative + * @param {string} url + * @returns {boolean} + */ +export function isUrlAbsolute(url) { + if (url.indexOf("//") === 0) { + return true; + } // URL is protocol-relative (= absolute) + if (url.indexOf("://") === -1) { + return false; + } // URL has no protocol (= relative) + if (url.indexOf(".") === -1) { + return false; + } // URL does not contain a dot, i.e. no TLD (= relative, possibly REST) + if (url.indexOf("/") === -1) { + return false; + } // URL does not contain a single slash (= relative) + if (url.indexOf(":") > url.indexOf("/")) { + return false; + } // The first colon comes after the first slash (= relative) + if (url.indexOf("://") < url.indexOf(".")) { + return true; + } // Protocol is defined before first dot (= absolute) + return false; // Anything else must be relative +} + +/** + * Take a relative path, resolve it within a base path, and return it + * @param {string} relativeUrl + * @param {string} baseUrl + * @return {string} + */ +export function resolveUrl(relativeUrl, baseUrl) { + const url = new URL(relativeUrl, baseUrl); + return url.href ? url.href : relativeUrl; +} + +/** + * https://stackoverflow.com/questions/5717093/check-if-a-javascript-string-is-a-url + * @param {string} string + * @returns {boolean} + */ +export function isValidHttpUrl(string) { + let url; + + try { + url = new URL(string); + } catch (_) { + return false; + } + + return url.protocol === "http:" || url.protocol === "https:"; +} + +/** + * https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server + * @param {string} file + * @param {string} contents + */ +export function downloadFile({ file, contents }) { + var element = document.createElement("a"); + element.setAttribute( + "href", + "data:text/plain;charset=utf-8," + encodeURIComponent(contents) + ); + element.setAttribute("download", file); + + element.style.display = "none"; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); +} + +/** + * https://gist.github.com/codeguy/6684588 + * @param {string} str + * @returns {string} + */ +export function slugify(str) { + str = str.replace(/^\s+|\s+$/g, ""); // trim + str = str.toLowerCase(); + + // remove accents, swap ñ for n, etc + const from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;"; + const to = "aaaaeeeeiiiioooouuuunc------"; + for (let i = 0, l = from.length; i < l; i++) { + str = str.replace(new RegExp(from.charAt(i), "g"), to.charAt(i)); + } + + str = str + // .replace(/[^a-z0-9 -]/g, "") // remove invalid chars + .replace(/\s+/g, "-") // collapse whitespace and replace by '-' + .replace(/-+/g, "-"); // collapse dashes + + return str; +} + + +function stripHtml(html) { + if (typeof window !== "undefined") { + var doc = new DOMParser().parseFromString(html, "text/html"); + return doc.body.textContent || ""; + } else { + return html; + } +} + +function isValidUrl(string) { + try { + new URL(string); + } catch (_) { + return false; + } + + return true; +} + +/** + * Check if a string is ISO8601 format, specifically: `YYYY-MM-DDTHH:MN:SS.MSSZ` + * https://stackoverflow.com/questions/52869695/check-if-a-date-string-is-in-iso-and-utc-format + * @param {string} str + * @returns {boolean} + */ +function isIsoDate(str) { + if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) return false; + var d = new Date(str); + return d.toISOString() === str; +} + +export function devLog(array) { + if (typeof window !== "undefined" && window.IS_DEV) { + // console.log("(__DEV__) " + array.join("\n ")); + // console.group(); + array.forEach((item, i) => { + if (i === 0) { + console.log("__DEV__ ", item); + } else { + console.log(" ", item); + } + }); + // console.groupEnd(); + } +} + +/** + * Take a URL and it's HTML contents and parse it with mercury to 1) + * sanitzie the HTML, and 2) absolutize image links. + * @param {string} url + * @param {string} html + * @returns {MercuryArticle} + */ +export function createMercuryArticle(url, html) { + return window.Mercury.parse(url, { html }).then((mercuryArticle) => { + let dom = new DOMParser().parseFromString( + mercuryArticle.content, + "text/html" + ); + let modified = false; + // Change all relative paths for and to absolute ones + Array.from(dom.querySelectorAll("img, a")).forEach(($node) => { + // the DOM node's property, i.e. $img.src, resolves to an absolute URL + // while .getAttribute() gives you what's in the source HTML (possibly + // a relative path) + const nodeType = $node.tagName.toLowerCase(); + const resolvedUrl = nodeType === "img" ? $node.src : $node.href; + + // If the resolved URL has the current window location's host in it, that + // means it was a relative path, i.e. "../path/to/thing" and therefore + // the browser resolved it to the current window. We don't want that. + // We want it to resolve to the source from whence it came. + if (resolvedUrl.includes(window.location.hostname)) { + const relativePath = + nodeType === "img" + ? $node.getAttribute("src") + : $node.getAttribute("href"); + const newResolvedUrl = resolveUrl(relativePath, mercuryArticle.url); + devLog([ + `Changed relative path for <${nodeType}> tag`, + `From: ${relativePath}`, + `To: ${newResolvedUrl}`, + ]); + $node.setAttribute(nodeType === "img" ? "src" : "href", newResolvedUrl); + modified = true; + } + }); + + if (modified) { + mercuryArticle = { + ...mercuryArticle, + content: dom.body.innerHTML, + }; + } + + devLog(["Created a new Mercurcy article", mercuryArticle]); + + return mercuryArticle; + }); +} + +/** + * https://stackoverflow.com/a/27979933/1339693 + */ +export function escapeXml(unsafe) { + return unsafe.replace(/[<>&'"]/g, function (c) { + switch (c) { + case "<": + return "<"; + case ">": + return ">"; + case "&": + return "&"; + case "'": + return "'"; + case '"': + return """; + } + }); +} + +/** + * Given an image's mimetype, return the extension. If there's no extension + * https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types + * @param {{ + * mimeType: string, + * fileUrl: string + * }} + * @returns {string} + */ +export function getImgExt({ mimeType, fileUrl }) { + switch (mimeType) { + case "image/apng": + return "apng"; + case "image/bmp": + return "bmp"; + case "image/gif": + return "gif"; + case "image/x-icon": + return "ico"; + case "image/jpeg": + return "jpg"; + case "image/png": + return "png"; + case "image/svg+xml": + return "svg"; + case "image/tiff": + return "tiff"; + case "image/webp": + return "webp"; + default: + // Pull it from the filename if we can't get it + // https://stackoverflow.com/questions/6997262/how-to-pull-url-file-extension-out-of-url-string-using-javascript + return fileUrl.split(/[#?]/)[0].split(".").pop().trim(); + } +} + +/** + * Import a UMD file using a promise + * @param {string} url + */ +export function importUMD(url) { + return new Promise((resolve, reject) => { + const script = document.createElement("script"); + script.onload = () => { + resolve(); + }; + script.onerror = (err) => { + reject(err); + }; + script.src = url; + + document.head.appendChild(script); + }); +} + +/** + * https://gist.github.com/SimonHoiberg/ad2710c8626c5a74cddd8f6385795cc0 + * @returns {string} + */ +export function getUid() { + return Date.now().toString(36) + Math.random().toString(36).substr(2); +} diff --git a/src/frontend/www/index.html b/src/frontend/www/index.html index 8cbad93..2c4afe1 100644 --- a/src/frontend/www/index.html +++ b/src/frontend/www/index.html @@ -4,6 +4,7 @@ 我的书架 + @@ -14,16 +15,16 @@ @@ -53,17 +54,6 @@ - - - diff --git a/src/frontend/www/search.html b/src/frontend/www/search.html deleted file mode 100644 index cafb739..0000000 --- a/src/frontend/www/search.html +++ /dev/null @@ -1,122 +0,0 @@ - - - - - - 搜索 - - - - - - - - - -
    -
    -
    - -
    - -
    - - -
    - -
    - - - - - - diff --git a/src/frontend/www/setting.html b/src/frontend/www/setting.html new file mode 100644 index 0000000..de83e6f --- /dev/null +++ b/src/frontend/www/setting.html @@ -0,0 +1,62 @@ + + + + + + 设置 + + + + + + + + + + +
    +
    + +
    +
    + 通知方式 +
    +
    +
      + +
      +
      + + +
      我们绝不会与其他人分享您的电子邮件。
      +
      + + +
      +
      +
      +
      + + diff --git a/src/frontend/www/style/common.css b/src/frontend/www/style/common.css index 5edccfd..c6b0900 100644 --- a/src/frontend/www/style/common.css +++ b/src/frontend/www/style/common.css @@ -1,5 +1,5 @@ body { - font-size: 12px; + /*font-size: 12px;*/ line-height: 1.5; background: #eee; font-family: PingFang SC, -apple-system, SF UI Text, Lucida Grande, STheiti, Microsoft YaHei, sans-serif; diff --git a/src/frontend/www/style/detail.css b/src/frontend/www/style/detail.css index a87d65a..eb79cce 100644 --- a/src/frontend/www/style/detail.css +++ b/src/frontend/www/style/detail.css @@ -107,37 +107,6 @@ } } -.btn_primary { - flex-shrink: 0; - display: flex; - padding: 0 25px; - justify-content: center; - align-items: center; - height: 40px; - line-height: 40px; - border-radius: 20px; - font-size: 14px; - font-weight: 500; - background-image: linear-gradient(90deg, #0087fc, #28b7ff); - color: #fff; - - &[disabled] { - background-color: rgba(13, 20, 30, .04); - color: #717882; - cursor: not-allowed; - background-image: none; - } -} -.download { - margin-right: 30px; -} - -.origin-download { - color: #0087fc; - cursor: pointer; - display: none; -} - .bookInfo_author_container { margin-top: 2px } @@ -190,18 +159,10 @@ .introDialog_content_title { font-family: "SourceHanSerifCN-Bold", PingFang SC, -apple-system, SF UI Text, Lucida Grande, STheiti, Microsoft YaHei, sans-serif; font-size: 18px; - color: #eef0f4; + color: #212832; margin-bottom: 16px } -.wr_whiteTheme .introDialog_content_title { - color: #212832 -} - -.introDialog_content_title:not(:first-child) { - margin-top: 32px -} - .introDialog_content_intro_para { line-height: 24px; text-align: justify @@ -224,52 +185,15 @@ max-width: 100% } -.introDialog_content_pub_title { - color: #8a8c90 -} - -.wr_whiteTheme .introDialog_content_pub_title { - color: #858c96 -} - -button { - background: none; - border: 0; - padding: 0; - text-decoration: none; - cursor: pointer +.actions { + display: flex; + justify-content: flex-end; + align-items: flex-start; + min-width: 200px; + gap: 10px; } -.chapters { +#toc ol, +#toc ul { list-style-type: none; - padding-left: 0; - .chapter { - &[data-level="1"] { - padding-left: 0; - } - &[data-level="2"] { - padding-left: 2rem; - } - &[data-level="3"] { - padding-left: 4rem; - } - &[data-level="4"] { - padding-left: 6rem; - } - &[data-level="5"] { - padding-left: 8rem; - } - &[data-level="6"] { - padding-left: 10rem; - } - &[data-level="7"] { - padding-left: 10rem; - } - &[data-level="8"] { - padding-left: 10rem; - } - &[data-level="9"] { - padding-left: 10rem; - } - } } diff --git a/src/frontend/www/style/review.css b/src/frontend/www/style/review.css deleted file mode 100644 index c956f70..0000000 --- a/src/frontend/www/style/review.css +++ /dev/null @@ -1,9843 +0,0 @@ -.reader_pdf_page { - position: relative; - display: flex; - justify-content: center; - background: #fff; - width: 100%; - overflow: hidden; - border-bottom: 4px solid #262628 -} - -.reader_pdf_page:last-child { - border: 0 -} - -.reader_pdf_page .wr_selection { - position: absolute; - z-index: 3; - background: rgba(0,151,255,.15) -} - -.reader_pdf_page_loading { - position: absolute; - height: 80px; - top: 50% -} - -.reader_pdf_page_loading .wr_loading { - left: 50% -} - -.reader_pdf_page_canvasWrapper { - margin: 0 auto; - position: relative; - z-index: 2 -} - -.reader_pdf_page_textLayer { - position: absolute; - top: 0; - bottom: 0; - overflow: hidden; - line-height: 1; - opacity: .2; - z-index: 1 -} - -.reader_pdf_page_textLayer span { - color: transparent; - position: absolute; - white-space: pre; - transform-origin: 0 0 -} - -.reader_pdf_tool { - position: fixed; - bottom: 30px; - left: 0; - right: 0; - height: auto; - display: flex; - justify-content: center; - z-index: 3 -} - -.reader_pdf_tool_content { - padding: 10px 18px; - background: #424242; - border-radius: 4px; - display: flex; - font-size: 14px -} - -.reader_pdf_tool_content_pageCount { - line-height: 24px; - margin-left: 6px -} - -.reader_pdf_tool_content_navigator { - display: flex; - justify-content: center -} - -.reader_pdf_tool_content_navigator_input { - width: 48px; - height: 24px; - background: #616161; - text-align: center; - line-height: 24px; - color: #fff; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - border-radius: 0 -} - -.reader_pdf_tool_content_navigator_btn { - height: 24px; - width: 24px; - background: #616161; - color: #fff; - display: flex; - justify-content: center; - flex-direction: column; - align-items: center -} - -.reader_pdf_tool_content_navigator_btn_icon { - width: 12px; - height: 12px; - margin: 0 auto; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_outline_arrow.7fcf8483.png); - background-size: 100% -} - -.reader_pdf_tool_content_navigator_btn_icon_back { - transform: rotate(180deg) -} - -.reader_pdf_tool_content_navigator_disabled { - cursor: not-allowed -} - -.reader_pdf_tool_content_navigator_disabled .reader_pdf_tool_content_navigator_btn_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_outline_arrow_disable.e4f7e340.png) -} - -.reader_pdf_tool_content_navigator_back { - border-radius: 4px 0 0 4px; - margin-right: 1px -} - -.reader_pdf_tool_content_navigator_forward { - border-radius: 0 4px 4px 0; - margin-left: 1px -} - -.readerCatalog_bookInfo { - cursor: pointer; - display: flex; - padding-top: 24px -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo { - padding-top:8px - } -} - -.readerCatalog_bookInfo_cover { - width: 64px; - height: 92px; - margin-right: 20px; - flex: none -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo_cover { - display:none - } -} - -.readerCatalog_bookInfo_right { - flex: auto; - padding-top: 2px; - display: flex; - flex-direction: column; - justify-content: center -} - -.readerCatalog_bookInfo_title { - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 18px; - color: #eef0f4 -} - -.wr_whiteTheme .readerCatalog_bookInfo_title { - color: #212832 -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo_title { - font-size:16px - } -} - -.readerCatalog_bookInfo_title_txt { - vertical-align: middle -} - -.readerCatalog_bookInfo_title_arrow { - display: none; - width: 7px; - height: 11px; - vertical-align: middle; - margin-left: 4px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray.0cf9af2a.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_bookInfo_title_arrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_2x.6197cb85.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_bookInfo_title_arrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_3x.7d0708bf.png) - } -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo_title_arrow { - display:inline-block - } -} - -.readerCatalog_bookInfo_author { - margin-top: 7px; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 14px; - color: #b2b4b8 -} - -.wr_whiteTheme .readerCatalog_bookInfo_author { - color: #5d646e -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo_author { - font-size:12px - } -} - -.readerCatalog_bookInfo_updateTime { - margin-top: 6px; - font-size: 14px; - color: #8a8c90 -} - -.wr_whiteTheme .readerCatalog_bookInfo_updateTime { - color: #858c96 -} - -.reader_pdf_outline { - position: fixed; - background-color: #262628; - width: 520px; - left: 50%; - top: 0; - bottom: 0; - z-index: 90; - margin-left: -20px; - box-shadow: -20px 0 20px 0 rgba(0,0,0,.1); - display: flex; - flex-direction: column -} - -.wr_whiteTheme .reader_pdf_outline { - background-color: #f4f5f7 -} - -@media(max-width: 1365px) { - .reader_pdf_outline { - margin-left:-140px - } -} - -@media(max-width: 1023px) { - .reader_pdf_outline { - width:560px; - margin-left: -280px - } -} - -@media(max-width: 767px) { - .reader_pdf_outline { - width:100%; - margin-left: 0; - left: 0; - right: 0; - top: 88px; - bottom: 56px - } -} - -.reader_pdf_outline_actions { - flex: none; - padding-left: 36px; - padding-right: 36px -} - -@media(max-width: 767px) { - .reader_pdf_outline_actions { - padding-left:20px; - padding-right: 20px - } -} - -.reader_pdf_outline_actions .reader_pdf_outline_actions_inner { - height: 40px; - text-align: right; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .reader_pdf_outline_actions .reader_pdf_outline_actions_inner { - position:relative; - border: 0 - } - - .reader_pdf_outline_actions .reader_pdf_outline_actions_inner:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .reader_pdf_outline_actions .reader_pdf_outline_actions_inner:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .reader_pdf_outline_actions .reader_pdf_outline_actions_inner { - border-color: rgba(13,20,30,.05) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .reader_pdf_outline_actions .reader_pdf_outline_actions_inner:after { - border-color:rgba(13,20,30,.05) - } -} - -.reader_pdf_outline_actions .reader_pdf_outline_actions_inner.empty { - height: 24px -} - -.reader_pdf_outline_actions .reader_pdf_outline_scroller { - display: inline-block; - width: 16px; - height: 100%; - cursor: pointer; - opacity: .7; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll.89206a73.png) no-repeat; - background-size: 16px 13px; - background-position: 50% 50%; - transition: transform .3s ease-in-out; - transform: rotate(0) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .reader_pdf_outline_actions .reader_pdf_outline_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_2x.f679a88b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .reader_pdf_outline_actions .reader_pdf_outline_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_3x.6349030e.png) - } -} - -.wr_whiteTheme .reader_pdf_outline_actions .reader_pdf_outline_scroller { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white.ffe99b7d.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .reader_pdf_outline_actions .reader_pdf_outline_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white_2x.e4aa6bb3.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .reader_pdf_outline_actions .reader_pdf_outline_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white_3x.a0ed9715.png) - } -} - -.reader_pdf_outline_actions .reader_pdf_outline_scroller:hover { - opacity: 1 -} - -.reader_pdf_outline_actions .reader_pdf_outline_scroller.rotate { - transform: rotate(180deg) -} - -.reader_pdf_outline_list { - flex: auto; - overflow: auto; - padding-bottom: env(safe-area-inset-bottom) -} - -.outlineItem { - height: 52px; - line-height: 52px; - padding-left: 36px; - padding-right: 36px -} - -@media(max-width: 767px) { - .outlineItem { - padding-left:20px; - padding-right: 20px - } -} - -.outlineItem:hover { - background: rgba(52,167,255,.07) -} - -.outlineItem:hover .outlineItem_text { - color: #eef0f4 -} - -.wr_whiteTheme .outlineItem:hover { - background: rgba(52,167,255,.07) -} - -.wr_whiteTheme .outlineItem:hover .outlineItem_text { - color: #0d141e -} - -.outlineItem .outlineItem_link { - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .outlineItem .outlineItem_link { - position:relative; - border: 0 - } - - .outlineItem .outlineItem_link:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .outlineItem .outlineItem_link:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .outlineItem .outlineItem_link { - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .outlineItem .outlineItem_link { - position:relative; - border: 0 - } - - .wr_whiteTheme .outlineItem .outlineItem_link:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .outlineItem .outlineItem_link:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.outlineItem .outlineItem_text { - color: #b2b4b8; - font-size: 15px -} - -.wr_whiteTheme .outlineItem .outlineItem_text { - color: #353c46 -} - -.outlineItem .outlineItem_title { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal; - flex: 1 -} - -.outlineItem.outlineItem_current .outlineItem_text { - color: #0097ff -} - -.wr_whiteTheme .outlineItem.outlineItem_current .outlineItem_text { - color: #1b88ee -} - -.outlineItem_level2 { - padding-left: 15px -} - -.outlineItem_level3 { - padding-left: 30px -} - -.reader_pdfViewer { - position: relative; - padding-top: 72px; - width: 100%; - margin: 0 auto; - overflow: auto -} - -@media(max-width: 767px) { - .reader_pdfViewer { - padding-top:0 - } -} - -.reader_pdfViewer .wr_selection { - position: absolute; - z-index: 4; - background: rgba(0,151,255,.15) -} - -.reader_pdfViewer_support { - position: absolute; - text-align: center; - font-size: 18px; - top: 30%; - left: 0; - right: 0; - color: #eef0f4 -} - -.wr_whiteTheme .reader_pdfViewer_support { - color: #212832 -} - -.reader_pdfViewer_loading { - width: 100%; - padding-top: 30%; - display: flex; - justify-content: center -} - -.reader_pdfViewer_loading_percent { - font-family: DIN-Regular,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 20px; - line-height: 36px; - color: #fff -} - -.wr_whiteTheme .reader_pdfViewer_loading_percent { - color: #0d141e -} - -.reader_pdfViewer_loading_loader { - position: relative; - height: 36px; - width: 36px -} - -.reader_pdfViewer_loading .wr_loading { - left: 50%; - top: 15px -} - -.reader_pdfViewer_error { - text-align: center; - font-size: 16px; - padding-top: 30%; - color: #eef0f4 -} - -.wr_whiteTheme .reader_pdfViewer_error { - color: #212832 -} - -.reader_pdfViewer_error .retry { - color: #4a7ab0 -} - -.fontSizeSliderContainer .vue-slider { - cursor: pointer -} - -.fontSizeSliderContainer .vue-slider-disabled { - opacity: .7 -} - -.fontSizeSliderContainer .vue-slider-rail { - height: 2px; - background-color: #626468 -} - -.wr_whiteTheme .fontSizeSliderContainer .vue-slider-rail { - background-color: #c4c8d0 -} - -.fontSizeSliderContainer .vue-slider-process { - background-color: #626468; - display: none -} - -.wr_whiteTheme .fontSizeSliderContainer .vue-slider-process { - background-color: #c4c8d0 -} - -.fontSizeSliderContainer .vue-slider-mark { - z-index: 4 -} - -.fontSizeSliderContainer .vue-slider-ltr .vue-slider-mark { - transform: none -} - -.fontSizeSliderContainer .vue-slider-ltr .vue-slider-mark,.fontSizeSliderContainer .vue-slider-rtl .vue-slider-mark { - top: 0 -} - -.fontSizeSliderContainer .vue-slider-mark-step { - width: 4px; - height: 4px; - border-radius: 2px; - background-color: #626468 -} - -.wr_whiteTheme .fontSizeSliderContainer .vue-slider-mark-step { - background-color: #c4c8d0 -} - -.fontSizeSliderContainer .vue-slider-ltr .vue-slider-mark-step,.fontSizeSliderContainer .vue-slider-rtl .vue-slider-mark-step { - top: -1px; - left: -2px -} - -.fontSizeSliderContainer .vue-slider-mark-label { - font-size: 14px; - white-space: nowrap -} - -.fontSizeSliderContainer .vue-slider-dot-handle { - cursor: pointer; - width: 100%; - height: 100%; - border-radius: 50%; - background-color: #fff; - box-sizing: border-box; - box-shadow: .5px .5px 2px 1px rgba(0,0,0,.32) -} - -.fontSizeSliderContainer .vue-slider-dot-handle-focus { - box-shadow: 0 0 1px 2px rgba(52,152,219,.36) -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner { - font-size: 14px; - white-space: nowrap; - padding: 2px 5px; - min-width: 20px; - text-align: center; - color: #fff; - border-radius: 5px; - border-color: #3498db; - background-color: #3498db; - box-sizing: content-box -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner:after { - content: ""; - position: absolute -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner-top:after { - top: 100%; - left: 50%; - transform: translate(-50%); - height: 0; - width: 0; - border: 5px solid transparent; - border-top-color: inherit -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner-bottom:after { - bottom: 100%; - left: 50%; - transform: translate(-50%); - height: 0; - width: 0; - border: 5px solid transparent; - border-bottom-color: inherit -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner-left:after { - left: 100%; - top: 50%; - transform: translateY(-50%); - height: 0; - width: 0; - border: 5px solid transparent; - border-left-color: inherit -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-inner-right:after { - right: 100%; - top: 50%; - transform: translateY(-50%); - height: 0; - width: 0; - border: 5px solid transparent; - border-right-color: inherit -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-wrapper { - opacity: 0; - transition: all .3s -} - -.fontSizeSliderContainer .vue-slider-dot-tooltip-wrapper-show { - opacity: 1 -} - -.readerControls { - display: flex; - flex-direction: column; - align-items: flex-start -} - -@media(max-width: 1000px),(min-width:1023px)and (max-width:1251px),(min-width:1365px)and (max-width:1525px) { - .readerControls { - align-items:flex-end - } -} - -.readerControls_fontSize,.readerControls_item { - width: 48px; - height: 48px; - background-color: #1c1c1d; - transition: background-color .2s ease-in-out; - border-radius: 24px; - line-height: 48px; - text-align: center; - position: relative -} - -.wr_whiteTheme .readerControls_fontSize,.wr_whiteTheme .readerControls_item { - background-color: #fff; - box-shadow: 0 8px 32px rgba(0,25,104,.1) -} - -.readerControls_fontSize:not(:first-child),.readerControls_item:not(:first-child) { - margin-top: 24px -} - -.readerControls_fontSize.disabled,.readerControls_item.disabled { - cursor: auto -} - -.readerControls_fontSize:hover .icon,.readerControls_item:hover .icon { - opacity: 1 -} - -.readerControls_fontSize:hover .fontSizeLabel .icon,.readerControls_item:hover .fontSizeLabel .icon { - opacity: .7 -} - -.readerControls_fontSize.disabled .icon,.readerControls_item.disabled .icon { - opacity: .3 -} - -.readerControls_fontSize { - display: flex; - flex-direction: row; - align-items: center; - transition: background-color .2s ease-in-out,width .15s ease-in-out; - overflow: hidden -} - -@media(max-width: 1000px),(min-width:1023px)and (max-width:1251px),(min-width:1365px)and (max-width:1525px) { - .readerControls_fontSize { - justify-content:flex-end - } -} - -.readerControls_fontSize .fontSizeButton { - flex-shrink: 0; - width: 48px; - height: 48px; - position: relative -} - -.readerControls_fontSize .fontSizeButton .icon { - position: absolute; - left: 50%; - top: 50%; - margin-top: -12px; - margin-left: -12px -} - -.readerControls_fontSize .fontSizeLabel { - display: none; - flex-shrink: 0; - width: 32px; - height: 48px; - position: relative -} - -.readerControls_fontSize .fontSizeLabel .iconLeft { - position: absolute; - left: 50%; - top: 50%; - margin-top: -12px; - margin-left: -12px -} - -.readerControls_fontSize .fontSizeLabel.left { - margin-left: 8px -} - -.readerControls_fontSize .fontSizeLabel.left .iconLeft { - position: absolute; - left: 50%; - top: 50%; - width: 32px; - height: 32px; - margin-top: -16px; - margin-left: -16px; - background-size: 100% 100% -} - -.readerControls_fontSize .fontSizeLabel.right { - margin-right: 8px -} - -.readerControls_fontSize .fontSizeLabel.right .iconRight { - position: absolute; - left: 50%; - top: 50%; - width: 32px; - height: 32px; - margin-top: -15px; - margin-left: -16px; - background-size: 100% 100% -} - -.readerControls_fontSize .fontSizeSliderContainer { - margin-left: 2px; - margin-right: 2px; - flex: auto; - display: none; - opacity: 0; - transition: opacity .15s ease-in-out -} - -@media(max-width: 1000px),(min-width:1023px)and (max-width:1251px),(min-width:1365px)and (max-width:1525px) { - .readerControls_fontSize .fontSizeSliderContainer { - margin-left:2px; - margin-right: 2px - } -} - -.readerControls_fontSize .fontSizeSliderContainer .vue-slider { - width: 100% -} - -.readerControls_fontSize.expand { - width: 200px -} - -.readerControls_fontSize.expand .fontSizeButton { - display: none -} - -.readerControls_fontSize.expand .fontSizeLabel { - display: block -} - -.readerControls_fontSize.expand .fontSizeSliderContainer { - display: block; - opacity: 1; - transition-delay: .1s -} - -.readerControls .icon { - width: 24px; - height: 24px; - opacity: .7; - background-size: 100%; - background-repeat: no-repeat; - position: absolute; - left: 50%; - top: 50%; - margin-top: -12px; - margin-left: -12px; - transition: background-image .2s ease-in-out -} - -.readerControls .catalog .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog.d979a697.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog_2x.55959afe.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog_3x.f86324d8.png) - } -} - -.wr_whiteTheme .readerControls .catalog .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog_white.41c2a65a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog_white_2x.019e22ae.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_catalog_white_3x.41973872.png) - } -} - -.readerControls .note .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note.9f62cdad.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .note .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note_2x.be9bab79.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .note .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note_3x.e9caa45e.png) - } -} - -.wr_whiteTheme .readerControls .note .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note_white.ab2151c4.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .note .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note_white_2x.e43d0049.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .note .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_note_white_3x.d38fa60e.png) - } -} - -.readerControls .lecture .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture_dark.0e593f22.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .lecture .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture_dark_2x.7ebabe28.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .lecture .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture_dark_3x.17c0ed91.png) - } -} - -.wr_whiteTheme .readerControls .lecture .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture.caa56f92.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .lecture .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture_2x.704b5db2.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .lecture .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_reading_lecture_3x.d98fb436.png) - } -} - -.readerControls .fontSizeButton .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize.36ea6817.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .fontSizeButton .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_2x.1ffb37ce.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .fontSizeButton .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_3x.a9e356e5.png) - } -} - -.wr_whiteTheme .readerControls .fontSizeButton .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_white.bbadcbc0.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .fontSizeButton .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_white_2x.ae5aaf9b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .fontSizeButton .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_white_3x.c20d7e2a.png) - } -} - -.readerControls .fontSizeLabel .iconLeft { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left.9f194ae6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .fontSizeLabel .iconLeft { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left_2x.21a8b36a.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .fontSizeLabel .iconLeft { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left_3x.cb5c9d7b.png) - } -} - -.wr_whiteTheme .readerControls .fontSizeLabel .iconLeft { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left_white.87374ddf.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .fontSizeLabel .iconLeft { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left_white_2x.ec2c7ba6.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .fontSizeLabel .iconLeft { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_left_white_3x.5483a257.png) - } -} - -.readerControls .fontSizeLabel .iconRight { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right.bbcf299a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .fontSizeLabel .iconRight { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right_2x.ff549bfa.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .fontSizeLabel .iconRight { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right_3x.9de45d92.png) - } -} - -.wr_whiteTheme .readerControls .fontSizeLabel .iconRight { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right_white.956f16ab.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .fontSizeLabel .iconRight { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right_white_2x.74cebbd6.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .fontSizeLabel .iconRight { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_fontsize_right_white_3x.d728aab0.png) - } -} - -.readerControls .dark .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark.89cac7cf.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .dark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark_2x.58422959.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .dark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark_3x.0032238f.png) - } -} - -.wr_whiteTheme .readerControls .dark .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark_white.213c07c7.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .dark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark_white_2x.1e6909a4.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .dark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_dark_white_3x.6e69f900.png) - } -} - -.readerControls .white .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white.1b920230.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .white .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white_2x.7d97980c.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .white .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white_3x.cb46acef.png) - } -} - -.wr_whiteTheme .readerControls .white .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white_white.e1cd3c00.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .white .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white_white_2x.0eca1411.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .white .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_white_white_3x.565263f0.png) - } -} - -.readerControls .download .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download.d28cc221.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerControls .download .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download_2x.45c2eb45.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerControls .download .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download_3x.c26c759c.png) - } -} - -.wr_whiteTheme .readerControls .download .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download_white.cec57638.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerControls .download .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download_white_2x.f99f127c.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerControls .download .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_control_download_white_3x.82ae6e2c.png) - } -} - -.readerControls_catalog_hint { - position: absolute; - top: 3px; - left: 64px; - font-size: 14px; - color: #eef0f4; - background: linear-gradient(90deg,#0087fc,#28b7ff); - border-radius: 3px; - padding: 10px 12px; - white-space: nowrap -} - -.readerControls_catalog_hint:after { - display: inline-block; - content: ""; - position: absolute; - width: 0; - height: 0; - top: 11px; - left: -16px; - border: 8px solid transparent; - border-right-color: #0087fc -} - -@media(max-width: 1000px),(min-width:1023px)and (max-width:1251px),(min-width:1365px)and (max-width:1525px) { - .readerControls_catalog_hint { - left:auto; - right: 64px - } - - .readerControls_catalog_hint:after { - left: auto; - right: -16px; - border-right-color: transparent; - border-left-color: #28b7ff - } -} - -.sectionListItem_title { - word-break: break-all; - font-size: 16px; - color: #eef0f4; - margin: 16px 36px 4px -} - -.wr_whiteTheme .sectionListItem_title { - color: #0d141e -} - -@media(max-width: 767px) { - .sectionListItem_title { - margin-left:20px; - margin-right: 20px - } -} - -.sectionListItem_divider { - margin-left: 36px; - margin-right: 36px; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0 -} - -@media(max-width: 767px) { - .sectionListItem_divider { - margin-left:20px; - margin-right: 20px - } -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .sectionListItem_divider { - position:relative; - border: 0 - } - - .sectionListItem_divider:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .sectionListItem_divider:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .sectionListItem_divider { - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .sectionListItem_divider { - position:relative; - border: 0 - } - - .wr_whiteTheme .sectionListItem_divider:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .sectionListItem_divider:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.sectionListItem_divider.leftIndent { - margin-left: 72px -} - -@media(max-width: 767px) { - .sectionListItem_divider.leftIndent { - margin-left:56px - } -} - -.sectionListItem_content { - display: block; - padding: 18px 36px; - word-break: break-all; - font-size: 15px; - line-height: 24px; - color: #b2b4b8; - cursor: default -} - -@media(max-width: 767px) { - .sectionListItem_content { - padding-left:20px; - padding-right: 20px - } -} - -.wr_whiteTheme .sectionListItem_content { - color: #5d646e -} - -.sectionListItem_content.clickable { - cursor: pointer -} - -.sectionListItem_content.clickable:hover { - background: rgba(52,167,255,.07); - color: #eef0f4 -} - -.wr_whiteTheme .sectionListItem_content.clickable:hover { - color: #212832; - background: rgba(52,167,255,.07) -} - -.panelListEmptyView { - height: 100%; - line-height: 80px; - text-align: center; - font-size: 16px; - display: flex; - color: #b2b4b8 -} - -.wr_whiteTheme .panelListEmptyView { - color: #5d646e -} - -.panelListEmptyView_content { - margin: auto -} - -.panelListLoadingView { - position: relative; - height: 80px -} - -.panelListLoadingView .wr_loading { - left: 50%; - top: 40% -} - -.cancel_auto_pay_dialog_wrapper { - border-radius: 16px; - max-width: 360px; - width: 80%; - text-align: left -} - -.cancel_auto_pay_dialog { - position: relative; - padding: 28px 24px 31px; - box-sizing: border-box; - width: 100% -} - -.cap_dialog_title { - font-size: 20px; - font-weight: 500; - color: #eef0f4; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal; - text-align: center; - line-height: 24px; - margin-bottom: 11px -} - -.wr_whiteTheme .cap_dialog_title { - color: #212832 -} - -@media(max-width: 468px) { - .cap_dialog_title { - padding-left:16px; - padding-right: 16px - } -} - -.cap_dialog_content { - margin-top: 3px; - font-size: 16px; - line-height: 22px; - color: #8a8c90; - text-align: center -} - -.wr_whiteTheme .cap_dialog_content { - color: #858c96 -} - -.cap_dialog_action { - height: 58px; - background: linear-gradient(90deg,#0087fc,#00a3f5); - border-radius: 0 0 16px 16px; - display: flex; - flex-direction: row; - justify-content: center -} - -.cap_dialog_action_item { - flex: 1; - height: 58px; - line-height: 58px; - font-size: 17px; - font-weight: 500; - color: #fff; - text-align: center -} - -.readerCatalog { - position: fixed; - background-color: #262628; - width: 520px; - left: 50%; - top: 0; - bottom: 0; - z-index: 90; - margin-left: -20px; - box-shadow: -20px 0 20px 0 rgba(0,0,0,.1); - display: flex; - flex-direction: column -} - -.wr_whiteTheme .readerCatalog { - background-color: #f4f5f7 -} - -@media(max-width: 1365px) { - .readerCatalog { - margin-left:-140px - } -} - -@media(max-width: 1023px) { - .readerCatalog { - width:560px; - margin-left: -280px - } -} - -@media(max-width: 767px) { - .readerCatalog { - width:100%; - margin-left: 0; - left: 0; - right: 0; - top: 88px; - bottom: 56px - } -} - -.readerCatalog_searchBar { - flex-shrink: 0; - height: 36px; - line-height: 36px; - margin: 18px 36px; - display: flex -} - -@media(max-width: 767px) { - .readerCatalog_searchBar { - margin-left:20px; - margin-right: 20px - } -} - -.readerCatalog_searchBar_left { - height: 36px; - flex: auto; - border-radius: 20px; - padding: 0 38px; - box-sizing: border-box; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_search.5731b0d1.png) no-repeat; - background-size: 100%; - background-repeat: no-repeat; - background-color: rgba(246,246,249,.1); - background-size: 20px 20px; - background-position: 10px 9px; - position: relative -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_searchBar_left { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_search_2x.ebebd7c2.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_searchBar_left { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_search_3x.a44561c9.png) - } -} - -.wr_whiteTheme .readerCatalog_searchBar_left { - background-color: #f6f7f9 -} - -.readerCatalog_searchBar_left input { - width: 100%; - height: 100%; - background: none; - color: #fff; - font-size: 13px -} - -.wr_whiteTheme .readerCatalog_searchBar_left input { - color: #0d141e -} - -.readerCatalog_searchBar_left input::-moz-placeholder { - color: #8a8c90 -} - -.readerCatalog_searchBar_left input:-ms-input-placeholder { - color: #8a8c90 -} - -.readerCatalog_searchBar_left input::-ms-input-placeholder { - color: #8a8c90 -} - -.readerCatalog_searchBar_left input::placeholder { - color: #8a8c90 -} - -.wr_whiteTheme .readerCatalog_searchBar_left input::-moz-placeholder { - color: #858c96 -} - -.wr_whiteTheme .readerCatalog_searchBar_left input:-ms-input-placeholder { - color: #858c96 -} - -.wr_whiteTheme .readerCatalog_searchBar_left input::-ms-input-placeholder { - color: #858c96 -} - -.wr_whiteTheme .readerCatalog_searchBar_left input::placeholder { - color: #858c96 -} - -.readerCatalog_searchBar_enter { - position: absolute; - width: 36px; - height: 100%; - right: 0; - top: 0; - cursor: pointer; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter.42668817.png) no-repeat; - background-size: 20px 20px; - background-position: 50% 50% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_searchBar_enter { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter_2x.5a530e50.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_searchBar_enter { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter_3x.3b190a6d.png) - } -} - -.wr_whiteTheme .readerCatalog_searchBar_enter { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter_white.0b6b5120.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerCatalog_searchBar_enter { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter_white_2x.d428191f.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerCatalog_searchBar_enter { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_search_enter_white_3x.fd3fe232.png) - } -} - -.readerCatalog_searchCancel { - flex: none; - font-size: 16px; - color: #eef0f4; - margin-left: 16px; - cursor: pointer -} - -.wr_whiteTheme .readerCatalog_searchCancel { - color: #212832 -} - -.readerCatalog_bookInfo { - flex: none; - padding-left: 36px; - padding-right: 36px -} - -@media(max-width: 767px) { - .readerCatalog_bookInfo { - padding-left:20px; - padding-right: 20px - } -} - -.readerCatalog_actions { - flex: none; - padding-left: 36px; - padding-right: 36px -} - -@media(max-width: 767px) { - .readerCatalog_actions { - padding-left:20px; - padding-right: 20px - } -} - -.readerCatalog_actions .readerCatalog_actions_inner { - display: flex; - flex-direction: row; - justify-content: end; - align-items: center; - height: 40px; - text-align: right; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_actions .readerCatalog_actions_inner { - position:relative; - border: 0 - } - - .readerCatalog_actions .readerCatalog_actions_inner:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_actions .readerCatalog_actions_inner:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .readerCatalog_actions .readerCatalog_actions_inner { - border-color: rgba(13,20,30,.05) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerCatalog_actions .readerCatalog_actions_inner:after { - border-color:rgba(13,20,30,.05) - } -} - -.readerCatalog_actions .readerCatalog_actions_inner.empty { - height: 24px -} - -.readerCatalog_actions .readerCatalog_scroller { - display: inline-block; - width: 16px; - height: 100%; - cursor: pointer; - opacity: .7; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll.89206a73.png) no-repeat; - background-size: 16px 13px; - background-position: 50% 50%; - transition: transform .3s ease-in-out; - transform: rotate(0) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_actions .readerCatalog_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_2x.f679a88b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_actions .readerCatalog_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_3x.6349030e.png) - } -} - -.wr_whiteTheme .readerCatalog_actions .readerCatalog_scroller { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white.ffe99b7d.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerCatalog_actions .readerCatalog_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white_2x.e4aa6bb3.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerCatalog_actions .readerCatalog_scroller { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_scroll_white_3x.a0ed9715.png) - } -} - -.readerCatalog_actions .readerCatalog_scroller:hover { - opacity: 1 -} - -.readerCatalog_actions .readerCatalog_scroller.rotate { - transform: rotate(180deg) -} - -.readerCatalog_actions_inner_autoPay { - display: inline-flex; - flex-direction: row; - align-items: center; - font-size: 14px; - font-weight: 500; - margin-right: 14px; - color: #8a8c90 -} - -.wr_whiteTheme .readerCatalog_actions_inner_autoPay { - color: #858c96 -} - -.readerCatalog_actions_inner_autoPay:hover { - color: #eef0f4 -} - -.wr_whiteTheme .readerCatalog_actions_inner_autoPay:hover { - color: #212832 -} - -.readerCatalog_actions_inner_autoPay_icon { - display: inline-block; - margin-right: 2px; - height: 12px; - width: 12px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked.d3288c1a.png) no-repeat; - background-size: 12px 12px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerCatalog_actions_inner_autoPay_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked_2x.aa8c3454.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerCatalog_actions_inner_autoPay_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked_3x.d425337d.png) - } -} - -.readerCatalog_list { - flex: auto; - overflow: auto; - padding-bottom: env(safe-area-inset-bottom) -} - -.chapterItem { - height: 52px; - line-height: 52px; - padding-left: 36px; - padding-right: 36px -} - -@media(max-width: 767px) { - .chapterItem { - padding-left:20px; - padding-right: 20px - } -} - -.chapterItem:hover { - background: rgba(52,167,255,.07) -} - -.chapterItem:hover .chapterItem_text { - color: #eef0f4 -} - -.wr_whiteTheme .chapterItem:hover { - background: rgba(52,167,255,.07) -} - -.wr_whiteTheme .chapterItem:hover .chapterItem_text { - color: #0d141e -} - -.chapterItem .chapterItem_link { - cursor: pointer; - display: flex; - justify-content: space-between; - align-items: center; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .chapterItem .chapterItem_link { - position:relative; - border: 0 - } - - .chapterItem .chapterItem_link:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .chapterItem .chapterItem_link:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .chapterItem .chapterItem_link { - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .chapterItem .chapterItem_link { - position:relative; - border: 0 - } - - .wr_whiteTheme .chapterItem .chapterItem_link:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .chapterItem .chapterItem_link:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.chapterItem .chapterItem_text { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal; - color: #b2b4b8; - font-size: 15px -} - -.wr_whiteTheme .chapterItem .chapterItem_text { - color: #353c46 -} - -.chapterItem.chapterItem_disabled .chapterItem_text { - color: #8a8c90 -} - -.wr_whiteTheme .chapterItem.chapterItem_disabled .chapterItem_text { - color: #858c96 -} - -.chapterItem.chapterItem_current .chapterItem_text { - color: #0097ff -} - -.wr_whiteTheme .chapterItem.chapterItem_current .chapterItem_text { - color: #1b88ee -} - -.chapterItem_level2 { - padding-left: 15px -} - -.chapterItem_level3 { - padding-left: 30px -} - -.chapterItem_level4 { - padding-left: 45px -} - -.chapterItem_lock { - flex: none; - width: 14px; - height: 16px; - margin-left: 16px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_lock.ca205906.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .chapterItem_lock { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_lock_2x.58eceac9.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .chapterItem_lock { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_catalog_lock_3x.c4404e29.png) - } -} - -.rc_search { - flex: auto; - overflow: auto; - padding-bottom: env(safe-area-inset-bottom) -} - -.rc_search .sectionListItem:first-child { - margin-top: 30px -} - -.rc_search_itemContent .highLight { - font-style: normal; - color: #0097ff -} - -.wr_whiteTheme .rc_search_itemContent .highLight { - color: #1b88ee -} - -.readerTopBar { - box-sizing: border-box; - position: fixed; - align-items: center; - justify-content: space-between; - display: flex; - width: 100%; - height: 72px; - max-width: 1000px; - margin-left: auto; - margin-right: auto; - z-index: 80; - border-bottom: 1px solid rgba(238,240,244,.1); - background-color: #1c1c1d; - transition: background-color .2s ease-in-out; - padding: 0 16px -} - -@media(max-width: 1365px) { - .readerTopBar { - max-width:760px - } -} - -@media(max-width: 1023px) { - .readerTopBar { - max-width:560px - } -} - -@media(max-width: 767px) { - .readerTopBar { - max-width:100% - } -} - -.wr_whiteTheme .readerTopBar { - border-bottom-color: rgba(33,40,50,.1); - background-color: #fff -} - -.readerTopBar_home { - flex: none; - width: 48px; - height: 48px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home.0edbfdf6.png); - background-repeat: no-repeat; - background-position: 50% 50%; - background-size: 20px 20px; - text-indent: -999em -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar_home { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_2x.8df88c9f.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar_home { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_3x.7c675692.png) - } -} - -.wr_whiteTheme .readerTopBar_home { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_white.580a9946.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopBar_home { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_white_2x.68a99e47.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerTopBar_home { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_white_3x.50c518fd.png) - } -} - -.readerTopBar_home:hover { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_hover.1d452d39.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar_home:hover { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_hover_2x.7b6031c5.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar_home:hover { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_home_hover_3x.5dbb982c.png) - } -} - -.readerTopBar_title { - flex: auto; - margin-left: 36px; - margin-right: 32px; - font-size: 16px; - font-weight: 500; - line-height: 16px; - overflow: hidden; - height: 16px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical -} - -@media(max-width: 1365px) { - .readerTopBar_title { - margin-left:8px - } -} - -@media(max-width: 1023px) { - .readerTopBar_title { - margin-left:0 - } -} - -.readerTopBar_title .readerTopBar_title_link { - cursor: pointer; - color: #fff; - opacity: .7 -} - -.wr_whiteTheme .readerTopBar_title .readerTopBar_title_link { - color: #0d141e -} - -.readerTopBar_title .readerTopBar_title_link:hover { - opacity: 1 -} - -.readerTopBar_title .readerTopBar_title_chapter { - color: #fff; - opacity: .7 -} - -.wr_whiteTheme .readerTopBar_title .readerTopBar_title_chapter { - color: #0d141e -} - -.readerTopBar_switcher_icon { - width: 24px; - height: 24px; - margin-right: 6px -} - -.readerTopBar_switcher_icon_pdf { - background-size: 24px 24px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_dark.992c1539.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar_switcher_icon_pdf { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_dark_2x.28413f22.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar_switcher_icon_pdf { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_dark_3x.8fb582ed.png) - } -} - -.wr_whiteTheme .readerTopBar_switcher_icon_pdf { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_bright.7619aa63.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopBar_switcher_icon_pdf { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_bright_2x.a75dacab.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerTopBar_switcher_icon_pdf { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_pdf_bright_3x.33dee82d.png) - } -} - -.readerTopBar_switcher_icon_epub { - background-size: 24px 24px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_dark.73bf2956.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar_switcher_icon_epub { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_dark_2x.a0f9dc6f.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar_switcher_icon_epub { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_dark_3x.2f7c09d5.png) - } -} - -.wr_whiteTheme .readerTopBar_switcher_icon_epub { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_bright.b6b45ff5.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopBar_switcher_icon_epub { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_bright_2x.4fab4f82.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerTopBar_switcher_icon_epub { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_ebook_bright_3x.435fdd71.png) - } -} - -.readerTopBar_switcher { - flex-shrink: 0; - font-size: 16px; - font-weight: 500; - color: #fff; - opacity: .7; - display: flex; - align-items: center; - flex-direction: row; - flex-wrap: nowrap -} - -.wr_whiteTheme .readerTopBar_switcher { - color: #0d141e -} - -.readerTopBar_switcher:hover { - opacity: 1 -} - -.readerTopBar .readerTopBar_title_chapter { - color: #fff; - opacity: .7 -} - -.wr_whiteTheme .readerTopBar .readerTopBar_title_chapter { - color: #0d141e -} - -.readerTopBar .readerTopBar_actions { - flex: none -} - -.readerTopBar .readerTopBar_right { - width: 100px; - display: flex; - flex-direction: row; - justify-content: flex-end -} - -@media(max-width: 1365px) { - .readerTopBar .readerTopBar_right { - width:auto; - flex: none; - min-width: 24px - } -} - -.readerTopBar .readerTopBar_right .actionItem,.readerTopBar .readerTopBar_right .readerTopBar_avatar { - margin-left: 24px; - margin-right: 24px -} - -.readerTopBar .actionItem { - display: inline-block; - margin-left: 24px; - font-size: 16px; - font-weight: 500; - color: #fff; - opacity: .7 -} - -.wr_whiteTheme .readerTopBar .actionItem { - color: #0d141e -} - -.readerTopBar .actionItem:hover { - opacity: 1 -} - -.readerTopBar .addShelfItem { - background-position: left 50%; - background-size: 24px 24px; - background-repeat: no-repeat; - padding-left: 32px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel.ee5ab845.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar .addShelfItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel_2x.42c8b0a4.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar .addShelfItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel_3x.8385ca2c.png) - } -} - -.wr_whiteTheme .readerTopBar .addShelfItem { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel_white.537f8cb7.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopBar .addShelfItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel_white_2x.ec63683b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerTopBar .addShelfItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_cancel_white_3x.f25408d1.png) - } -} - -.readerTopBar .added { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf.e1f86368.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopBar .added { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_2x.eb4e275a.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopBar .added { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_3x.105d7ad2.png) - } -} - -.wr_whiteTheme .readerTopBar .added { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_white.49004b3f.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopBar .added { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_white_2x.44efcc87.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerTopBar .added { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_top_bookshelf_white_3x.8a5c5671.png) - } -} - -.readerTopBar .readerTopBar_avatar { - width: 28px; - height: 28px -} - -.fade-enter-active,.fade-leave-active { - transition: transform .2s ease,opacity .2s ease -} - -.fade-enter-from,.fade-leave-to { - opacity: 0; - transform: translateY(-10px) -} - -.dropdown { - cursor: pointer; - position: relative -} - -.dropdown:focus { - outline: none -} - -.disabled { - cursor: default -} - -.disabled:hover>.mark { - opacity: .5!important -} - -.dropdown:hover>.mark { - opacity: 1 -} - -.dropdown>.mark { - transition: opacity .2s ease; - opacity: .5; - display: flex; - align-items: center; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -.dropdown>.mark>div { - white-space: nowrap; - font-family: sans-serif; - font-size: 12px; - line-height: 16px -} - -.dropdown>.mark>svg { - margin-left: 3px; - margin-top: 1px -} - -.dropdown>.panel { - position: absolute; - border-radius: 6px; - overflow: hidden; - top: 24px; - left: 0; - box-sizing: border-box; - box-shadow: 0 2px 12px rgba(0,0,0,.15) -} - -.copy_code { - transition: opacity .2s ease; - position: relative; - opacity: .5; - width: 20px; - height: 20px; - cursor: pointer -} - -.copy_code:focus { - outline: none -} - -.copy_code>textarea { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - position: absolute; - padding: 0; - width: 0; - height: 0; - background: transparent; - resize: none; - opacity: 0; - border-color: transparent -} - -.copy_code>svg { - pointer-events: none -} - -.copy_code:hover { - opacity: 1 -} - -.copy_code:hover>.tooltip { - display: block -} - -.copy_code>.tooltip { - font-family: sans-serif; - display: none; - position: absolute; - bottom: -10px; - left: -96px; - font-size: 12px; - color: #fff; - width: 84px; - height: 30px; - line-height: 30px; - background: rgba(0,0,0,.8); - box-sizing: border-box; - text-align: center; - border-radius: 4px -} - -.header { - position: relative; - z-index: 2; - height: 34px; - box-sizing: border-box -} - -.header>.dropdown { - position: absolute; - top: 12px; - left: 18px -} - -.header>.copy_code { - position: absolute; - top: 10px; - right: 12px -} - -.code_editor { - display: flex; - flex-direction: column; - font-size: 0; - position: relative; - text-align: left -} - -.code_editor>.code_area { - position: relative; - overflow-x: hidden; - overflow-y: auto -} - -.code_editor>.code_area::-webkit-scrollbar { - right: 8px; - width: 8px; - box-shadow: none; - border: 0 -} - -.code_editor>.code_area::-webkit-scrollbar-track,.code_editor>.code_area::-webkit-scrollbar-track-piece { - opacity: 0 -} - -.code_editor>.code_area::-webkit-scrollbar-thumb { - border-radius: 10px; - background: rgba(0,0,0,.3) -} - -.code_editor>.code_area>.code_editor_pre>.code_editor_code,.code_editor>.code_area>.code_editor_textarea { - padding: 0 20px 20px; - font-family: Consolas,Monaco,monospace; - line-height: 1.5; - font-size: 16px -} - -.code_editor>.code_area>.code_editor_textarea { - overflow-y: hidden; - box-sizing: border-box; - caret-color: #7f7f7f; - -webkit-text-fill-color: transparent; - white-space: pre; - word-wrap: normal; - border: 0; - position: absolute; - z-index: 1; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: none; - resize: none -} - -.code_editor>.code_area>.code_editor_textarea:focus-visible,.code_editor>.code_area>.code_editor_textarea:hover { - outline: none -} - -.code_editor>.code_area>.code_editor_pre { - position: relative; - margin: 0; - padding: 0!important -} - -.code_editor>.code_area>.code_editor_pre>.code_editor_code { - position: relative; - overflow-x: visible; - border-radius: 0; - box-sizing: border-box; - display: block; - border: 0; - margin: 0 -} - -.hide_header>.code_area>.code_editor_pre>.code_editor_code,.hide_header>.code_area>.code_editor_textarea { - padding: 20px -} - -.hide_header.scroll>.code_area { - height: 100% -} - -.read_only>.code_area>.code_editor_pre>.code_editor_code { - width: 100%; - height: 100%; - overflow: auto!important -} - -.wrap_code>.code_area>.code_editor_pre>.code_editor_code,.wrap_code>.code_area>.code_editor_textarea { - white-space: pre-wrap; - word-wrap: break-word -} - -.scroll>.code_area { - height: calc(100% - 34px) -} - -.scroll>.code_area>.code_editor_textarea { - overflow: auto -} - -.scroll>.code_area>.code_editor_pre { - width: 100%; - height: 100%; - overflow: hidden -} - -.panel { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - height: 100%; - font-family: sans-serif -} - -.panel>.lang_list { - overflow: auto; - height: calc(100% - 36px); - font-size: 13px; - box-sizing: border-box; - padding: 0; - list-style: none; - margin: 0; - text-align: left; - background: #fff -} - -.panel>.lang_list>li { - font-size: 13px; - color: #333; - transition: background .16s ease,color .16s ease; - box-sizing: border-box; - padding: 0 12px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - line-height: 30px -} - -.panel>.lang_list>li:first-child { - padding-top: 5px -} - -.panel>.lang_list>li:last-child { - padding-bottom: 5px -} - -.panel>.lang_list>li:hover { - color: #111; - background: #eee -} - -.atom_one_dark.hljs,.atom_one_dark .hljs { - color: #abb2bf; - background: #282c34 -} - -.atom_one_dark .hljs-comment,.atom_one_dark .hljs-quote { - color: #5c6370; - font-style: italic -} - -.atom_one_dark .hljs-doctag,.atom_one_dark .hljs-formula,.atom_one_dark .hljs-keyword { - color: #c678dd -} - -.atom_one_dark .hljs-deletion,.atom_one_dark .hljs-name,.atom_one_dark .hljs-section,.atom_one_dark .hljs-selector-tag,.atom_one_dark .hljs-subst { - color: #e06c75 -} - -.atom_one_dark .hljs-literal { - color: #56b6c2 -} - -.atom_one_dark .hljs-addition,.atom_one_dark .hljs-attribute,.atom_one_dark .hljs-meta .hljs-string,.atom_one_dark .hljs-regexp,.atom_one_dark .hljs-string { - color: #98c379 -} - -.atom_one_dark .hljs-attr,.atom_one_dark .hljs-number,.atom_one_dark .hljs-selector-attr,.atom_one_dark .hljs-selector-class,.atom_one_dark .hljs-selector-pseudo,.atom_one_dark .hljs-template-variable,.atom_one_dark .hljs-type,.atom_one_dark .hljs-variable { - color: #d19a66 -} - -.atom_one_dark .hljs-bullet,.atom_one_dark .hljs-link,.atom_one_dark .hljs-meta,.atom_one_dark .hljs-selector-id,.atom_one_dark .hljs-symbol,.atom_one_dark .hljs-title { - color: #61aeee -} - -.atom_one_dark .hljs-built_in,.atom_one_dark .hljs-class .hljs-title,.atom_one_dark .hljs-title .class_ { - color: #e6c07b -} - -.atom_one_dark .hljs-emphasis { - font-style: italic -} - -.atom_one_dark .hljs-strong { - font-weight: 700 -} - -.atom_one_dark .hljs-link { - text-decoration: underline -} - -.atom_one_light.hljs,.atom_one_light .hljs { - color: #383a42; - background: #fafafa -} - -.atom_one_light .hljs-comment,.atom_one_light .hljs-quote { - color: #a0a1a7; - font-style: italic -} - -.atom_one_light .hljs-doctag,.atom_one_light .hljs-formula,.atom_one_light .hljs-keyword { - color: #a626a4 -} - -.atom_one_light .hljs-deletion,.atom_one_light .hljs-name,.atom_one_light .hljs-section,.atom_one_light .hljs-selector-tag,.atom_one_light .hljs-subst { - color: #e45649 -} - -.atom_one_light .hljs-literal { - color: #0184bb -} - -.atom_one_light .hljs-addition,.atom_one_light .hljs-attribute,.atom_one_light .hljs-meta .hljs-string,.atom_one_light .hljs-regexp,.atom_one_light .hljs-string { - color: #50a14f -} - -.atom_one_light .hljs-attr,.atom_one_light .hljs-number,.atom_one_light .hljs-selector-attr,.atom_one_light .hljs-selector-class,.atom_one_light .hljs-selector-pseudo,.atom_one_light .hljs-template-variable,.atom_one_light .hljs-type,.atom_one_light .hljs-variable { - color: #986801 -} - -.atom_one_light .hljs-bullet,.atom_one_light .hljs-link,.atom_one_light .hljs-meta,.atom_one_light .hljs-selector-id,.atom_one_light .hljs-symbol,.atom_one_light .hljs-title { - color: #4078f2 -} - -.atom_one_light .hljs-built_in,.atom_one_light .hljs-class .hljs-title,.atom_one_light .hljs-title .class_ { - color: #c18401 -} - -.atom_one_light .hljs-emphasis { - font-style: italic -} - -.atom_one_light .hljs-strong { - font-weight: 700 -} - -.atom_one_light .hljs-link { - text-decoration: underline -} - -.passageCodeEditorWrapper { - background: #282c34; - overflow: initial -} - -body pre code.hljs { - display: block; - overflow-x: auto; - padding: 1em -} - -body code.hljs { - padding: 3px 5px -} - -body .hljs { - color: #abb2bf; - background: #282c34 -} - -body .hljs-comment,body .hljs-quote { - color: #5c6370; - font-style: italic -} - -body .hljs-doctag,body .hljs-formula,body .hljs-keyword { - color: #c678dd -} - -body .hljs-deletion,body .hljs-name,body .hljs-section,body .hljs-selector-tag,body .hljs-subst { - color: #e06c75 -} - -body .hljs-literal { - color: #56b6c2 -} - -body .hljs-addition,body .hljs-attribute,body .hljs-meta .hljs-string,body .hljs-regexp,body .hljs-string { - color: #98c379 -} - -body .hljs-attr,body .hljs-number,body .hljs-selector-attr,body .hljs-selector-class,body .hljs-selector-pseudo,body .hljs-template-variable,body .hljs-type,body .hljs-variable { - color: #d19a66 -} - -body .hljs-bullet,body .hljs-link,body .hljs-meta,body .hljs-selector-id,body .hljs-symbol,body .hljs-title { - color: #61aeee -} - -body .hljs-built_in,body .hljs-class .hljs-title,body .hljs-title.class_ { - color: #e6c07b -} - -body .hljs-emphasis { - font-style: italic -} - -body .hljs-strong { - font-weight: 700 -} - -body .hljs-link { - text-decoration: underline -} - -.wr_whiteTheme pre code.hljs { - display: block; - overflow-x: auto; - padding: 1em -} - -.wr_whiteTheme code.hljs { - padding: 3px 5px -} - -.wr_whiteTheme .hljs { - color: #383a42; - background: #fafafa -} - -.wr_whiteTheme .hljs-comment,.wr_whiteTheme .hljs-quote { - color: #a0a1a7; - font-style: italic -} - -.wr_whiteTheme .hljs-doctag,.wr_whiteTheme .hljs-formula,.wr_whiteTheme .hljs-keyword { - color: #a626a4 -} - -.wr_whiteTheme .hljs-deletion,.wr_whiteTheme .hljs-name,.wr_whiteTheme .hljs-section,.wr_whiteTheme .hljs-selector-tag,.wr_whiteTheme .hljs-subst { - color: #e45649 -} - -.wr_whiteTheme .hljs-literal { - color: #0184bb -} - -.wr_whiteTheme .hljs-addition,.wr_whiteTheme .hljs-attribute,.wr_whiteTheme .hljs-meta .hljs-string,.wr_whiteTheme .hljs-regexp,.wr_whiteTheme .hljs-string { - color: #50a14f -} - -.wr_whiteTheme .hljs-attr,.wr_whiteTheme .hljs-number,.wr_whiteTheme .hljs-selector-attr,.wr_whiteTheme .hljs-selector-class,.wr_whiteTheme .hljs-selector-pseudo,.wr_whiteTheme .hljs-template-variable,.wr_whiteTheme .hljs-type,.wr_whiteTheme .hljs-variable { - color: #986801 -} - -.wr_whiteTheme .hljs-bullet,.wr_whiteTheme .hljs-link,.wr_whiteTheme .hljs-meta,.wr_whiteTheme .hljs-selector-id,.wr_whiteTheme .hljs-symbol,.wr_whiteTheme .hljs-title { - color: #4078f2 -} - -.wr_whiteTheme .hljs-built_in,.wr_whiteTheme .hljs-class .hljs-title,.wr_whiteTheme .hljs-title.class_ { - color: #c18401 -} - -.wr_whiteTheme .hljs-emphasis { - font-style: italic -} - -.wr_whiteTheme .hljs-strong { - font-weight: 700 -} - -.wr_whiteTheme .hljs-link { - text-decoration: underline -} - -.passage-skeleton { - position: absolute; - width: 100%; - display: flex -} - -.passage-skeleton .passage-loading { - margin: auto; - position: relative -} - -.viewer-close:before,.viewer-flip-horizontal:before,.viewer-flip-vertical:before,.viewer-fullscreen-exit:before,.viewer-fullscreen:before,.viewer-next:before,.viewer-one-to-one:before,.viewer-play:before,.viewer-prev:before,.viewer-reset:before,.viewer-rotate-left:before,.viewer-rotate-right:before,.viewer-zoom-in:before,.viewer-zoom-out:before { - background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC"); - background-repeat: no-repeat; - background-size: 280px; - color: transparent; - display: block; - font-size: 0; - height: 20px; - line-height: 0; - width: 20px -} - -.viewer-container { - bottom: 0; - direction: ltr; - font-size: 0; - left: 0; - line-height: 0; - overflow: hidden; - position: absolute; - right: 0; - -webkit-tap-highlight-color: rgba(0,0,0,0); - top: 0; - touch-action: none; - -webkit-touch-callout: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -.viewer-container::-moz-selection,.viewer-container ::-moz-selection { - background-color: transparent -} - -.viewer-container::selection,.viewer-container ::selection { - background-color: transparent -} - -.viewer-container:focus { - outline: 0 -} - -.viewer-container img { - display: block; - height: auto; - max-height: none!important; - max-width: 90vw!important; - min-height: 0!important; - min-width: 0!important; - width: 100% -} - -.viewer-canvas { - bottom: 0; - left: 0; - overflow: hidden; - position: absolute; - right: 0; - top: 0 -} - -.viewer-canvas>img { - height: auto; - margin: 15px auto; - max-width: 90%!important; - width: auto -} - -.viewer-player { - background-color: #000; - bottom: 0; - cursor: none; - display: none; - right: 0; - z-index: 1 -} - -.viewer-player,.viewer-player>img { - left: 0; - position: absolute; - top: 0 -} - -.viewer-fixed { - position: fixed -} - -.viewer-open { - overflow: hidden -} - -.viewer-show { - display: block -} - -.viewer-hide { - display: none -} - -.viewer-backdrop { - background-color: rgba(0,0,0,.5) -} - -.viewer-invisible { - visibility: hidden -} - -.viewer-move { - cursor: grab -} - -.viewer-fade { - opacity: 0 -} - -.viewer-in { - opacity: 1 -} - -.viewer-transition { - transition: all .3s -} - -@keyframes viewer-spinner { - 0% { - transform: rotate(0deg) - } - - to { - transform: rotate(1turn) - } -} - -.viewer-loading:after { - animation: viewer-spinner 1s linear infinite; - border: 4px solid hsla(0,0%,100%,.1); - border-left-color: hsla(0,0%,100%,.5); - border-radius: 50%; - content: ""; - display: inline-block; - height: 40px; - left: 50%; - margin-left: -20px; - margin-top: -20px; - position: absolute; - top: 50%; - width: 40px; - z-index: 1 -} - -@media(max-width: 767px) { - .viewer-hide-xs-down { - display:none - } -} - -@media(max-width: 991px) { - .viewer-hide-sm-down { - display:none - } -} - -@media(max-width: 1199px) { - .viewer-hide-md-down { - display:none - } -} - -.passage-content,.passage-content span { - text-indent: 0!important -} - -.passage-content pre { - line-height: normal!important; - margin: 0!important -} - -.readerBottomBar { - display: none; - position: fixed; - z-index: 91; - bottom: 0; - width: 100%; - height: 56px; - padding-bottom: env(safe-area-inset-bottom); - align-items: center; - justify-content: space-between; - background-color: #101418 -} - -.wr_whiteTheme .readerBottomBar { - background-color: #fff -} - -.wr_whiteTheme .readerBottomBar.showShadow { - box-shadow: 0 -.3px 20px rgba(0,0,0,.08) -} - -.rbb_item { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 100% -} - -.rbb_item .icon { - width: 24px; - height: 24px -} - -.rbb_item .txt { - margin-top: 3px; - font-size: 10px; - color: #b2b4b8 -} - -.wr_whiteTheme .rbb_item .txt { - color: #5d646e -} - -.home .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home.3867b9ec.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .home .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home_2x.6d0eebab.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .home .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home_3x.485edf79.png) - } -} - -.wr_whiteTheme .home .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home_white.4e3bf5e2.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .home .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home_white_2x.a59a83f7.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .home .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_home_white_3x.04e00262.png) - } -} - -.catalog .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog.25fd0b58.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog_2x.5f05cb5d.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog_3x.5e3cd530.png) - } -} - -.wr_whiteTheme .catalog .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog_white.42fcc271.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog_white_2x.45a83e51.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .catalog .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_catalog_white_3x.39188ac3.png) - } -} - -.setting .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting.5c5c728f.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .setting .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting_2x.456b5994.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .setting .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting_3x.8cd4b64a.png) - } -} - -.wr_whiteTheme .setting .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting_white.c44d25e1.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .setting .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting_white_2x.e87281ad.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .setting .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_setting_white_3x.f3f01f51.png) - } -} - -.rbb_addShelf { - margin-left: 16px; - margin-right: 16px -} - -.rbb_addShelf.added { - background: hsla(0,0%,100%,.1); - color: #b2b4b8!important -} - -.wr_whiteTheme .rbb_addShelf.added { - background: rgba(0,0,0,.03); - color: #5d646e!important -} - -.rbb_addShelf_icon { - display: inline-block; - width: 24px; - height: 24px; - vertical-align: middle; - margin-right: 6px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add.44d1845d.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add_2x.6cbee9d7.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add_3x.94b2b9c3.png) - } -} - -.wr_whiteTheme .rbb_addShelf_icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add_white.44d1845d.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add_white_2x.6cbee9d7.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_add_white_3x.94b2b9c3.png) - } -} - -.added .rbb_addShelf_icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added.14842b77.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .added .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added_2x.a420816d.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .added .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added_3x.35b17699.png) - } -} - -.wr_whiteTheme .added .rbb_addShelf_icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added_white.120ce0d9.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .added .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added_white_2x.58c07219.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .added .rbb_addShelf_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_bottom_bookshelf_added_white_3x.c30b0c9f.png) - } -} - -.readerBottomSettingPanel { - display: none; - position: fixed; - z-index: 90; - width: 100%; - bottom: 0; - padding-bottom: env(safe-area-inset-bottom); - background-color: #101418 -} - -.wr_whiteTheme .readerBottomSettingPanel { - background-color: #fff; - box-shadow: 0 -.3px 20px rgba(0,0,0,.1) -} - -.rbsp_inner { - padding-top: 12px; - padding-bottom: 12px; - margin-bottom: 56px -} - -.rbsp_color { - margin: 12px 20px; - height: 24px; - display: flex; - justify-content: space-between -} - -.rbsp_color .rbsp_color_item { - flex: 1; - height: 100%; - border-radius: 6px; - box-sizing: border-box; - text-indent: -999em; - background-size: 20px 20px; - background-position: 50% 50%; - background-repeat: no-repeat -} - -.rbsp_color .white { - background-color: #fff; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white.4c9573a0.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .rbsp_color .white { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white_2x.e3c94740.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .rbsp_color .white { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white_3x.5bf8504b.png) - } -} - -.wr_whiteTheme .rbsp_color .white { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white_white.680713a6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .rbsp_color .white { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white_white_2x.2e8f061d.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .rbsp_color .white { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_white_white_3x.8b64fae5.png) - } -} - -.rbsp_color .dark { - background-color: #10141b; - margin-left: 6px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black.b3541272.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .rbsp_color .dark { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black_2x.5f0df325.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .rbsp_color .dark { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black_3x.158984cb.png) - } -} - -.wr_whiteTheme .rbsp_color .dark { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black_white.88e521cd.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .rbsp_color .dark { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black_white_2x.b534d209.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .rbsp_color .dark { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_setting_panel_black_white_3x.2cda7718.png) - } -} - -.rbsp_color .current { - border: 1px solid #0097ff -} - -.wr_whiteTheme .rbsp_color .current { - border-color: #1b88ee -} - -.rbsp_download { - display: block; - width: 100%; - padding-top: 6px; - padding-bottom: 12px; - font-size: 12px; - font-weight: 500; - text-align: center; - color: #0097ff -} - -.wr_whiteTheme .rbsp_download { - color: #1b88ee -} - -body[data-v-5f0d59d4],dd[data-v-5f0d59d4],dl[data-v-5f0d59d4],fieldset[data-v-5f0d59d4],form[data-v-5f0d59d4],h1[data-v-5f0d59d4],h2[data-v-5f0d59d4],h3[data-v-5f0d59d4],h4[data-v-5f0d59d4],h5[data-v-5f0d59d4],h6[data-v-5f0d59d4],legend[data-v-5f0d59d4],p[data-v-5f0d59d4],pre[data-v-5f0d59d4] { - margin: 0 -} - -fieldset[data-v-5f0d59d4],ol[data-v-5f0d59d4],ul[data-v-5f0d59d4] { - margin: 0; - padding: 0 -} - -td[data-v-5f0d59d4],th[data-v-5f0d59d4] { - padding: 0 -} - -table[data-v-5f0d59d4] { - font-size: inherit -} - -fieldset[data-v-5f0d59d4],img[data-v-5f0d59d4] { - border: 0 -} - -li[data-v-5f0d59d4],ol[data-v-5f0d59d4],ul[data-v-5f0d59d4] { - list-style: none -} - -body[data-v-5f0d59d4] { - font-size: 12px; - line-height: 1.5; - background: #262628; - color: #eef0f4 -} - -h1[data-v-5f0d59d4],h2[data-v-5f0d59d4],h3[data-v-5f0d59d4],h4[data-v-5f0d59d4] { - font-size: 18px; - font-weight: 400 -} - -body[data-v-5f0d59d4],button[data-v-5f0d59d4],input[data-v-5f0d59d4],select[data-v-5f0d59d4],textarea[data-v-5f0d59d4] { - font-family: PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - outline: none; - -webkit-text-size-adjust: none -} - -button[data-v-5f0d59d4],input[data-v-5f0d59d4],select[data-v-5f0d59d4],textarea[data-v-5f0d59d4] { - font-size: inherit; - -webkit-tap-highlight-color: rgba(0,0,0,0) -} - -a[data-v-5f0d59d4] { - color: #4a7ab0; - text-decoration: none; - -webkit-tap-highlight-color: rgba(0,0,0,.03) -} - -[data-v-5f0d59d4]:focus { - outline: none -} - -article[data-v-5f0d59d4],aside[data-v-5f0d59d4],details[data-v-5f0d59d4],figcaption[data-v-5f0d59d4],figure[data-v-5f0d59d4],footer[data-v-5f0d59d4],header[data-v-5f0d59d4],hgroup[data-v-5f0d59d4],main[data-v-5f0d59d4],nav[data-v-5f0d59d4],section[data-v-5f0d59d4],summary[data-v-5f0d59d4] { - display: block -} - -audio[data-v-5f0d59d4],canvas[data-v-5f0d59d4],video[data-v-5f0d59d4] { - display: inline-block -} - -.qui_txtNormal[data-v-5f0d59d4] { - font-weight: 400!important -} - -.qui_txtBold[data-v-5f0d59d4] { - font-weight: 700!important -} - -.qui_txtLeft[data-v-5f0d59d4] { - text-align: left!important -} - -.qui_txtRight[data-v-5f0d59d4] { - text-align: right!important -} - -.qui_txtUnderline[data-v-5f0d59d4] { - text-decoration: underline!important -} - -.qui_txtUnderlineNone[data-v-5f0d59d4] { - text-decoration: none!important -} - -.qui_txtOverflow[data-v-5f0d59d4] { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal -} - -.qui_clear[data-v-5f0d59d4]:after { - clear: both; - content: "."; - display: block; - line-height: 0; - font-size: 0; - visibility: hidden -} - -.qui_txtNowrap[data-v-5f0d59d4] { - white-space: nowrap!important -} - -.qui_layoutLeft[data-v-5f0d59d4] { - float: left!important -} - -.qui_layoutRight[data-v-5f0d59d4] { - float: right!important -} - -.qui_displayNone[data-v-5f0d59d4] { - display: none!important -} - -@keyframes iconBreathe-data-v-5f0d59d4 { - 0% { - transform: scale(1) - } - - 40% { - transform: scale(1.3) - } - - 60% { - transform: scale(1) - } - - to { - transform: scale(1) - } -} - -@keyframes itemFadeIn-data-v-5f0d59d4 { - 0% { - background-color: #fff - } - - to { - background-color: rgba(27,136,238,.1) - } -} - -@keyframes itemFadeOut-data-v-5f0d59d4 { - 0% { - background-color: rgba(27,136,238,.1) - } - - to { - background-color: #fff - } -} - -body[data-v-5f0d59d4],html[data-v-5f0d59d4] { - height: 100%; - -webkit-touch-callout: none -} - -body[data-v-5f0d59d4] { - height: 100%; - font-family: PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - -webkit-font-size-adjust: none; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale -} - -a[data-v-5f0d59d4] { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -a[data-v-5f0d59d4]:active,a[data-v-5f0d59d4]:hover { - text-decoration: none -} - -button[data-v-5f0d59d4] { - background: none; - border: 0; - padding: 0; - text-decoration: none; - cursor: pointer -} - -input[data-v-5f0d59d4],textarea[data-v-5f0d59d4] { - margin: 0; - padding: 0; - border: 0 -} - -.frame_wrap[data-v-5f0d59d4] { - padding-bottom: 20px; - min-width: 320px -} - -textarea[data-v-5f0d59d4] { - overflow: auto -} - -.wr_hide[data-v-5f0d59d4] { - display: none!important -} - -.wr_show[data-v-5f0d59d4] { - display: block!important -} - -.wr_txtLineThrough[data-v-5f0d59d4] { - text-decoration: line-through -} - -.wr_fade[data-v-5f0d59d4] { - transition: opacity .25s; - opacity: 0 -} - -.wr_fade_Show[data-v-5f0d59d4] { - opacity: 1 -} - -.readerForbidden_Content[data-v-5f0d59d4] { - height: 100%; - box-sizing: border-box; - width: 100%; - max-width: none -} - -.readerForbidden_Content .app_content[data-v-5f0d59d4] { - max-width: none; - background-color: #262628; - transition: background-color .2s ease-in-out; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center -} - -.wr_whiteTheme .readerForbidden_Content .app_content[data-v-5f0d59d4] { - background-color: #f4f5f7 -} - -.readerForbidden_icon[data-v-5f0d59d4] { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/readerForbidden.96098659.png) no-repeat; - background-size: 100%; - width: 72px; - height: 72px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerForbidden_icon[data-v-5f0d59d4] { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/readerForbidden_2x.d03ca97e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerForbidden_icon[data-v-5f0d59d4] { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/readerForbidden_3x.9c84f907.png) - } -} - -.readerForbidden_title[data-v-5f0d59d4] { - color: #eef0f4; - line-height: 42px; - font-size: 30px; - margin-top: 37px -} - -.wr_whiteTheme .readerForbidden_title[data-v-5f0d59d4] { - color: #212832 -} - -.readerForbidden_hint[data-v-5f0d59d4] { - color: #b2b4b8; - line-height: 35px; - font-size: 18px; - margin-top: 20px -} - -.wr_whiteTheme .readerForbidden_hint[data-v-5f0d59d4] { - color: #5d646e -} - -.readerForbidden_hint .readerForbidden_hint_countdown[data-v-5f0d59d4] { - color: #2493ee -} - -.payWholeBookDialogWrap { - width: 80%; - max-width: 270px -} - -.payDialog_content { - padding: 32px 16px 48px -} - -.payDialog_content .payDialog_price { - font-family: WeChatNumber,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - line-height: 1em; - font-size: 34px; - color: #eef0f4 -} - -.wr_whiteTheme .payDialog_content .payDialog_price { - color: #212832 -} - -.payDialog_content .payDialog_account { - margin-top: 2px; - padding-bottom: 5px; - font-size: 14px; - color: #8a8c90 -} - -.wr_whiteTheme .payDialog_content .payDialog_account { - color: #858c96 -} - -.payDialog_content .payDialog_sectionTitle { - margin-top: 14px; - padding-top: 7px; - font-size: 14px; - color: #8a8c90 -} - -.wr_whiteTheme .payDialog_content .payDialog_sectionTitle { - color: #858c96 -} - -.payDialog_content .payDialog_sectionContent { - margin-top: 3px; - padding-bottom: 6px; - font-size: 16px; - color: #eef0f4 -} - -.wr_whiteTheme .payDialog_content .payDialog_sectionContent { - color: #212832 -} - -.payDialog_content .red,.wr_whiteTheme .payDialog_content .red { - color: #fa3a3a -} - -.payDialog_actions { - height: 52px; - line-height: 52px; - border-radius: 0 0 12px 12px; - background: linear-gradient(90deg,#0087fc,#00a3f5) -} - -.payDialog_actions .payDialog_action { - cursor: pointer; - display: block; - height: 100%; - text-align: center; - font-size: 15px; - color: #fff -} - -.payDialog_actions .payDialog_action:hover { - opacity: .8 -} - -.payChapterDialogWrap { - max-width: 500px; - width: 80%; - height: 80%; - max-height: 700px; - min-height: 480px; - text-align: left -} - -.payChapterDialog { - position: relative; - width: 100%; - height: 100% -} - -.pcd_title { - display: flex; - height: 60px; - line-height: 60px; - padding: 0 24px; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_title { - position:relative; - border: 0 - } - - .pcd_title:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_title:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .pcd_title { - border-color: rgba(13,20,30,.05) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .pcd_title:after { - border-color:rgba(13,20,30,.05) - } -} - -@media(max-width: 468px) { - .pcd_title { - padding-left:16px; - padding-right: 16px - } -} - -.pcd_title .pcd_bookTitle { - flex: auto; - font-size: 20px; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - color: #eef0f4; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal; - padding-right: 60px -} - -.wr_whiteTheme .pcd_title .pcd_bookTitle { - color: #212832 -} - -.pcd_title .pcd_selectAll { - flex: none; - font-size: 15px; - color: #0097ff -} - -.wr_whiteTheme .pcd_title .pcd_selectAll { - color: #1b88ee -} - -.pcd_content { - position: absolute; - top: 60px; - bottom: 287px; - left: 0; - right: 0; - overflow: auto; - color: #eef0f4 -} - -.wr_whiteTheme .pcd_content { - color: #212832 -} - -.pcd_content_paid_only { - bottom: 309px -} - -.pcd_chapter_item { - height: 60px; - display: flex; - align-items: center; - padding-left: 12px; - padding-right: 24px -} - -@media(max-width: 468px) { - .pcd_chapter_item { - padding-left:6px; - padding-right: 16px - } -} - -.pcd_chapter_item.selectable { - cursor: pointer -} - -.pcd_chapter_item:hover,.wr_whiteTheme .pcd_chapter_item:hover { - background: rgba(52,167,255,.07) -} - -.pcd_section_content .pcd_chapter_item { - padding-left: 64px -} - -@media(max-width: 468px) { - .pcd_section_content .pcd_chapter_item { - padding-left:42px - } -} - -.pcd_chapter_item_arrow { - width: 8px; - height: 36px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_arrow.6cf57319.png) no-repeat; - background-size: 100%; - background-repeat: no-repeat; - background-size: 8px 12px; - background-position: 50% 50%; - padding-left: 12px; - padding-right: 16px; - cursor: pointer; - transition: transform .2s -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_chapter_item_arrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_arrow_2x.c6bd8669.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_chapter_item_arrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_arrow_3x.b6b75b96.png) - } -} - -.pcd_chapter_item_arrow.expand { - transform: rotate(90deg) -} - -.pcd_chapter_item_checkbox { - width: 18px; - height: 18px; - margin-left: 16px; - display: none -} - -.pcd_chapter_item_checkbox_label { - display: inline-block; - width: 18px; - height: 18px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal.16df1891.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_chapter_item_checkbox_label { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal_2x.71001b0c.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_chapter_item_checkbox_label { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal_3x.bad0a5ac.png) - } -} - -.pcd_chapter_item.checked .pcd_chapter_item_checkbox_label { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal_checked.fe49dc95.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_chapter_item.checked .pcd_chapter_item_checkbox_label { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal_checked_2x.dd2b1a75.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_chapter_item.checked .pcd_chapter_item_checkbox_label { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_normal_checked_3x.24d6192e.png) - } -} - -.pcd_chapter_item_content { - flex-grow: 1; - display: flex; - flex-direction: column -} - -.pcd_chapter_item_content .line1 { - font-size: 15px; - color: #eef0f4; - line-height: 15px; - overflow: hidden; - height: 15px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical -} - -@media(max-width: 468px) { - .pcd_chapter_item_content .line1 { - font-size:14px - } -} - -.wr_whiteTheme .pcd_chapter_item_content .line1 { - color: #212832 -} - -.pcd_chapter_item_content .line2 { - margin-top: 5px; - font-size: 12px; - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_chapter_item_content .line2 { - color: #5d646e -} - -.pcd_chapter_item_content .line2.red,.wr_whiteTheme .pcd_chapter_item_content .line2.red { - color: #fa3a3a -} - -.pcd_actions { - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 287px; - padding-left: 24px; - padding-right: 24px; - background-color: #2a2a2a; - border-top: 1px solid hsla(0,0%,100%,.05); - border-radius: 0 0 12px 12px -} - -.wr_whiteTheme .pcd_actions { - background-color: #fff; - border-top-color: rgba(13,20,30,.05) -} - -@media(max-width: 468px) { - .pcd_actions { - padding-left:16px; - padding-right: 16px - } -} - -.pcd_actions .pcd_actions_item { - height: 40px; - display: flex; - align-items: flex-start; - justify-content: space-between; - font-size: 14px; - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_item { - color: #5d646e -} - -.pcd_actions .pcd_actions_item_white { - color: #fff -} - -.wr_whiteTheme .pcd_actions .pcd_actions_item_white { - color: #0d141e -} - -.pcd_actions .pcd_actions_item_blue { - color: #0097ff -} - -.wr_whiteTheme .pcd_actions .pcd_actions_item_blue { - color: #1b88ee -} - -.pcd_actions .pcd_actions_item_disabled { - color: #8a8c90; - text-decoration: line-through -} - -.wr_whiteTheme .pcd_actions .pcd_actions_item_disabled { - color: #858c96 -} - -.pcd_actions .pcd_actions_item_number { - font-size: 22px; - font-family: WeChatNumber,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - margin-right: 3px; - vertical-align: -1px -} - -@media(max-width: 468px) { - .pcd_actions .pcd_actions_item_number { - font-size:16px; - margin-right: 1px; - vertical-align: 0 - } -} - -.pcd_actions .pcd_actions_buy { - cursor: pointer; - height: 60px; - margin-top: 16px; - border-radius: 6px; - background: linear-gradient(90deg,#0087fc,#00a3f5); - text-align: center; - display: flex; - flex-direction: column; - justify-content: center -} - -.pcd_actions .pcd_actions_buy:hover { - opacity: .8 -} - -.pcd_actions .pcd_actions_buy.disabled { - opacity: .8; - cursor: auto -} - -.pcd_actions .pcd_actions_buy .line1 { - font-weight: 500; - font-size: 16px; - color: #fff -} - -.pcd_actions .pcd_actions_account { - padding-top: 24px; - font-size: 15px; - font-weight: 500; - text-align: center; - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_account { - color: #5d646e -} - -.pcd_actions .pcd_actions_account.red,.wr_whiteTheme .pcd_actions .pcd_actions_account.red { - color: #f95457 -} - -.pcd_actions .pcd_actions_account_reset { - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_account_reset { - color: #5d646e -} - -.pcd_actions .pcd_actions_paid_balance_only { - font-size: 15px; - font-weight: 500; - text-align: center; - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_paid_balance_only { - color: #5d646e -} - -.pcd_actions .pcd_actions_autoPay { - display: flex; - align-items: center; - margin: 0 auto; - padding: 12px 22px; - font-size: 15px; - font-weight: 500; - text-align: center; - color: #b2b4b8 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_autoPay { - color: #5d646e -} - -.pcd_actions .pcd_actions_autoPay:hover { - color: #eef0f4 -} - -.wr_whiteTheme .pcd_actions .pcd_actions_autoPay:hover { - color: #212832 -} - -.pcd_actions_paid { - height: 309px -} - -.pcd_actions_autoPay_checkbox { - display: inline-block; - margin-right: 8px; - height: 16px; - width: 16px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini.db9e9781.png) no-repeat; - background-size: 16px 16px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_actions_autoPay_checkbox { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_2x.be38875e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_actions_autoPay_checkbox { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_3x.b54fac4f.png) - } -} - -.pcd_actions_autoPay_checkbox.checked { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked.d3288c1a.png) no-repeat; - background-size: 16px 16px; - background-position: 0 50% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .pcd_actions_autoPay_checkbox.checked { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked_2x.aa8c3454.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .pcd_actions_autoPay_checkbox.checked { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_checkbox_mini_checked_3x.d425337d.png) - } -} - -.readerLoginGuide { - margin-bottom: 24px; - background-color: hsla(0,0%,100%,.05); - border-radius: 12px; - padding: 20px; - display: flex -} - -.wr_whiteTheme .readerLoginGuide { - background-color: rgba(0,0,0,.05) -} - -.readerLoginGuide_qrcode { - flex: none; - width: 100px; - height: 100px -} - -.readerLoginGuide_qrcode_loading { - position: relative; - width: 100%; - height: 100%; - margin: 0 auto -} - -.readerLoginGuide_qrcode_loading .wr_loading { - left: 50%; - top: 50% -} - -.readerLoginGuide_qrcode_retry { - display: block; - width: 100px; - height: 100px; - line-height: 100px; - font-size: 14px; - text-align: center; - font-weight: 500; - color: #0097ff; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_login_guide_qrcode.13b35687.png) no-repeat; - background-size: 100% -} - -.wr_whiteTheme .readerLoginGuide_qrcode_retry { - color: #1b88ee -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerLoginGuide_qrcode_retry { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_login_guide_qrcode_2x.9ead9d9f.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerLoginGuide_qrcode_retry { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_login_guide_qrcode_3x.a1e70390.png) - } -} - -.readerLoginGuide_right { - flex: 1; - display: flex; - flex-direction: column; - justify-content: center; - align-items: flex-start; - margin-left: 24px -} - -.readerLoginGuide_right .line1 { - font-size: 18px; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - color: #eef0f4; - text-align: left -} - -.wr_whiteTheme .readerLoginGuide_right .line1 { - color: #212832 -} - -.readerLoginGuide_right .line2 { - margin-top: 8px; - font-size: 18px; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - color: #e7d1a1; - text-align: left -} - -.wr_whiteTheme .readerLoginGuide_right .line2 { - color: #8c6e2c -} - -.reader_footerNote_mask { - position: fixed; - top: 0; - bottom: 0; - left: 0; - right: 0; - background-color: transparent; - z-index: 90 -} - -.reader_footerNote_container { - z-index: 100; - position: absolute; - width: 92%; - max-width: 304px -} - -.reader_footerNote_container:after { - content: ""; - position: absolute; - bottom: -8px; - left: 50%; - margin-left: -8px; - border-top: 8px solid #3a3c3e; - border-left: 8px solid transparent; - border-right: 8px solid transparent -} - -.reader_footerNote_container_Top:after { - content: ""; - position: absolute; - bottom: auto; - top: -8px; - left: 50%; - margin-left: -8px; - border: 8px solid transparent; - border-top: none; - border-bottom: 8px solid #3a3c3e -} - -.reader_footerNote_bubble { - padding: 16px; - border-radius: 16px; - background-color: #3a3c3e; - max-height: 300px; - overflow: auto -} - -.reader_footerNote_text { - color: #fff; - font-size: 15px; - line-height: 23px; - word-break: break-all; - word-wrap: break-word -} - -.rcv_succ_dialog_content { - padding: 60px 24px 24px -} - -.rcv_succ_dialog_head { - text-align: center; - padding-bottom: 40px -} - -.rcv_succ_dialog_img { - display: inline-block; - width: 72px; - height: 72px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_vip_collage_succ.70344746.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .rcv_succ_dialog_img { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_vip_collage_succ_2x.5e21d357.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .rcv_succ_dialog_img { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_vip_collage_succ_3x.cb1dc43e.png) - } -} - -.rcv_succ_dialog_title { - margin-top: 28px; - font-size: 28px; - color: #ecd8ac; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif -} - -.rcv_succ_dialog_foot { - border-top: 1px solid hsla(0,0%,100%,.05); - padding-top: 24px; - display: flex; - align-items: center; - text-align: left -} - -.wr_whiteTheme .rcv_succ_dialog_foot { - border-top-color: rgba(0,0,0,.05) -} - -.rcv_succ_dialog_foot .rcv_succ_dialog_foot_qrcode { - flex: none; - width: 72px; - height: 72px -} - -.rcv_succ_dialog_foot .rcv_succ_dialog_foot_right { - flex: 1; - margin-left: 24px; - font-size: 16px; - color: #ecd8ac -} - -.rcv_succ_dialog_foot .rcv_succ_dialog_foot_right .line2 { - margin-top: 5px -} - -.writeReview_container { - text-align: left -} - -.writeReview_editor_container { - position: relative -} - -.writeReview_editor { - position: absolute; - top: 0; - bottom: 100px; - left: 0; - right: 0 -} - -.writeReview_editor .writeReview_icon { - position: absolute; - left: 24px; - top: 38px; - width: 24px; - height: 24px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review.a35138a4.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_2x.64b11be8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_3x.208a3374.png) - } -} - -.wr_whiteTheme .writeReview_editor .writeReview_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_white.2d66aa3b.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_white_2x.552c3c85.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_white_3x.9e3e4f56.png) - } -} - -.forceDark .writeReview_editor .writeReview_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review.a35138a4.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_2x.64b11be8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_editor .writeReview_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_popup_review_3x.208a3374.png) - } -} - -.writeReview_editor .writeReview_textarea { - width: calc(100% - 48px); - height: calc(100% - 15px); - overflow: scroll; - overflow-x: hidden; - background-color: transparent; - border: 0; - font-size: 17px; - line-height: 28px; - resize: none; - margin: 15px 24px 0; - box-sizing: border-box; - color: #fff -} - -.wr_whiteTheme .writeReview_editor .writeReview_textarea { - color: #0d141e -} - -.writeReview_editor .writeReview_textarea::-moz-placeholder { - color: #8a8c90 -} - -.writeReview_editor .writeReview_textarea:-ms-input-placeholder { - color: #8a8c90 -} - -.writeReview_editor .writeReview_textarea::-ms-input-placeholder { - color: #8a8c90 -} - -.writeReview_editor .writeReview_textarea::placeholder { - color: #8a8c90 -} - -.wr_whiteTheme .writeReview_editor .writeReview_textarea::-moz-placeholder { - color: #858c96 -} - -.wr_whiteTheme .writeReview_editor .writeReview_textarea:-ms-input-placeholder { - color: #858c96 -} - -.wr_whiteTheme .writeReview_editor .writeReview_textarea::-ms-input-placeholder { - color: #858c96 -} - -.wr_whiteTheme .writeReview_editor .writeReview_textarea::placeholder { - color: #858c96 -} - -.forceDark .writeReview_editor .writeReview_textarea { - color: #fff -} - -.forceDark .writeReview_editor .writeReview_textarea::-moz-placeholder { - color: #8a8c90 -} - -.forceDark .writeReview_editor .writeReview_textarea:-ms-input-placeholder { - color: #8a8c90 -} - -.forceDark .writeReview_editor .writeReview_textarea::-ms-input-placeholder { - color: #8a8c90 -} - -.forceDark .writeReview_editor .writeReview_textarea::placeholder { - color: #8a8c90 -} - -.writeReview_editor textarea::-webkit-scrollbar { - width: 8px; - box-shadow: none; - border: 0 -} - -.writeReview_editor textarea::-webkit-scrollbar-track,.writeReview_editor textarea::-webkit-scrollbar-track-piece { - opacity: 0 -} - -.writeReview_editor textarea::-webkit-scrollbar-thumb { - border-radius: 10px; - background: rgba(0,0,0,.3) -} - -.writeReview_editor.paddingLarge .writeReview_textarea { - margin: 36px 58px 0; - width: calc(100% - 116px); - height: calc(100% - 36px) -} - -.writeReview_footer { - position: absolute; - bottom: 0; - left: 24px; - right: 24px -} - -.writeReview_footer:after { - content: ""; - display: block; - clear: both -} - -.writeReview_footer .menu_option_list_link { - height: 41px; - line-height: 1em; - padding-top: 10px; - overflow: hidden -} - -.writeReview_footer .writeReview_private_button { - cursor: pointer; - float: left; - height: 32px; - border-radius: 16px; - padding: 0 12px; - background-color: hsla(0,0%,100%,.1) -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button { - background-color: #edeeef -} - -.forceDark .writeReview_footer .writeReview_private_button { - background-color: hsla(0,0%,100%,.1) -} - -.writeReview_footer .writeReview_private_button .button_leftIcon,.writeReview_footer .writeReview_private_button .button_rightIcon,.writeReview_footer .writeReview_private_button .button_text { - display: inline-block; - vertical-align: middle; - margin-top: 7px -} - -.writeReview_footer .writeReview_private_button .button_leftIcon { - width: 16px; - height: 16px; - margin-top: 5px; - margin-right: 4px -} - -.writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow.c3d1ac71.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_2x.27fd6f04.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_3x.3746bd05.png) - } -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white.ae9b3d93.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white_2x.be45b6e8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white_3x.18123b4d.png) - } -} - -.forceDark .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow.c3d1ac71.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_2x.27fd6f04.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Follow .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_3x.3746bd05.png) - } -} - -.writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish.358fd280.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_2x.553e0bed.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_3x.27d909ea.png) - } -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white.ae002e9c.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white_2x.2ac860fd.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white_3x.bf8af40e.png) - } -} - -.forceDark .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish.358fd280.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_2x.553e0bed.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Publish .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_3x.27d909ea.png) - } -} - -.writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret.ea0011c6.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_2x.3f6de91e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_3x.32f3a186.png) - } -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white.144816b5.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white_2x.300be2d1.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white_3x.5658597a.png) - } -} - -.forceDark .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret.ea0011c6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_2x.3f6de91e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer .writeReview_private_button_Private .button_leftIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_3x.32f3a186.png) - } -} - -.writeReview_footer .writeReview_private_button .button_text { - font-size: 13px; - font-weight: 700; - color: #fff -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button .button_text { - color: #626468 -} - -.forceDark .writeReview_footer .writeReview_private_button .button_text { - color: #fff -} - -.writeReview_footer .writeReview_private_button .button_rightIcon { - width: 7px; - height: 11px; - margin-left: 12px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white.1dbf14d1.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white_2x.ebdc774b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white_3x.b48b7cb1.png) - } -} - -.wr_whiteTheme .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_in_white_theme.b6e642ff.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_in_white_theme_2x.5fa2df54.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_in_white_theme_3x.7069dd5f.png) - } -} - -.forceDark .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white.1dbf14d1.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white_2x.ebdc774b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer .writeReview_private_button .button_rightIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_white_3x.b48b7cb1.png) - } -} - -.writeReview_footer .writeReview_submit_button { - float: right; - height: 32px; - line-height: 32px; - border-radius: 16px -} - -.forceDark .writeReview_footer .menu_option_containerBorder { - border-radius: 0; - border: 1px solid transparent -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer .menu_option_containerBorder { - position:relative; - border: 0 - } - - .forceDark .writeReview_footer .menu_option_containerBorder:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: 1px solid transparent; - transform: scale(.5); - transform-origin: 0 0; - box-sizing: border-box; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer .menu_option_containerBorder:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.writeReview_footer .menu_option_list { - background-color: #424242 -} - -.wr_whiteTheme .writeReview_footer .menu_option_list { - background-color: #fff -} - -.forceDark .writeReview_footer .menu_option_list { - background-color: #424242 -} - -.writeReview_footer .menu_option_list_link:hover { - background-color: #383838 -} - -.wr_whiteTheme .writeReview_footer .menu_option_list_link:hover { - background-color: #f5f6f8 -} - -.forceDark .writeReview_footer .menu_option_list_link:hover { - background-color: #383838 -} - -.forceDark .writeReview_footer .menu_option_list_link { - color: #b2b4b8 -} - -.writeReview_footer_Border { - padding: 24px 0; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer_Border { - position:relative; - border: 0 - } - - .writeReview_footer_Border:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer_Border:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .writeReview_footer_Border { - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer_Border { - position:relative; - border: 0 - } - - .wr_whiteTheme .writeReview_footer_Border:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer_Border:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.forceDark .writeReview_footer_Border { - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer_Border { - position:relative; - border: 0 - } - - .forceDark .writeReview_footer_Border:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer_Border:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.writeReview_footer_Menu_Icon { - float: left; - width: 16px; - height: 16px; - margin-right: 8px; - margin-top: 7px -} - -.writeReview_footer_Menu_Icon.publish { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish.358fd280.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_2x.553e0bed.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_3x.27d909ea.png) - } -} - -.wr_whiteTheme .writeReview_footer_Menu_Icon.publish { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white.ae002e9c.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white_2x.2ac860fd.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_white_3x.bf8af40e.png) - } -} - -.forceDark .writeReview_footer_Menu_Icon.publish { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish.358fd280.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_2x.553e0bed.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer_Menu_Icon.publish { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_publish_3x.27d909ea.png) - } -} - -.writeReview_footer_Menu_Icon.follow { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow.c3d1ac71.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_2x.27fd6f04.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_3x.3746bd05.png) - } -} - -.wr_whiteTheme .writeReview_footer_Menu_Icon.follow { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white.ae9b3d93.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white_2x.be45b6e8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_white_3x.18123b4d.png) - } -} - -.forceDark .writeReview_footer_Menu_Icon.follow { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow.c3d1ac71.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_2x.27fd6f04.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer_Menu_Icon.follow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_follow_3x.3746bd05.png) - } -} - -.writeReview_footer_Menu_Icon.secret { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret.ea0011c6.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_2x.3f6de91e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_3x.32f3a186.png) - } -} - -.wr_whiteTheme .writeReview_footer_Menu_Icon.secret { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white.144816b5.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white_2x.300be2d1.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_white_3x.5658597a.png) - } -} - -.forceDark .writeReview_footer_Menu_Icon.secret { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret.ea0011c6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .forceDark .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_2x.3f6de91e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .forceDark .writeReview_footer_Menu_Icon.secret { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_private_secret_3x.32f3a186.png) - } -} - -.writeReview_footer_Menu_Title { - display: block -} - -.writeReview_footer_Menu_Subtitle { - display: block; - margin-top: 5px; - font-size: 10px; - color: #8a8c90 -} - -.wr_whiteTheme .writeReview_footer_Menu_Subtitle { - color: #858c96 -} - -.forceDark .writeReview_footer_Menu_Subtitle { - color: #8a8c90 -} - -.writeReview_footer_Clear { - clear: both -} - -.book_ratings_button_container { - display: flex; - justify-content: space-between; - width: 100%; - margin-top: 24px -} - -.book_ratings_button { - font-family: PingFangSC-Medium,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 14px; - color: #9ea0a5; - width: calc((100% - 40px)/3); - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - height: 44px; - border-radius: 10px; - border: 1px solid transparent; - background-color: rgba(240,240,242,.1); - box-sizing: border-box -} - -.wr_whiteTheme .book_ratings_button { - color: #717882; - background-color: rgba(13,20,30,.04) -} - -.book_ratings_button_icon { - height: 16px; - width: 16px; - margin-right: 4px; - background-repeat: no-repeat; - background-size: 100% -} - -.book_ratings_button_Active { - color: #0097ff; - background-color: rgba(0,151,255,.1); - border-color: #0097ff -} - -.wr_whiteTheme .book_ratings_button_Active { - color: #1b88ee; - background-color: rgba(27,136,238,.1); - border-color: #1b88ee -} - -.book_ratings_button_Good .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_good_dark.79a1900c.svg) -} - -.book_ratings_button_Good.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_good_active_dark.7cecb98a.svg) -} - -.wr_whiteTheme .book_ratings_button_Good .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_good.23c1b3ef.svg) -} - -.wr_whiteTheme .book_ratings_button_Good.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_good_active.7d8047d3.svg) -} - -.book_ratings_button_Fair .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_fair_dark.064f832b.svg) -} - -.book_ratings_button_Fair.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_fair_active_dark.928002d0.svg) -} - -.wr_whiteTheme .book_ratings_button_Fair .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_fair.d6dfefe0.svg) -} - -.wr_whiteTheme .book_ratings_button_Fair.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_fair_active.741dd49a.svg) -} - -.book_ratings_button_Poor .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_poor_dark.d8b64a1f.svg) -} - -.book_ratings_button_Poor.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_poor_active_dark.d4ec78ac.svg) -} - -.wr_whiteTheme .book_ratings_button_Poor .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_poor.025c099b.svg) -} - -.wr_whiteTheme .book_ratings_button_Poor.book_ratings_button_Active .book_ratings_button_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_button_grade_poor_active.3b69abc9.svg) -} - -.writeReview_dialog_container { - width: 80%; - max-width: 600px; - height: 80%; - max-height: 600px -} - -.writeReview_dialog_container .wr_dialog_closeButton { - z-index: 2 -} - -.writeReview_dialog_header { - position: relative; - z-index: 1; - padding: 52px 16px 16px; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .writeReview_dialog_header { - position:relative; - border: 0 - } - - .writeReview_dialog_header:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .writeReview_dialog_header:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.writeReview_dialog_header .book_ratings_button_container { - margin-top: 0 -} - -.wr_whiteTheme .writeReview_dialog_header { - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .writeReview_dialog_header { - position:relative; - border: 0 - } - - .wr_whiteTheme .writeReview_dialog_header:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .writeReview_dialog_header:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.writeReview_dialog_starControl { - float: left -} - -.writeReview_dialog_content { - position: absolute; - left: 0; - right: 0; - top: 114px; - bottom: 0 -} - -.writeReview_dialog_content.disabled .writeReview_submit_button { - cursor: default; - opacity: .5 -} - -.writeReview_dialog_panel { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0 -} - -.readerWriteReviewPanel { - position: fixed; - z-index: 5; - bottom: 44px; - box-sizing: border-box; - width: 1000px; - padding-left: 100px; - padding-right: 100px; - height: 248px; - max-height: 80% -} - -@media(max-width: 1365px) { - .readerWriteReviewPanel { - width:760px; - padding-left: 72px; - padding-right: 72px - } -} - -@media(max-width: 1023px) { - .readerWriteReviewPanel { - width:560px; - padding-left: 36px; - padding-right: 36px - } -} - -@media(max-width: 767px) { - .readerWriteReviewPanel { - width:100%; - padding-left: 20px; - padding-right: 20px; - left: 0; - right: 0; - bottom: 82px - } -} - -.readerWriteReviewPanel .readerWriteReviewPanel_bg { - position: relative; - padding: 24px; - border-radius: 12px; - height: 100%; - box-sizing: border-box; - background-color: #2f2f2f -} - -@supports((-webkit-backdrop-filter: blur(40px)) or (backdrop-filter:blur(40px))) { - .readerWriteReviewPanel .readerWriteReviewPanel_bg { - background-color:rgba(50,50,50,.8); - -webkit-backdrop-filter: blur(40px); - backdrop-filter: blur(40px) - } -} - -.readerWriteReviewPanel .readerWriteReviewPanel_bg .closeButton { - position: absolute; - z-index: 6; - right: 16px; - top: 16px; - width: 20px; - height: 20px; - text-indent: -9999em; - overflow: hidden; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/dialog_close.a5f40ec8.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerWriteReviewPanel .readerWriteReviewPanel_bg .closeButton { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/dialog_close_2x.6b6a17c4.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerWriteReviewPanel .readerWriteReviewPanel_bg .closeButton { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/dialog_close_3x.7d071bf3.png) - } -} - -.readerWriteReviewPanel .disabled .writeReview_submit_button { - cursor: default; - opacity: .5 -} - -.reader_toolbar_color_container { - position: absolute; - padding: 10px; - border-radius: 999px; - background-color: #3a3c3e; - top: -54px; - left: 0; - display: flex; - gap: 12px; - flex-wrap: nowrap; - flex-direction: row -} - -.reader_toolbar_color_container .reader_toolbar_color_item { - width: 20px; - height: 20px; - border-radius: 999px; - display: flex; - justify-content: center; - align-items: center -} - -.reader_toolbar_color_container .reader_toolbar_color_item_selected { - width: 100%; - height: 100%; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/scribe_color_choice.e588ae99.png); - background-size: cover -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .reader_toolbar_color_container .reader_toolbar_color_item_selected { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/scribe_color_choice_2x.83c91c77.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .reader_toolbar_color_container .reader_toolbar_color_item_selected { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/scribe_color_choice_3x.73a313c3.png) - } -} - -.reader_toolbar_container { - z-index: 5; - position: absolute; - width: auto; - padding: 0 4px; - border-radius: 16px; - background-color: #3a3c3e; - max-width: 90% -} - -.reader_toolbar_container .arrow { - content: ""; - position: absolute; - bottom: -8px; - left: 50%; - margin-left: -8px; - border-top: 8px solid #3a3c3e; - border-left: 8px solid transparent; - border-right: 8px solid transparent -} - -.reader_toolbar_container.below .arrow { - bottom: auto; - top: -8px; - border-top: none; - border-bottom: 8px solid #3a3c3e -} - -.reader_toolbar_content { - overflow: auto -} - -.reader_toolbar_itemContainer { - display: flex; - flex-direction: row -} - -.toolbarItem { - width: 56px; - height: 68px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - flex-shrink: 0; - position: relative -} - -.toolbarItem .toolbarItem_icon { - position: relative; - display: inline-block; - width: 24px; - height: 24px -} - -.toolbarItem .toolbarItem_icon,.toolbarItem .toolbarItem_icon:after { - background-size: 100% 100%; - background-repeat: no-repeat; - transition: opacity .2s ease-in-out -} - -.toolbarItem .toolbarItem_icon:after { - content: ""; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - opacity: 0 -} - -.toolbarItem.selected,.toolbarItem:hover { - background: linear-gradient(180deg,rgba(0,0,0,.2),transparent) -} - -.toolbarItem.selected .toolbarItem_icon:after,.toolbarItem:hover .toolbarItem_icon:after { - opacity: 1 -} - -.toolbarItem .toolbarItem_text { - font-size: 11px; - color: #fff; - margin-top: 3px -} - -.toolbarItem.selected:after { - content: ""; - width: 4px; - height: 4px; - border-radius: 50%; - background: #0097ff; - position: absolute; - left: 50%; - margin-left: -2px; - bottom: 6px -} - -.underlineBg .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_bg.af6fb6a9.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_bg_2x.5bece330.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_bg_3x.3bf86da5.png) - } -} - -.underlineBg.selected .toolbarItem_icon,.underlineBg:hover .toolbarItem_icon { - background: none -} - -.underlineBg.selected .toolbarItem_icon:after,.underlineBg:hover .toolbarItem_icon:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow.55bcd033.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon:after,.underlineBg:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow_2x.0153f377.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon:after,.underlineBg:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow_3x.d467ff56.png) - } -} - -.underlineBg.selected .toolbarItem_icon_1:after,.underlineBg:hover .toolbarItem_icon_1:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_red.70e9bcd8.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon_1:after,.underlineBg:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_red_2x.9ddf61b8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon_1:after,.underlineBg:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_red_3x.c056b016.png) - } -} - -.underlineBg.selected .toolbarItem_icon_2:after,.underlineBg:hover .toolbarItem_icon_2:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_purple.d1228d84.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon_2:after,.underlineBg:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_purple_2x.ef7a2ebc.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon_2:after,.underlineBg:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_purple_3x.c385d321.png) - } -} - -.underlineBg.selected .toolbarItem_icon_3:after,.underlineBg:hover .toolbarItem_icon_3:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_blue.f1649f69.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon_3:after,.underlineBg:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_blue_2x.e66f3575.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon_3:after,.underlineBg:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_blue_3x.28551b12.png) - } -} - -.underlineBg.selected .toolbarItem_icon_4:after,.underlineBg:hover .toolbarItem_icon_4:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_green.a882b3a8.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon_4:after,.underlineBg:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_green_2x.c40e6460.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon_4:after,.underlineBg:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_green_3x.b6aad8fa.png) - } -} - -.underlineBg.selected .toolbarItem_icon_5:after,.underlineBg:hover .toolbarItem_icon_5:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow.55bcd033.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineBg.selected .toolbarItem_icon_5:after,.underlineBg:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow_2x.0153f377.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineBg.selected .toolbarItem_icon_5:after,.underlineBg:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_mark_yellow_3x.d467ff56.png) - } -} - -.underlineHandWrite .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_handwrite.fe9a7d52.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_handwrite_2x.5605bd22.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_handwrite_3x.938774d8.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon:after,.underlineHandWrite:hover .toolbarItem_icon:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue.b71d682a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon:after,.underlineHandWrite:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue_2x.4e7da08b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon:after,.underlineHandWrite:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue_3x.c5372d6a.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon_1:after,.underlineHandWrite:hover .toolbarItem_icon_1:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_red.0e29e9ab.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon_1:after,.underlineHandWrite:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_red_2x.ced36585.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon_1:after,.underlineHandWrite:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_red_3x.383ae6b6.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon_2:after,.underlineHandWrite:hover .toolbarItem_icon_2:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_purple.dddf451b.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon_2:after,.underlineHandWrite:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_purple_2x.0f2e6060.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon_2:after,.underlineHandWrite:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_purple_3x.e4b7bc42.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon_3:after,.underlineHandWrite:hover .toolbarItem_icon_3:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue.b71d682a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon_3:after,.underlineHandWrite:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue_2x.4e7da08b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon_3:after,.underlineHandWrite:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_blue_3x.c5372d6a.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon_4:after,.underlineHandWrite:hover .toolbarItem_icon_4:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_green.bf638a30.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon_4:after,.underlineHandWrite:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_green_2x.07e10fcf.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon_4:after,.underlineHandWrite:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_green_3x.4176fd8a.png) - } -} - -.underlineHandWrite.selected .toolbarItem_icon_5:after,.underlineHandWrite:hover .toolbarItem_icon_5:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_yellow.ad1771f6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineHandWrite.selected .toolbarItem_icon_5:after,.underlineHandWrite:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_yellow_2x.97ec9e31.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineHandWrite.selected .toolbarItem_icon_5:after,.underlineHandWrite:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_wave_yellow_3x.b0501245.png) - } -} - -.underlineStraight .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_straight.ffe7184a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_straight_2x.40206067.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_straight_3x.acfbf17e.png) - } -} - -.underlineStraight.selected .toolbarItem_icon:after,.underlineStraight:hover .toolbarItem_icon:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red.02ee9d45.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon:after,.underlineStraight:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red_2x.ba500dc8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon:after,.underlineStraight:hover .toolbarItem_icon:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red_3x.0ce8dcdb.png) - } -} - -.underlineStraight.selected .toolbarItem_icon_1:after,.underlineStraight:hover .toolbarItem_icon_1:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red.02ee9d45.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon_1:after,.underlineStraight:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red_2x.ba500dc8.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon_1:after,.underlineStraight:hover .toolbarItem_icon_1:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_red_3x.0ce8dcdb.png) - } -} - -.underlineStraight.selected .toolbarItem_icon_2:after,.underlineStraight:hover .toolbarItem_icon_2:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_purple.90a9b5e6.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon_2:after,.underlineStraight:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_purple_2x.35765795.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon_2:after,.underlineStraight:hover .toolbarItem_icon_2:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_purple_3x.1a39dc3d.png) - } -} - -.underlineStraight.selected .toolbarItem_icon_3:after,.underlineStraight:hover .toolbarItem_icon_3:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_blue.71849a1a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon_3:after,.underlineStraight:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_blue_2x.a955b588.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon_3:after,.underlineStraight:hover .toolbarItem_icon_3:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_blue_3x.70e962db.png) - } -} - -.underlineStraight.selected .toolbarItem_icon_4:after,.underlineStraight:hover .toolbarItem_icon_4:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_green.52aad9f4.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon_4:after,.underlineStraight:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_green_2x.3bd5e3be.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon_4:after,.underlineStraight:hover .toolbarItem_icon_4:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_green_3x.2caab597.png) - } -} - -.underlineStraight.selected .toolbarItem_icon_5:after,.underlineStraight:hover .toolbarItem_icon_5:after { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_yellow.9309c6d4.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .underlineStraight.selected .toolbarItem_icon_5:after,.underlineStraight:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_yellow_2x.4cac8853.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .underlineStraight.selected .toolbarItem_icon_5:after,.underlineStraight:hover .toolbarItem_icon_5:after { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_straight_yellow_3x.1fdc3286.png) - } -} - -.copy .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_copy.07fe36df.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .copy .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_copy_2x.f9444afc.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .copy .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_copy_3x.17ca4d6c.png) - } -} - -.removeUnderline .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_remove.d3a8e13b.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .removeUnderline .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_remove_2x.3667fb2a.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .removeUnderline .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_underline_remove_3x.c5b16f4c.png) - } -} - -.review .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_review.fcb1e862.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .review .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_review_2x.90fb13ee.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .review .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_review_3x.7e6da5c1.png) - } -} - -.query .toolbarItem_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_query.ba0f29c3.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .query .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_query_2x.1d02e607.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .query .toolbarItem_icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_toolbar_query_3x.21d38c44.png) - } -} - -.readerReviewDetailPanel { - -webkit-user-select: text; - -moz-user-select: text; - -ms-user-select: text; - user-select: text; - position: fixed; - z-index: 5; - bottom: 0; - box-sizing: border-box; - width: 1000px; - padding-left: 100px; - padding-right: 100px; - padding-bottom: 44px -} - -@media(max-width: 1365px) { - .readerReviewDetailPanel { - width:760px; - padding-left: 72px; - padding-right: 72px - } -} - -@media(max-width: 1023px) { - .readerReviewDetailPanel { - width:560px; - padding-left: 36px; - padding-right: 36px - } -} - -@media(max-width: 767px) { - .readerReviewDetailPanel { - width:100%; - padding-left: 20px; - padding-right: 20px; - left: 0; - right: 0; - bottom: 82px - } -} - -.readerReviewDetailPanel .readerReviewDetailPanel_bg { - max-height: 300px; - overflow-y: auto; - padding: 24px; - border-radius: 12px; - background-color: #2f2f2f -} - -@supports((-webkit-backdrop-filter: blur(40px)) or (backdrop-filter:blur(40px))) { - .readerReviewDetailPanel .readerReviewDetailPanel_bg { - background-color:rgba(50,50,50,.8); - -webkit-backdrop-filter: blur(40px); - backdrop-filter: blur(40px) - } -} - -.readerReviewDetailPanel .readerReviewDetail_item { - margin-bottom: 36px -} - -.readerReviewDetailPanel .readerReviewDetail_item:last-child { - margin-bottom: 0 -} - -.readerReviewDetailPanel .title { - display: flex; - flex-direction: row; - align-items: center -} - -.readerReviewDetailPanel .avatar { - flex: none; - width: 18px; - height: 18px; - margin-right: 6px -} - -.readerReviewDetailPanel .name { - flex: auto; - font-size: 14px; - color: #8a8c90; - margin-right: 12px -} - -.readerReviewDetailPanel .status { - font-size: 12px; - color: #b2b4b8 -} - -.readerReviewDetailPanel .status .icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - margin-right: 4px -} - -.readerReviewDetailPanel .private .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_detail_private.066076ea.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerReviewDetailPanel .private .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_detail_private_2x.84b22f08.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerReviewDetailPanel .private .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_detail_private_3x.f5f88368.png) - } -} - -.readerReviewDetailPanel .content { - margin-top: 12px; - color: #fff; - font-size: 17px; - line-height: 28px; - max-height: 216px; - overflow: scroll; - overflow-x: hidden; - word-break: break-all -} - -.readerReviewDetailPanel .content::-webkit-scrollbar { - width: 8px; - box-shadow: none; - border: 0 -} - -.readerReviewDetailPanel .content::-webkit-scrollbar-track,.readerReviewDetailPanel .content::-webkit-scrollbar-track-piece { - opacity: 0 -} - -.readerReviewDetailPanel .content::-webkit-scrollbar-thumb { - border-radius: 10px; - background: rgba(0,0,0,.3) -} - -.readerReviewDetailPanel .actions { - margin-top: 12px -} - -.readerReviewDetailPanel .actionItem { - font-size: 14px; - color: #0097ff -} - -.readerDictQueryPanel { - width: 80%; - max-width: 500px; - max-height: 100%; - overflow-y: auto; - box-sizing: border-box; - padding-top: 18px; - padding-bottom: 18px -} - -.readerDictQueryPanel .readerDictQueryPanel_content { - text-align: left -} - -.readerDictQueryPanel .readerDictQueryPanel_bg { - padding: 24px; - border-radius: 12px; - background-color: #2f2f2f -} - -@supports((-webkit-backdrop-filter: blur(40px)) or (backdrop-filter:blur(40px))) { - .readerDictQueryPanel .readerDictQueryPanel_bg { - background-color:rgba(50,50,50,.8); - -webkit-backdrop-filter: blur(40px); - backdrop-filter: blur(40px) - } -} - -.readerDictQueryPanel .readerDictQueryPanel_item { - display: block; - cursor: default; - margin-bottom: 16px -} - -.readerDictQueryPanel .readerDictQueryPanel_item:last-child { - margin-bottom: 0 -} - -.readerDictQueryPanel .readerDictQueryPanel_link { - cursor: pointer -} - -.readerDictQueryPanel .readerDictQueryPanel_link:hover { - background-color: #242424 -} - -.readerDictQueryPanel .keyword { - color: #eef0f4; - font-size: 22px; - font-weight: 500; - line-height: 24px; - overflow: hidden; - height: 24px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - height: auto; - max-height: 24px -} - -.readerDictQueryPanel .status { - margin-top: 6px; - color: #8a8c90; - font-size: 15px -} - -.readerDictQueryPanel .smallTitleText { - margin-top: 8px; - color: #8a8c90; - font-size: 14px; - line-height: 16px; - height: 16px; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - height: auto; - max-height: 16px -} - -.readerDictQueryPanel .contentText,.readerDictQueryPanel .smallTitleText { - overflow: hidden; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical -} - -.readerDictQueryPanel .contentText { - margin-top: 5px; - color: #d0d3d8; - font-size: 15px; - line-height: 22px; - height: 66px; - -webkit-line-clamp: 3; - -moz-line-clamp: 3; - line-clamp: 3; - height: auto; - max-height: 66px -} - -.readerDictQueryPanel .contentHeadText { - color: #8a8c90 -} - -.readerDictQueryPanel .titleText { - color: #eef0f4; - font-size: 16px; - font-weight: 500; - overflow: hidden -} - -.readerDictQueryPanel .titleText .iconArrow { - float: right; - width: 7px; - height: 11px; - margin-top: 6px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray.0cf9af2a.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerDictQueryPanel .titleText .iconArrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_2x.6197cb85.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerDictQueryPanel .titleText .iconArrow { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_right_gray_3x.7d0708bf.png) - } -} - -.readerMemberCardTips { - padding-top: 10px; - padding-bottom: 10px; - background-color: #363636 -} - -.wr_whiteTheme .readerMemberCardTips { - background-color: #faf6ec -} - -.readerMemberCardTips .icon { - margin-right: 10px; - display: inline-block; - width: 20px; - height: 20px; - vertical-align: middle; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard.d62464ba.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerMemberCardTips .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard_2x.09a1ca77.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerMemberCardTips .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard_3x.3a0d140e.png) - } -} - -.wr_whiteTheme .readerMemberCardTips .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard_white.ce32fa7f.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerMemberCardTips .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard_white_2x.55337120.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerMemberCardTips .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_tips_membercard_white_3x.653fd938.png) - } -} - -.readerMemberCardTips .text { - vertical-align: middle; - font-size: 14px; - color: #e7d1a1 -} - -.wr_whiteTheme .readerMemberCardTips .text { - color: #8c6e2c -} - -.review_starControl_content { - position: relative; - cursor: pointer -} - -.review_starControl_title { - margin-bottom: 8px; - font-size: 14px; - color: #8a8c90 -} - -.wr_whiteTheme .review_starControl_title { - color: #858c96 -} - -.review_starControl_normal,.review_starControl_selected { - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: space-between; - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100% -} - -.review_starControl_normal { - z-index: 1 -} - -.review_starControl_selected { - z-index: 2 -} - -.normal_starItem,.selected_starItem,.selected_starItem_Placeholder { - width: 24px; - height: 24px -} - -.normal_starItem { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star.93f13e0c.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .normal_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_2x.21ea947b.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .normal_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_3x.d715706b.png) - } -} - -.wr_whiteTheme .normal_starItem { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_white.5613d386.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .normal_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_white_2x.3f96762e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .normal_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_white_3x.7ba61105.png) - } -} - -.selected_starItem { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected.b9785450.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .selected_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected_2x.7e6e2f5e.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .selected_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected_3x.95a4286a.png) - } -} - -.wr_whiteTheme .selected_starItem { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected_white.48a5c7bb.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .selected_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected_white_2x.fad83b2f.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .selected_starItem { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/review_blue_star_selected_white_3x.4bb1801a.png) - } -} - -.wr_ratingLevelBar { - display: flex; - align-items: center -} - -.wr_ratingLevelBar_icon { - width: 14px; - height: 14px; - background-repeat: no-repeat; - background-size: 100% -} - -.wr_ratingLevelBar_text { - margin-left: 3px; - color: #78787a; - line-height: 20px; - font-size: 14px; - font-weight: 500 -} - -.wr_whiteTheme .wr_ratingLevelBar_text { - color: #99a0aa -} - -.wr_ratingLevelBar_Good .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_good_dark_3x.0d78c334.png) -} - -.wr_whiteTheme .wr_ratingLevelBar_Good .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_good_3x.0d78c334.png) -} - -.wr_ratingLevelBar_Fair .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_fair_dark_3x.2f7a6dfd.png) -} - -.wr_whiteTheme .wr_ratingLevelBar_Fair .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_fair_3x.05687180.png) -} - -.wr_ratingLevelBar_Poor .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_poor_dark_3x.dd24e2b9.png) -} - -.wr_whiteTheme .wr_ratingLevelBar_Poor .wr_ratingLevelBar_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_grade_poor_3x.dd24e2b9.png) -} - -@font-face { - font-family: WeChatNumber; - src: url(data:font/truetype;charset=utf-8;base64,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) format("truetype"); - font-style: normal; - font-weight: 400 -} - -@font-face { - font-family: DIN-Light; - src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format("truetype"); - font-style: normal; - font-weight: 400 -} - -@font-face { - font-family: DIN-Regular; - src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format("truetype"); - font-style: normal; - font-weight: 400 -} - -@font-face { - font-family: DIN-Medium; - src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format("truetype"); - font-style: normal; - font-weight: 400 -} - -@font-face { - font-family: DIN-Bold; - src: url(data:application/x-font-ttf;charset=utf-8;base64,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) format("truetype"); - font-style: normal; - font-weight: 400 -} - -@font-face { - font-family: "SourceHanSerifCN-Bold"; - src: url(https://rescdn.qqmail.com/weread/assets/mini_program/SourceHanSerifCN-Bold.ttf) format("truetype"); - font-style: normal; - font-weight: 400; - font-display: swap -} - -body,html { - height: 100%; - -webkit-touch-callout: none -} - -body { - height: 100%; - font-family: PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - -webkit-font-size-adjust: none; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale -} - -a { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -a:active,a:hover { - text-decoration: none -} - -button { - background: none; - border: 0; - padding: 0; - text-decoration: none; - cursor: pointer -} - -input,textarea { - margin: 0; - padding: 0; - border: 0 -} - -.frame_wrap { - padding-bottom: 20px; - min-width: 320px -} - -textarea { - overflow: auto -} - -.wr_hide { - display: none!important -} - -.wr_show { - display: block!important -} - -.wr_txtLineThrough { - text-decoration: line-through -} - -.wr_fade { - transition: opacity .25s; - opacity: 0 -} - -.wr_fade_Show { - opacity: 1 -} - -.bookReviewList_item.clickable { - cursor: pointer -} - -.reader_topReview_container { - padding-top: 16px; - margin-left: 100px; - margin-right: 100px -} - -@media(max-width: 1365px) { - .reader_topReview_container { - margin-left:72px; - margin-right: 72px - } -} - -@media(max-width: 1023px) { - .reader_topReview_container { - margin-left:36px; - margin-right: 36px - } -} - -@media(max-width: 767px) { - .reader_topReview_container { - margin-left:20px; - margin-right: 20px - } -} - -.reader_topReview_header { - overflow: hidden; - margin-bottom: 20px -} - -.bookReviewList_title,.reader_topReview_title { - font-size: 16px; - font-family: PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-weight: 500; - color: #eef0f4 -} - -.wr_whiteTheme .bookReviewList_title,.wr_whiteTheme .reader_topReview_title { - color: #212832 -} - -.reader_topReview_starControl { - margin-top: -28px; - float: right -} - -.bookReviewList_item,.reader_topReview_item { - background: rgba(240,240,242,.1); - padding: 20px; - border-radius: 12px; - margin-bottom: 20px -} - -.wr_whiteTheme .bookReviewList_item,.wr_whiteTheme .reader_topReview_item { - background: rgba(13,20,30,.04) -} - -.bookReviewList_item .avatar,.reader_topReview_item .avatar { - width: 20px!important; - height: 20px!important; - display: inline-block!important; - vertical-align: middle!important; - margin-right: 6px -} - -.bookReviewList_item .title,.reader_topReview_item .title { - display: flex; - align-items: center -} - -.bookReviewList_item .name,.reader_topReview_item .name { - font-size: 14px; - font-weight: 500; - display: inline-block; - vertical-align: middle; - margin-right: 6px; - line-height: 20px; - color: #a0a0a2 -} - -.wr_whiteTheme .bookReviewList_item .name,.wr_whiteTheme .reader_topReview_item .name { - color: #717882 -} - -.bookReviewList_item .content,.reader_topReview_item .content { - margin-top: 8px; - line-height: 25px; - font-size: 16px; - text-align: justify; - color: #fff -} - -.wr_whiteTheme .bookReviewList_item .content,.wr_whiteTheme .reader_topReview_item .content { - color: #0d141e -} - -.bookReviewList_item .content_Normal,.reader_topReview_item .content_Normal { - position: relative; - line-height: 25px; - overflow: hidden; - height: 125px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 5; - -moz-line-clamp: 5; - line-clamp: 5; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - height: auto; - max-height: 125px -} - -.reader_topReview_footer { - padding: 0 0 16px -} - -.wr_whiteTheme .reader_topReview_footer { - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .reader_topReview_footer { - position:relative; - border: 0 - } - - .wr_whiteTheme .reader_topReview_footer:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .reader_topReview_footer:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.reader_topReview_more { - font-size: 15px; - font-weight: 700; - color: #0097ff -} - -.wr_whiteTheme .reader_topReview_more { - color: #1b88ee -} - -.reader_topReview_more:hover { - text-decoration: underline -} - -.reader_topReview_more_button { - border: 0; - background: hsla(0,0%,100%,.03); - border-radius: 10px; - font-size: 14px; - color: #b2b4b8; - text-align: center; - line-height: 20px; - padding: 12px; - width: 100%; - font-weight: 500 -} - -.wr_whiteTheme .reader_topReview_more_button { - background: rgba(13,20,30,.03); - color: #5d646e -} - -.readerNotePanel { - position: fixed; - background-color: #262628; - width: 520px; - left: 50%; - top: 0; - bottom: 0; - z-index: 90; - margin-left: -20px; - box-shadow: -20px 0 20px 0 rgba(0,0,0,.1); - display: flex; - flex-direction: column -} - -.wr_whiteTheme .readerNotePanel { - background-color: #f4f5f7 -} - -@media(max-width: 1365px) { - .readerNotePanel { - margin-left:-140px - } -} - -@media(max-width: 1023px) { - .readerNotePanel { - width:560px; - margin-left: -280px - } -} - -@media(max-width: 767px) { - .readerNotePanel { - width:100%; - margin-left: 0; - left: 0; - right: 0; - top: 88px; - bottom: 56px - } -} - -.readerNoteList { - flex: auto; - overflow: auto; - padding-bottom: env(safe-area-inset-bottom) -} - -.noteItem_content { - display: flex; - flex-direction: row; - align-items: flex-start -} - -.noteItem_content .icon { - margin-top: 4px; - display: inline-block; - flex-shrink: 0; - width: 24px; - height: 24px; - margin-right: 12px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline.2d994025.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .noteItem_content .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline_2x.514e9a95.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .noteItem_content .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline_3x.e7494112.png) - } -} - -.wr_whiteTheme .noteItem_content .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline_white.19d9d8bc.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .noteItem_content .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline_white_2x.8256d8cb.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .noteItem_content .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_underline_white_3x.bdaa80d9.png) - } -} - -.noteItem_content .wr_ratingLevelBar { - margin-top: 2px -} - -.noteItem_content .text { - margin-top: 3px; - font-size: 15px; - color: #eef0f4; - line-height: 24px; - overflow: hidden; - height: 120px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 5; - -moz-line-clamp: 5; - line-clamp: 5; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - height: auto; - max-height: 120px -} - -.wr_whiteTheme .noteItem_content .text { - color: #212832 -} - -.noteItem_content .abstract { - margin-top: 12px; - font-size: 14px; - color: #8a8c90; - line-height: 24px; - overflow: hidden; - height: 72px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 3; - -moz-line-clamp: 3; - line-clamp: 3; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - height: auto; - max-height: 72px; - border-left: 2px solid rgba(138,140,144,.3); - padding-left: 10px -} - -.wr_whiteTheme .noteItem_content .abstract { - color: #858c96; - border-left-color: rgba(133,140,150,.3) -} - -.noteItem_content_review .icon { - margin-top: 4px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review.6dddb62c.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .noteItem_content_review .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review_2x.f3f14cea.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .noteItem_content_review .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review_3x.b9a0922d.png) - } -} - -.wr_whiteTheme .noteItem_content_review .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review_white.b357af3a.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .noteItem_content_review .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review_white_2x.31be45bb.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .noteItem_content_review .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_review_white_3x.d38a23ec.png) - } -} - -.noteItem_content_bookmark .icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark.39f0dfc1.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .noteItem_content_bookmark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark_2x.f65b7cbf.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .noteItem_content_bookmark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark_3x.d972e6bb.png) - } -} - -.wr_whiteTheme .noteItem_content_bookmark .icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark_white.42e86502.png) -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .noteItem_content_bookmark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark_white_2x.d46bce59.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .noteItem_content_bookmark .icon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_notelist_bookmark_white_3x.733161e2.png) - } -} - -.readerNotePanelBottomBar { - padding: 15px 36px; - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerNotePanelBottomBar { - position:relative; - border: 0 - } - - .readerNotePanelBottomBar:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid hsla(0,0%,100%,.05); - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerNotePanelBottomBar:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .readerNotePanelBottomBar { - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerNotePanelBottomBar { - position:relative; - border: 0 - } - - .wr_whiteTheme .readerNotePanelBottomBar:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #ebedf1; - border-width: 1px 0 0; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerNotePanelBottomBar:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.readerNotePanelBottomBarContentTitle { - font-weight: 500; - font-size: 15px; - line-height: 22px; - color: #eef0f4; - font-family: DIN-Medium,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif -} - -.wr_whiteTheme .readerNotePanelBottomBarContentTitle { - color: #212832 -} - -.readerNotePanelBottomBarContentDesc { - font-size: 11px; - line-height: 22px; - color: #8a8c90 -} - -.wr_whiteTheme .readerNotePanelBottomBarContentDesc { - color: #858c96 -} - -.readerNotePanelBottomBarActionButton { - background: linear-gradient(90deg,#0087fc,#28b7ff); - border-radius: 65px; - padding: 9px 20px; - font-size: 15px; - line-height: 22px; - color: #fff; - font-weight: 500 -} - -.book_rating_item_bar { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - font-size: 12px; - font-family: PingFangSC-Medium,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - color: #8a8c90; - line-height: 16px -} - -.wr_whiteTheme .book_rating_item_bar { - color: #858c96 -} - -.book_rating_item_bar_background { - flex: 1; - background-color: hsla(0,0%,100%,.04); - border-radius: 3px; - margin-left: 8px; - height: 5px; - overflow: hidden -} - -.wr_whiteTheme .book_rating_item_bar_background { - background-color: rgba(13,20,30,.04) -} - -.book_rating_item_bar_content { - height: 100%; - background-color: hsla(0,0%,100%,.35); - border-radius: 3px -} - -.wr_whiteTheme .book_rating_item_bar_content { - background-color: rgba(13,20,30,.35) -} - -.book_rating_item_label { - flex: 1; - display: flex -} - -.book_rating_item_label_text { - font-family: "SourceHanSerifCN-H",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-weight: 500; - font-size: 22px; - color: #c6c8cc -} - -.wr_whiteTheme .book_rating_item_label_text { - color: #49505a -} - -.book_rating_item_label_number { - font-family: DIN-Bold,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 36px; - color: #0097ff -} - -.wr_whiteTheme .book_rating_item_label_number { - color: #1b88ee -} - -.book_rating_item_label_number_suffix { - font-size: 20px -} - -.book_rating_item_label_number_image { - width: auto; - height: 36px -} - -.book_rating_item_label_number.book_rating_item_label_ListItem,.book_rating_item_label_number_image.book_rating_item_label_ListItem,.book_rating_item_label_text.book_rating_item_label_ListItem { - flex-shrink: 0; - margin-left: 8px -} - -.book_rating_item_label_text.book_rating_item_label_ListItem { - font-size: 14px -} - -.book_rating_item_label_number_image.book_rating_item_label_ListItem { - height: 22px -} - -.book_rating_item_label_number.book_rating_item_label_ListItem,.book_rating_item_label_number.book_rating_item_label_ListItem .book_rating_item_label_number_suffix { - font-size: 15px -} - -.book_rating_item_container { - display: flex; - flex-direction: row; - margin-top: 10px; - align-items: center -} - -.book_rating_item_container_Clickable:active { - opacity: .5 -} - -.book_rating_item_detail { - display: flex; - flex-direction: column; - justify-content: center -} - -.book_rating_item_detail img { - margin-top: 4px -} - -.book_rating_item_detail_count { - display: flex; - flex-direction: row; - align-items: center; - font-family: DIN-Medium,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 12px; - color: #8a8c90; - line-height: 16px -} - -.wr_whiteTheme .book_rating_item_detail_count { - color: #858c96 -} - -.book_rating_item_detail_count_icon { - margin-left: 2px; - height: 12px; - width: 6px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_item_detail_count_icon_dark.986b2933.svg) 50% no-repeat; - background-size: 100% -} - -.wr_whiteTheme .book_rating_item_detail_count_icon { - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/book_ratings_item_detail_count_icon.115b4b50.svg) -} - -.book_rating_item_label_number+.book_rating_item_detail_count { - margin-top: 3px -} - -img+.book_rating_item_detail_count { - margin-top: 10px -} - -.book_rating_item_bar_container { - flex: 1; - margin: 11px 0 0 20px -} - -.book_rating_item_bar_margin { - margin: 8px 0 -} - -.book_ratings_header { - display: flex; - font-family: DIN-Medium,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 500; - color: #eef0f4 -} - -.wr_whiteTheme .book_ratings_header { - color: #212832 -} - -.book_ratings_tag_container { - padding-bottom: 20px; - margin-bottom: 20px; - display: flex; - flex-direction: row; - border-radius: 0; - border: solid #dee0e2; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .book_ratings_tag_container { - position:relative; - border: 0 - } - - .book_ratings_tag_container:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #dee0e2; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - box-sizing: border-box; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .book_ratings_tag_container:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.book_ratings_tag_item { - padding: 4px 12px; - font-family: PingFangSC-Regular,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 12px; - color: #9ea0a5; - border-radius: 13px; - border: 1px solid #dee0e2 -} - -.wr_whiteTheme .book_ratings_tag_item { - color: #717882 -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .book_ratings_tag_item { - position:relative; - border: 0 - } - - .book_ratings_tag_item:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 26px; - border: 1px solid #dee0e2; - transform: scale(.5); - transform-origin: 0 0; - box-sizing: border-box; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .book_ratings_tag_item:after { - width:300%; - height: 300%; - border-radius: 39px; - transform: scale(.3333333333) - } -} - -.isLooking { - padding: 32px 0 -} - -.isLooking_footer_wrapper { - display: flex; - justify-content: space-between; - align-items: center -} - -.isLooking_footer { - color: hsla(0,0%,100%,.3); - font-size: 15px; - line-height: 21px; - text-shadow: none!important -} - -.wr_whiteTheme .isLooking_footer { - color: rgba(0,0,0,.3) -} - -.isLooking_link { - color: #7d90a9; - font-size: 15px; - line-height: 21px; - display: flex; - align-items: center -} - -.wr_whiteTheme .isLooking_link { - color: #576b95 -} - -.isLooking_link_Selected { - color: #cc9c00 -} - -.wr_whiteTheme .isLooking_link_Selected { - color: #ffc300 -} - -.isLooking_icon { - width: 24px; - height: 24px; - margin-right: 4px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_outlined_news_dark_3x.d53631e6.svg) no-repeat 50%; - background-size: cover -} - -.wr_whiteTheme .isLooking_icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_outlined_news_light_3x.8768dad0.svg) no-repeat 50%; - background-size: cover -} - -.isLooking_icon_Selected { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_outlined_news_selected_dark_3x.3dd4f788.svg) no-repeat 50%; - background-size: cover -} - -.wr_whiteTheme .isLooking_icon_Selected { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_outlined_news_selected_light_3x.fd7c9c03.svg) no-repeat 50%; - background-size: cover -} - -.isLooking_amount { - margin-left: 4px -} - -.isLooking_bubble { - margin: 16px 0 0; - width: 100%; - border-radius: 8px; - background: #2c2c2c; - padding: 16px 0; - position: relative -} - -.wr_whiteTheme .isLooking_bubble { - background: #f7f7f7 -} - -.isLooking_bubble_content { - display: flex; - align-items: center; - justify-content: center; - letter-spacing: .35px -} - -.isLooking_bubble_icon { - height: 20px; - width: 20px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_filled_done_dark_3x.0d2f4437.svg) no-repeat 50%; - background-size: cover; - margin-right: 4px; - transform: translateY(-.5px) -} - -.wr_whiteTheme .isLooking_bubble_icon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icons_filled_done_light_3x.9d1edd54.svg) no-repeat 50%; - background-size: cover -} - -.isLooking_bubble_text { - color: hsla(0,0%,100%,.8); - font-size: 15px; - line-height: 21px; - margin-right: 8px -} - -.wr_whiteTheme .isLooking_bubble_text { - color: rgba(0,0,0,.9) -} - -.isLooking_bubble_link { - color: #7d90a9; - font-size: 15px; - line-height: 21px; - margin-right: 4px -} - -.wr_whiteTheme .isLooking_bubble_link { - color: #576b95 -} - -.isLooking_bubble_arrow { - height: 11px; - width: 6px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_dark_3x.d7d18502.png) no-repeat 50%; - background-size: cover -} - -.wr_whiteTheme .isLooking_bubble_arrow { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/arrow_light_3x.23cb9a09.png) no-repeat 50%; - background-size: cover -} - -.isLooking_bubble_triangle { - position: absolute; - background: #2c2c2c; - height: 25px; - width: 14px; - border-radius: 2px; - transform: rotate(45deg); - right: 24px; - top: -8px -} - -.wr_whiteTheme .isLooking_bubble_triangle { - background: #f7f7f7 -} - -.comment-area__btn { - font-size: 16px -} - -.wr_btn { - position: relative; - display: inline-block; - height: 28px; - padding: 0 15px; - min-width: 34px; - line-height: 28px; - font-size: 13px; - font-weight: 500; - text-align: center; - background: linear-gradient(90deg,#0087fc,#28b7ff); - border-radius: 14px; - color: #fff!important; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} - -.wr_btn:hover { - text-decoration: none -} - -.wr_btn[disabled],.wr_btn_Disabled { - opacity: .5 -} - -.wr_btn_originalPrice { - margin-left: 3px; - padding: 0 2px; - position: relative; - color: #1b88ee -} - -.wr_btn_originalPrice:after { - content: ""; - position: absolute; - top: 0; - right: -1px; - bottom: 0; - left: -1px; - margin: auto; - height: 1px; - background: #999 -} - -.wr_btn .wr_loading { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - margin: auto; - font-size: 24px -} - -.wr_btn .wr_loading_blade { - background: #fff -} - -.wr_btn_Big { - display: block; - height: 40px; - line-height: 40px; - font-size: 15px; - border-radius: 20px; - padding: 0 28px -} - -.wr_btn_Gray { - background: #eaeef5; - color: #1b88ee!important -} - -.wr_btn_Gold { - background: linear-gradient(45deg,#d7bb7f,#eddaaf); - color: #4f3a19!important -} - -.wr_btn_Red { - background-image: linear-gradient(180deg,#ff2214 0,#ff5e2b); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFF2214",endColorstr="#FFFF5E2B",GradientType=0); - box-shadow: 0 6px 24px 0 rgba(229,62,47,.2) -} - -.wr_btn_Red,.wr_btn_RedicalRed { - background-repeat: repeat-x; - color: #fff!important -} - -.wr_btn_RedicalRed { - background-image: linear-gradient(90deg,#e94348 0,#ea4957 62%,#ea4c60); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFE94348",endColorstr="#FFEA4C60",GradientType=1) -} - -.wr_btn_Ghost { - border: 1px solid rgba(0,0,0,.05); - background: none!important; - color: #1b88ee!important; - height: 24px; - line-height: 26px; - font-size: 12px; - padding: 0 12px -} - -.wr_btn_WithIcon { - display: flex; - justify-content: center; - align-items: center -} - -.readerTopStoriesBookInfo { - padding-top: 24px; - margin: 0 16px; - overflow: hidden; - --BG-0: #111; - --BG-1: #1e1e1e; - --BG-2: #191919; - --BG-3: #202020; - --BG-4: #404040; - --BG-5: #2c2c2c; - --FG-0: hsla(0,0%,100%,0.8); - --FG-HALF: hsla(0,0%,100%,0.6); - --FG-1: hsla(0,0%,100%,0.5); - --FG-2: hsla(0,0%,100%,0.3); - --FG-3: hsla(0,0%,100%,0.05); - --ORANGE: #c87d2f; - --YELLOW: #cc9c00; - --GREEN: #74a800; - --LIGHTGREEN: #3eb575; - --INDIGO: #1196ff; - --PURPLE: #8183ff; - --WHITE: hsla(0,0%,100%,0.8); - --LINK: #7d90a9; - --TEXTGREEN: #259c5c; - --FG: #fff; - --BG: #000; - --TAG-TEXT-ORANGE: rgba(250,157,59,0.6); - --TAG-TEXT-GREEN: rgba(6,174,86,0.6); - --TAG-TEXT-BLUE: rgba(16,174,255,0.6); - --TAG-TEXT-BLACK: hsla(0,0%,100%,0.5); - --TAG-BACKGROUND-BLACK: hsla(0,0%,100%,0.05) -} - -.readerTopStoriesBookInfo,.wr_whiteTheme .readerTopStoriesBookInfo { - --RED: #fa5151; - --BRAND: #07c160; - --BLUE: #10aeff; - --TAG-BACKGROUND-ORANGE: rgba(250,157,59,0.1); - --TAG-BACKGROUND-GREEN: rgba(6,174,86,0.1); - --TAG-BACKGROUND-BLUE: rgba(16,174,255,0.1) -} - -.wr_whiteTheme .readerTopStoriesBookInfo { - --BG-0: #ededed; - --BG-1: #f7f7f7; - --BG-2: #fff; - --BG-3: #f7f7f7; - --BG-4: #4c4c4c; - --BG-5: #fff; - --FG-0: rgba(0,0,0,0.9); - --FG-HALF: rgba(0,0,0,0.9); - --FG-1: rgba(0,0,0,0.5); - --FG-2: rgba(0,0,0,0.3); - --FG-3: rgba(0,0,0,0.1); - --ORANGE: #fa9d3b; - --YELLOW: #ffc300; - --GREEN: #91d300; - --LIGHTGREEN: #95ec69; - --INDIGO: #1485ee; - --PURPLE: #6467f0; - --WHITE: #fff; - --LINK: #576b95; - --TEXTGREEN: #06ae56; - --FG: #000; - --BG: #fff; - --TAG-TEXT-ORANGE: #fa9d3b; - --TAG-TEXT-GREEN: #06ae56; - --TAG-TEXT-BLUE: #10aeff; - --TAG-TEXT-BLACK: rgba(0,0,0,0.5); - --TAG-BACKGROUND-BLACK: rgba(0,0,0,0.05) -} - -.readerTopStoriesBookInfo .readerTopStoriesBookInfo_head { - display: flex -} - -.readerTopStoriesBookInfo .readerTopStoriesBookInfo_head .bookInfo_cover { - flex-shrink: 0; - width: 160px; - height: 232px -} - -@media(max-width: 1365px) { - .readerTopStoriesBookInfo .readerTopStoriesBookInfo_head .bookInfo_cover { - width:134px; - height: 195px - } -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .readerTopStoriesBookInfo_head .bookInfo_cover { - width:108px; - height: 157px - } -} - -@media(max-width: 460px) { - .readerTopStoriesBookInfo .readerTopStoriesBookInfo_head .bookInfo_cover { - width:80px; - height: 116px - } -} - -.readerTopStoriesBookInfo .bookInfo_right { - flex: 1; - margin-left: 40px; - padding-top: 18px -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .bookInfo_right { - margin-left:20px - } -} - -@media(max-width: 460px) { - .readerTopStoriesBookInfo .bookInfo_right { - margin-left:16px; - padding-top: 0 - } -} - -.readerTopStoriesBookInfo .bookInfo_right_header { - display: flex; - justify-content: space-between -} - -.readerTopStoriesBookInfo .bookInfo_Button { - margin: 32px 0 0 -} - -.readerTopStoriesBookInfo .bookInfo_Button button { - margin: 0!important; - max-width: 100%!important -} - -.readerTopStoriesBookInfo .bookInfo_right_header_title { - margin-top: 4px; - color: #eef0f4; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 24px; - line-height: 35px -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_right_header_title { - color: #212832 -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .bookInfo_right_header_title { - font-size:20px; - line-height: 31px - } -} - -@media(max-width: 460px) { - .readerTopStoriesBookInfo .bookInfo_right_header_title { - margin-top:6px; - font-size: 18px; - line-height: 29px - } -} - -.readerTopStoriesBookInfo .bookInfo_right_header_addShelfBtn { - flex-shrink: 0; - display: flex; - padding-left: 20px; - padding-right: 22px; - justify-content: center; - align-items: center; - height: 40px; - line-height: 40px; - border-radius: 20px; - margin: 10px 0 0 40px; - font-size: 14px -} - -@media(max-width: 460px) { - .readerTopStoriesBookInfo .bookInfo_right_header_addShelfBtn { - margin-top:4px; - margin-left: 14px; - padding-left: 10px; - padding-right: 12px; - height: 36px; - line-height: 36px; - border-radius: 18px - } -} - -.readerTopStoriesBookInfo .bookInfo_author_container { - margin-top: 2px -} - -.readerTopStoriesBookInfo .bookInfo_author { - color: #b2b4b8; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 18px; - line-height: 26px -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_author { - color: #5d646e -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .bookInfo_author { - font-size:15px; - line-height: 23px - } -} - -.readerTopStoriesBookInfo .bookInfo_author.link { - color: #0097ff -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_author.link { - color: #1b88ee -} - -.readerTopStoriesBookInfo .bookInfo_intro { - position: relative; - margin-top: 21px; - cursor: pointer; - text-align: justify; - color: #8a8c90; - line-height: 25px; - overflow: hidden; - height: 50px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 2; - -moz-line-clamp: 2; - line-clamp: 2; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - font-size: 14px -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_intro { - color: #858c96 -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .bookInfo_intro { - margin-top:10px; - font-size: 13px; - height: 69px; - line-height: 23px - } -} - -.readerTopStoriesBookInfo .bookInfo_intro.hasMore:after { - content: "更多"; - position: absolute; - bottom: 0; - right: 0; - color: #8a8c90; - font-size: 14px; - padding-left: 40px; - background: linear-gradient(90deg,#262628,#262628 50%,#262628); - transition: background-image .2s ease-in-out -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_intro.hasMore:after { - color: #858c96 -} - -@media(max-width: 1023px) { - .readerTopStoriesBookInfo .bookInfo_intro.hasMore:after { - font-size:13px - } -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_intro.hasMore:after { - background-image: linear-gradient(90deg,hsla(0,0%,100%,0),#fff 50%,#fff) -} - -.readerTopStoriesBookInfo .bookInfo_intro:hover { - color: #b2b4b8 -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_intro:hover { - color: #5d646e -} - -.readerTopStoriesBookInfo .bookInfo_intro.hasMore:hover:after { - color: #b2b4b8 -} - -.wr_whiteTheme .readerTopStoriesBookInfo .bookInfo_intro.hasMore:hover:after { - color: #5d646e -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview { - margin-top: 60px; - display: flex -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item { - flex: auto; - background-color: #27282a; - transition: background-color .2s ease-in-out; - border-radius: 6px; - padding: 14px 16px; - display: flex; - flex-direction: column; - justify-content: center -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item { - background-color: #f6f7f9 -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item:not(:first-child) { - margin-left: 28px -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item:hover { - background-color: #1a1b1c -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item:hover { - background-color: #edeeef -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .item.showAll { - flex: none -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line1 { - font-size: 14px; - color: #d0d3d8; - line-height: 21px; - overflow: hidden; - height: 21px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line1 { - color: #49505a -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2 { - margin-top: 4px; - font-size: 12px; - color: #8a8c90; - line-height: 18px; - overflow: hidden; - height: 18px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2 { - color: #858c96 -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2.blue { - color: #0097ff -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2.blue { - color: #1b88ee -} - -.readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2.title { - font-size: 14px; - line-height: 21px; - overflow: hidden; - height: 21px; - display: -webkit-box; - display: -moz-box; - text-overflow: ellipsis; - -webkit-line-clamp: 1; - -moz-line-clamp: 1; - line-clamp: 1; - -webkit-box-orient: vertical; - -webkit-text-size-adjust: none; - box-orient: vertical; - color: #d0d3d8 -} - -.wr_whiteTheme .readerTopStoriesBookInfo .readerBookInfo_chapterPreview .line2.title { - color: #49505a -} - -.readerTopStoriesBookInfo .introDialogWrap { - width: 80%; - max-width: 500px; - max-height: 80%; - overflow: auto -} - -.readerTopStoriesBookInfo .introDialog_content { - padding: 40px 32px 32px; - text-align: left; - color: #b2b4b8; - font-size: 14px -} - -.wr_whiteTheme .readerTopStoriesBookInfo .introDialog_content { - color: #5d646e -} - -.readerTopStoriesBookInfo .introDialog_content_title { - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - font-size: 18px; - color: #eef0f4; - margin-bottom: 16px -} - -.wr_whiteTheme .readerTopStoriesBookInfo .introDialog_content_title { - color: #212832 -} - -.readerTopStoriesBookInfo .introDialog_content_title:not(:first-child) { - margin-top: 32px -} - -.readerTopStoriesBookInfo .introDialog_content_intro_para { - line-height: 24px; - text-align: justify -} - -.readerTopStoriesBookInfo .introDialog_content_intro_para:not(:first-child) { - margin-top: 12px -} - -.readerTopStoriesBookInfo .introDialog_content_pub_line { - display: flex; - justify-content: space-between -} - -.readerTopStoriesBookInfo .introDialog_content_pub_line:not(:last-child) { - margin-bottom: 12px -} - -.readerTopStoriesBookInfo .introDialog_content_pub_line.long { - max-width: 100% -} - -.readerTopStoriesBookInfo .introDialog_content_pub_title { - color: #8a8c90 -} - -.wr_whiteTheme .readerTopStoriesBookInfo .introDialog_content_pub_title { - color: #858c96 -} - -.readerTopStoriesBookInfo_title { - margin-bottom: 24px; - font-size: 22px; - line-height: 1.6em; - font-weight: 500; - color: #fff -} - -.wr_whiteTheme .readerTopStoriesBookInfo_title { - color: #000 -} - -.readerTopStoriesBookInfo_split { - margin: 2px 24px 32px; - border-radius: 0; - border: solid #383c40; - border-width: 0 0 1px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerTopStoriesBookInfo_split { - position:relative; - border: 0 - } - - .readerTopStoriesBookInfo_split:after { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 200%; - height: 200%; - border-radius: 0; - border: solid #383c40; - border-width: 0 0 1px; - transform: scale(.5); - transform-origin: 0 0; - pointer-events: none - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerTopStoriesBookInfo_split:after { - width:300%; - height: 300%; - border-radius: 0; - transform: scale(.3333333333) - } -} - -.wr_whiteTheme .readerTopStoriesBookInfo_split { - border-color: #e6e8ea -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerTopStoriesBookInfo_split:after { - border-color:#e6e8ea - } -} - -.reader_common_dialog_wrapper { - width: 300px; - padding: 40px 20px 20px; - box-sizing: border-box; - backgroundColor: #262628 -} - -.wr_whiteTheme .reader_common_dialog_wrapper { - backgroundColor: #f4f5f7 -} - -.reader_common_dialog_title { - font-size: 18px; - line-height: 25px; - text-align: center; - color: #eef0f4; - margin-bottom: 8px; - font-weight: 500 -} - -.wr_whiteTheme .reader_common_dialog_title { - color: #212832 -} - -.reader_common_dialog_text { - font-size: 14px; - line-height: 17px; - text-align: center; - color: #b2b4b8; - font-family: DIN,PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif -} - -.wr_whiteTheme .reader_common_dialog_text { - color: #5d646e -} - -.reader_common_dialog_button { - background: linear-gradient(90deg,#0087fc,#00a3f5); - border-radius: 12px; - padding: 12px 40px; - font-size: 17px; - line-height: 24px; - color: #fff; - font-weight: 500; - display: inline-block; - margin-top: 40px -} - -.wr_underline_wrapper { - position: absolute; - z-index: 3; - cursor: pointer -} - -.wr_underline { - width: 100%; - height: 100% -} - -.wr_underline_thought { - border-bottom: 1px dashed #ff374f -} - -.wr_underline_straight { - transform: translateY(2px); - display: flex; - flex-wrap: nowrap; - align-items: flex-end; - height: 100%; - width: 100% -} - -.wr_underline_straight .wr_underline_straight_start { - max-width: 15px; - height: 4px; - display: inline-block; - flex: 1; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/underline_straight_start.5f014967.png); - background-size: 100% 100% -} - -.wr_underline_straight .wr_underline_straight_middle { - height: 4px; - display: inline-block; - flex: 6.67; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/underline_straight_middle.35bbccf9.png); - background-size: 100% 100% -} - -.wr_underline_straight .wr_underline_straight_end { - max-width: 15px; - height: 4px; - display: inline-block; - flex: 1; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/underline_straight_end.a22bd49b.png); - background-size: 100% 100% -} - -.wr_underline_mark { - box-sizing: border-box; - background-size: 100% 100%; - background-clip: content-box; - background-repeat: repeat-x; - opacity: .15 -} - -.wr_whiteTheme .wr_underline_mark { - opacity: .3 -} - -.wr_underline_mark:after,.wr_underline_mark:before { - position: absolute; - content: ""; - height: 100%; - background-size: 100% 100% -} - -.wr_underline_mark.wr_bg0 { - padding-left: 14px; - padding-right: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg0_m.2af38def.png) -} - -.wr_underline_mark.wr_bg0:before { - left: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg0_l.5d416dcb.png) -} - -.wr_underline_mark.wr_bg0:after { - right: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg0_r.821ea1e9.png) -} - -.wr_underline_mark.wr_bg1 { - padding-left: 14px; - padding-right: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_m.da2e1651.png) -} - -.wr_underline_mark.wr_bg1:before { - left: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_l.a257e161.png) -} - -.wr_underline_mark.wr_bg1:after { - right: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_r.a8dca3f0.png) -} - -.wr_underline_mark.wr_bg2 { - padding-left: 14px; - padding-right: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_m.da2e1651.png) -} - -.wr_underline_mark.wr_bg2:before { - left: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_l.a257e161.png) -} - -.wr_underline_mark.wr_bg2:after { - right: 0; - width: 14px; - background-image: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/reader_underline_bg1_r.a8dca3f0.png) -} - -.wr_underline_wave { - transform: translateY(2px); - display: flex; - flex-wrap: nowrap; - align-items: flex-end; - height: 100%; - width: 100% -} - -.wr_underline_wave_start { - height: 7px; - display: inline-block; - flex: 1 -} - -.wr_underline_wave_start_1 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_start_1.a88247ee.png); - background-size: 100% 100% -} - -.wr_underline_wave_start_2 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_start_2.898d241f.png); - background-size: 100% 100% -} - -.wr_underline_wave_start_3 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_start_3.37101ab8.png); - background-size: 100% 100% -} - -.wr_underline_wave_start_4 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_start_4.20ef0af6.png); - background-size: 100% 100% -} - -.wr_underline_wave_start_5 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_start_5.ed6970ed.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle { - height: 7px; - display: inline-block; - flex: 3.2 -} - -.wr_underline_wave_middle_1 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_1.f77bcdc2.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_2 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_2.8459e65d.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_3 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_3.e0cb761a.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_4 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_4.965b9e61.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_5 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_5.b41f18dc.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_6 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_6.db027f64.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_7 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_7.8727cbfe.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_8 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_8.c01489a5.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_9 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_9.bdf4de1e.png); - background-size: 100% 100% -} - -.wr_underline_wave_middle_10 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_middle_10.a92aecba.png); - background-size: 100% 100% -} - -.wr_underline_wave_end { - height: 7px; - display: inline-block; - flex: 1 -} - -.wr_underline_wave_end_1 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_end_1.571a19b0.png); - background-size: 100% 100% -} - -.wr_underline_wave_end_2 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_end_2.0375baf2.png); - background-size: 100% 100% -} - -.wr_underline_wave_end_3 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_end_3.f017123a.png); - background-size: 100% 100% -} - -.wr_underline_wave_end_4 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_end_4.5bee2e28.png); - background-size: 100% 100% -} - -.wr_underline_wave_end_5 { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_highlight_end_5.c33436e6.png); - background-size: 100% 100% -} - -.wr_underline_color_1 .wr_underline_wave { - filter: hue-rotate(120deg) -} - -.wr_underline_color_1 .wr_underline_mark { - filter: hue-rotate(300deg) -} - -.wr_underline_color_2 .wr_underline_wave { - filter: hue-rotate(45deg) -} - -.wr_underline_color_2 .wr_underline_straight { - filter: hue-rotate(260deg) -} - -.wr_underline_color_2 .wr_underline_mark { - filter: hue-rotate(215deg) -} - -.wr_underline_color_3 .wr_underline_straight { - filter: hue-rotate(225deg) -} - -.wr_underline_color_3 .wr_underline_mark { - filter: hue-rotate(170deg) -} - -.wr_underline_color_4 .wr_underline_wave { - filter: hue-rotate(240deg) -} - -.wr_underline_color_4 .wr_underline_straight { - filter: hue-rotate(110deg) -} - -.wr_underline_color_4 .wr_underline_mark { - filter: hue-rotate(69deg) -} - -.wr_underline_color_5 .wr_underline_wave { - filter: hue-rotate(150deg) brightness(2.2) -} - -.wr_underline_color_5 .wr_underline_straight { - filter: hue-rotate(40deg) brightness(1.3) -} - -body,dd,dl,fieldset,form,h1,h2,h3,h4,h5,h6,legend,p,pre { - margin: 0 -} - -fieldset,ol,ul { - margin: 0; - padding: 0 -} - -td,th { - padding: 0 -} - -table { - font-size: inherit -} - -fieldset,img { - border: 0 -} - -li,ol,ul { - list-style: none -} - -body { - font-size: 12px; - line-height: 1.5; - background: #262628; - color: #eef0f4 -} - -h1,h2,h3,h4 { - font-size: 18px; - font-weight: 400 -} - -body,button,input,select,textarea { - font-family: PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - outline: none; - -webkit-text-size-adjust: none -} - -button,input,select,textarea { - font-size: inherit; - -webkit-tap-highlight-color: rgba(0,0,0,0) -} - -a { - color: #4a7ab0; - text-decoration: none; - -webkit-tap-highlight-color: rgba(0,0,0,.03) -} - -:focus { - outline: none -} - -article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary { - display: block -} - -audio,canvas,video { - display: inline-block -} - -.qui_txtNormal { - font-weight: 400!important -} - -.qui_txtBold { - font-weight: 700!important -} - -.qui_txtLeft { - text-align: left!important -} - -.qui_txtRight { - text-align: right!important -} - -.qui_txtUnderline { - text-decoration: underline!important -} - -.qui_txtUnderlineNone { - text-decoration: none!important -} - -.qui_txtOverflow { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - word-break: break-all; - word-wrap: normal -} - -.qui_clear:after { - clear: both; - content: "."; - display: block; - line-height: 0; - font-size: 0; - visibility: hidden -} - -.qui_txtNowrap { - white-space: nowrap!important -} - -.qui_layoutLeft { - float: left!important -} - -.qui_layoutRight { - float: right!important -} - -.qui_displayNone { - display: none!important -} - -@keyframes iconBreathe { - 0% { - transform: scale(1) - } - - 40% { - transform: scale(1.3) - } - - 60% { - transform: scale(1) - } - - to { - transform: scale(1) - } -} - -@keyframes itemFadeIn { - 0% { - background-color: #fff - } - - to { - background-color: rgba(27,136,238,.1) - } -} - -@keyframes itemFadeOut { - 0% { - background-color: rgba(27,136,238,.1) - } - - to { - background-color: #fff - } -} - -.preRenderContainer .preRenderContent h1 { - margin-bottom: 1em; - font-size: 1.6em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent h2 { - margin-bottom: .9em; - font-size: 1.5em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent h3 { - margin-bottom: .9em; - font-size: 1.4em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent h4 { - margin-bottom: .8em; - font-size: 1.3em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent h5 { - margin-bottom: .9em; - font-size: 1.2em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent h6 { - margin-bottom: .9em; - font-size: 1.1em; - text-indent: 0 -} - -.preRenderContainer .preRenderContent div { - overflow: hidden -} - -.preRenderContainer .preRenderContent div[data-wr-inset] { - padding: 20px -} - -.preRenderContainer .preRenderContent .reader_footer_note { - margin-left: 3px; - margin-right: 3px; - position: relative; - top: 3px -} - -.preRenderContainer .preRenderContent .bgColor { - margin-bottom: 1.2em -} - -.preRenderContainer .preRenderContent .bgColor h1,.preRenderContainer .preRenderContent .bgColor h2,.preRenderContainer .preRenderContent .bgColor h3,.preRenderContainer .preRenderContent .bgColor h4,.preRenderContainer .preRenderContent .bgColor h5,.preRenderContainer .preRenderContent .bgColor h6,.preRenderContainer .preRenderContent .border h1,.preRenderContainer .preRenderContent .border h2,.preRenderContainer .preRenderContent .border h3,.preRenderContainer .preRenderContent .border h4,.preRenderContainer .preRenderContent .border h5,.preRenderContainer .preRenderContent .border h6 { - margin-bottom: 0 -} - -.preRenderContainer .preRenderContent .qrbodyPic { - clear: both -} - -.preRenderContainer .preRenderContent p { - word-break: normal -} - -.renderTargetContainer .wr_canvasContainer { - position: absolute; - left: 0; - top: 0; - z-index: 2 -} - -.renderTargetContainer .wr_selection { - position: absolute; - z-index: 3; - background: rgba(0,151,255,.15) -} - -.renderTargetContainer .wr_highlight_bg { - position: absolute; - z-index: 1; - background: rgba(36,147,238,.25) -} - -.wr_whiteTheme .renderTargetContainer .wr_highlight_bg { - background: rgba(27,136,238,.25) -} - -.renderTargetContainer .wr_myNote,.renderTargetContainer .wr_underline { - position: absolute; - z-index: 3; - cursor: pointer -} - -.renderTargetContainer .wr_myNote { - border-bottom: 1px dashed #ff374f -} - -.renderTargetContainer .wr_pendingLoading { - background-color: #303236 -} - -.wr_whiteTheme .renderTargetContainer .wr_pendingLoading { - background-color: #eee -} - -.renderTargetContainer .renderTargetContent video { - cursor: pointer; - width: 100%; - height: 100% -} - -.renderTargetContainer .renderTargetContent .wr_video_playButton { - font-size: 15px; - font-weight: 700; - color: #fff; - height: 40px; - line-height: 40px; - border-radius: 20px; - padding: 0 20px; - cursor: pointer; - background-color: rgba(0,0,0,.6); - position: absolute; - left: 50%; - top: 50%; - pointer-events: none; - transform: translate(-50%,-50%) -} - -.renderTargetContainer .renderTargetContent .wr_video_playing .wr_video_playButton { - display: none -} - -.renderTargetContainer .renderTargetContent .wr_readerBackground_opacity { - opacity: .3 -} - -.renderTargetContainer .renderTargetContent .wr_readerImage_opacity { - opacity: .5 -} - -.renderTargetContainer .renderTargetContent .wr_absolute { - position: absolute; - z-index: 2 -} - -.renderTargetContainer .renderTargetContent .reader_footer_note { - z-index: 5 -} - -.renderTargetContainer .renderTargetContent .wr_decoration { - position: absolute; - z-index: 0; - box-sizing: border-box -} - -.renderTargetContainer .renderTargetContent .wr_highlight_char { - color: #0097ff -} - -.wr_whiteTheme .renderTargetContainer .renderTargetContent .wr_highlight_char { - color: #1b88ee -} - -.chapterTitle { - margin-bottom: 18px; - font-size: 24px; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif; - color: #eef0f4 -} - -.wr_whiteTheme .chapterTitle { - color: #0d141e -} - -.fontLevel1 .chapterTitle { - font-size: 20px -} - -.fontLevel2 .chapterTitle { - font-size: 24px -} - -.fontLevel3 .chapterTitle { - font-size: 28px -} - -.fontLevel4 .chapterTitle { - font-size: 32px -} - -.fontLevel5 .chapterTitle { - font-size: 36px -} - -.fontLevel6 .chapterTitle { - font-size: 44px -} - -.fontLevel7 .chapterTitle { - font-size: 48px -} - -.preRenderContainer .preRenderContent pre,.renderTargetContainer .renderTargetContent pre { - margin-bottom: 1em; - word-break: break-all; - word-wrap: break-word; - white-space: pre-wrap; - background-color: #2d2d2d; - color: #d0d3d8; - border-radius: 4px; - padding: 12px -} - -.preRenderContainer .preRenderContent div[class=bgcolora] pre,.renderTargetContainer .renderTargetContent div[class=bgcolora] pre { - margin-bottom: 0; - background: transparent -} - -.preRenderContainer .preRenderContent img,.renderTargetContainer .renderTargetContent img { - max-width: 100%; - margin: 0!important -} - -.preRenderContainer .preRenderContent p,.renderTargetContainer .renderTargetContent p { - margin-bottom: 1em; - font-size: 22px; - line-height: 44px; - text-indent: 0!important -} - -.preRenderContainer .preRenderContent p:last-child,.renderTargetContainer .renderTargetContent p:last-child { - margin-bottom: 0 -} - -.fontLevel1 .preRenderContainer .preRenderContent p,.fontLevel1 .renderTargetContainer .renderTargetContent p { - font-size: 18px; - line-height: 36px -} - -.fontLevel2 .preRenderContainer .preRenderContent p,.fontLevel2 .renderTargetContainer .renderTargetContent p { - font-size: 22px; - line-height: 44px -} - -.fontLevel3 .preRenderContainer .preRenderContent p,.fontLevel3 .renderTargetContainer .renderTargetContent p { - font-size: 26px; - line-height: 52px -} - -.fontLevel4 .preRenderContainer .preRenderContent p,.fontLevel4 .renderTargetContainer .renderTargetContent p { - font-size: 30px; - line-height: 60px -} - -.fontLevel5 .preRenderContainer .preRenderContent p,.fontLevel5 .renderTargetContainer .renderTargetContent p { - font-size: 34px; - line-height: 68px -} - -.fontLevel6 .preRenderContainer .preRenderContent p,.fontLevel6 .renderTargetContainer .renderTargetContent p { - font-size: 38px; - line-height: 76px -} - -.fontLevel7 .preRenderContainer .preRenderContent p,.fontLevel7 .renderTargetContainer .renderTargetContent p { - font-size: 46px; - line-height: 92px -} - -.preRenderContainer .preRenderContent .bodyPic,.renderTargetContainer .renderTargetContent .bodyPic { - text-align: center -} - -.preRenderContainer .preRenderContent .bodyPic img,.renderTargetContainer .renderTargetContent .bodyPic img { - vertical-align: bottom -} - -.preRenderContainer .preRenderContent .bleed-pic img,.preRenderContainer .preRenderContent img.bleed-pic,.preRenderContainer .preRenderContent img.qqreader-fullimg,.renderTargetContainer .renderTargetContent .bleed-pic img,.renderTargetContainer .renderTargetContent img.bleed-pic,.renderTargetContainer .renderTargetContent img.qqreader-fullimg { - width: 100% -} - -.preRenderContainer .preRenderContent .reader_footer_note,.renderTargetContainer .renderTargetContent .reader_footer_note { - width: 19px; - height: 19px; - cursor: pointer -} - -.wr_whiteTheme .preRenderContainer .preRenderContent pre,.wr_whiteTheme .renderTargetContainer .renderTargetContent pre { - background-color: #e6e6e6; - color: #0d141e -} - -.wr_whiteTheme .renderTargetContainer .renderTargetContent .wr_readerBackground_opacity,.wr_whiteTheme .renderTargetContainer .renderTargetContent .wr_readerImage_opacity { - opacity: 1 -} - -html body { - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - background-color: #262628 -} - -html body.wr_whiteTheme { - background-color: #f6f7f9 -} - -.readerHeader { - color: #b2b4b8; - text-align: center; - padding: 80px 100px 0 -} - -.wr_whiteTheme .readerHeader { - color: #5d646e -} - -@media(max-width: 1365px) { - .readerHeader { - padding-left:72px; - padding-right: 72px - } -} - -@media(max-width: 1023px) { - .readerHeader { - padding-left:36px; - padding-right: 36px - } -} - -@media(max-width: 767px) { - .readerHeader { - padding:40px 20px 100px - } -} - -.readerContentHeader { - margin-left: 100px; - margin-right: 100px; - padding: 1px; - margin-bottom: 20px -} - -@media(max-width: 1365px) { - .readerContentHeader { - margin-left:72px; - margin-right: 72px - } -} - -@media(max-width: 1023px) { - .readerContentHeader { - margin-left:36px; - margin-right: 36px - } -} - -@media(max-width: 767px) { - .readerContentHeader { - margin-left:20px; - margin-right: 20px - } -} - -.readerHeaderButton { - color: #0097ff; - font-size: 18px; - line-height: 36px; - font-weight: 600; - text-align: left -} - -.wr_whiteTheme .readerHeaderButton { - color: #1b88ee -} - -.wr_page_reader .app { - height: 100% -} - -.wr_page_reader .book_ratings_container { - padding-bottom: 36px; - margin-left: 100px; - margin-right: 100px -} - -@media(max-width: 1365px) { - .wr_page_reader .book_ratings_container { - margin-left:72px; - margin-right: 72px - } -} - -@media(max-width: 1023px) { - .wr_page_reader .book_ratings_container { - margin-left:36px; - margin-right: 36px - } -} - -@media(max-width: 767px) { - .wr_page_reader .book_ratings_container { - margin-left:20px; - margin-right: 20px - } -} - -.readerContent { - height: 100%; - box-sizing: border-box -} - -@media print { - .readerContent { - display: none - } -} - -.readerContent .app_content { - background-color: #1c1c1d; - transition: background-color .2s ease-in-out; - min-height: 100%; - max-width: 1000px -} - -.wr_whiteTheme .readerContent .app_content { - background-color: #fff -} - -@media(max-width: 1365px) { - .readerContent .app_content { - max-width:760px - } -} - -@media(max-width: 1023px) { - .readerContent .app_content { - max-width:560px - } -} - -@media(max-width: 767px) { - .readerContent .app_content { - max-width:100% - } -} - -.navBar_inner { - max-width: 1000px -} - -@media(max-width: 1365px) { - .navBar_inner { - max-width:760px - } -} - -@media(max-width: 767px) { - .navBar_inner { - max-width:100% - } -} - -.navBarOffset { - padding-top: 100px -} - -.readerChapterContent { - margin-left: 100px; - margin-right: 100px; - padding: 1px; - color: #d0d3d8; - font-size: 22px; - text-align: justify -} - -@media(max-width: 1365px) { - .readerChapterContent { - margin-left:72px; - margin-right: 72px - } -} - -@media(max-width: 1023px) { - .readerChapterContent { - margin-left:36px; - margin-right: 36px - } -} - -@media(max-width: 767px) { - .readerChapterContent { - margin-left:20px; - margin-right: 20px - } -} - -.wr_whiteTheme .readerChapterContent { - color: #0d141e -} - -.readerChapterContent.fontLevel1 { - font-size: 18px -} - -.readerChapterContent.fontLevel2 { - font-size: 22px -} - -.readerChapterContent.fontLevel3 { - font-size: 26px -} - -.readerChapterContent.fontLevel4 { - font-size: 30px -} - -.readerChapterContent.fontLevel5 { - font-size: 34px -} - -.readerChapterContent.fontLevel6 { - font-size: 38px -} - -.readerChapterContent.fontLevel7 { - font-size: 46px -} - -.readerChapterContent .hide { - display: none -} - -.readerChapterContent.navBarOffset { - padding-top: 100px -} - -.readerChapterContent .renderTargetContainer_needPay { - position: relative; - padding-bottom: 80px -} - -.readerChapterContent .renderTargetContainer_needPay:after { - content: ""; - position: absolute; - z-index: 4; - left: 0; - right: 0; - bottom: 0; - height: 100%; - max-height: 160px; - background: linear-gradient(180deg,rgba(28,28,29,0),#1c1c1d 47.4%,#1c1c1d); - transition: background-image .2s ease-in-out -} - -.wr_whiteTheme .readerChapterContent .renderTargetContainer_needPay:after { - background: linear-gradient(180deg,hsla(0,0%,100%,0),#fff 47.4%,#fff) -} - -.readerChapterContent .reader_footer_note { - display: inline-block; - width: 19px; - height: 19px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_black.bb44bce4.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerChapterContent .reader_footer_note { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_black_2x.d3976646.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerChapterContent .reader_footer_note { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_black_3x.e47c9075.png) - } -} - -.wr_whiteTheme .readerChapterContent .reader_footer_note { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_white.571a9125.png) no-repeat; - background-size: 100% -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .wr_whiteTheme .readerChapterContent .reader_footer_note { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_white_2x.e40a42ed.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .wr_whiteTheme .readerChapterContent .reader_footer_note { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/zhu_white_3x.f8daeeba.png) - } -} - -.topAnchor { - height: 0 -} - -.readerChapterContentLoading { - position: relative; - height: 80px; - margin-top: 30% -} - -.readerChapterContentLoading .wr_loading { - left: 50%; - top: 40% -} - -.preRenderContainer { - position: relative; - opacity: 0; - overflow: hidden; - word-break: break-all; - word-wrap: break-word -} - -.preRenderContainer pre { - line-height: normal!important -} - -.preRenderContent { - overflow: hidden -} - -.renderTargetContainer { - position: relative -} - -.chapterContentError { - text-align: center; - font-size: 16px; - margin-top: 20%; - padding-bottom: 20%; - color: #eef0f4 -} - -.wr_whiteTheme .chapterContentError { - color: #212832 -} - -.chapterContentError .retry { - color: #4a7ab0 -} - -.readerFooter { - color: #b2b4b8; - text-align: center; - padding: 80px 100px -} - -.wr_whiteTheme .readerFooter { - color: #5d646e -} - -@media(max-width: 1365px) { - .readerFooter { - padding-left:72px; - padding-right: 72px - } -} - -@media(max-width: 1023px) { - .readerFooter { - padding-left:36px; - padding-right: 36px - } -} - -@media(max-width: 767px) { - .readerFooter { - padding:40px 20px 100px - } -} - -.lineThrough { - text-decoration: line-through -} - -.readerFooter_button { - display: block; - width: 100%; - max-width: 400px; - height: 60px; - line-height: 60px; - margin: 0 auto 24px; - border-radius: 12px; - text-align: center; - font-size: 16px; - font-weight: 500; - background-color: hsla(0,0%,100%,.1); - color: #eef0f4; - transition: background-color .2s ease-in-out -} - -.wr_whiteTheme .readerFooter_button { - background-color: #f6f7f9; - color: #1b88ee -} - -@media(max-width: 767px) { - .readerFooter_button { - max-width:100%; - height: 50px; - line-height: 50px - } -} - -.readerFooter_button.blue { - background: linear-gradient(90deg,#0087fc,#00a3f5); - color: #fff -} - -.readerFooter_button:hover { - background-color: hsla(0,0%,100%,.05) -} - -.wr_whiteTheme .readerFooter_button:hover { - background-color: #edeeef -} - -.readerFooter_button_twoLines { - display: flex; - flex-direction: column; - align-items: center; - line-height: 1em; - justify-content: center -} - -.readerFooter_button_twoLines .line1 { - font-size: 16px; - font-weight: 500 -} - -.readerFooter_button_twoLines .line1.withIcon { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_button_membercard.76c6ed76.png) no-repeat; - background-size: 20px 20px; - background-position: left 50%; - padding-left: 25px -} - -@media(-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio:2),(min-resolution:2dppx),(min-resolution:192dpi) { - .readerFooter_button_twoLines .line1.withIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_button_membercard_2x.ecac4b88.png) - } -} - -@media(-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio:3),(min-resolution:3dppx),(min-resolution:288dpi) { - .readerFooter_button_twoLines .line1.withIcon { - background-image:url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/icon_button_membercard_3x.6150085f.png) - } -} - -.readerFooter_button_twoLines .line2 { - font-size: 13px; - font-weight: 400; - margin-top: 4px -} - -.readerFooter_desc { - text-align: center; - font-size: 16px; - line-height: 28px; - color: #b2b4b8 -} - -.wr_whiteTheme .readerFooter_desc { - color: #5d646e -} - -.readerFooter_ending { - display: flex; - flex-direction: column; - justify-content: center; - align-content: center; - width: 200px; - height: 200px; - border-radius: 100px; - margin: 0 auto -} - -.readerFooter_ending_finish { - background-color: hsla(0,0%,100%,.05) -} - -.readerFooter_ending_title { - white-space: pre; - line-height: 46px; - font-size: 32px; - color: #b2b4b8; - font-family: "SourceHanSerifCN-Bold",PingFang SC,-apple-system,SF UI Text,Lucida Grande,STheiti,Microsoft YaHei,sans-serif -} - -.wr_whiteTheme .readerFooter_ending_title { - color: #5d646e -} - -.readerFooter_ending_time { - white-space: pre; - margin-top: 12px; - line-height: 21px; - font-size: 15px; - color: #8a8c90 -} - -.wr_whiteTheme .readerFooter_ending_time { - color: #858c96 -} - -.readerFooter_trial_end { - margin-bottom: 72px -} - -.readerControls { - width: 48px; - overflow: visible; - position: fixed; - z-index: 5; - left: 50%; - bottom: 48px; - margin-left: 548px -} - -@media(max-width: 1365px) { - .readerControls { - margin-left:428px - } -} - -@media(max-width: 1023px) { - .readerControls { - margin-left:304px - } -} - -.readerMemberCardTips { - position: fixed; - width: 100%; - left: 50%; - transform: translate(-50%); - z-index: 10; - top: 72px; - box-sizing: border-box; - max-width: 1000px; - padding-left: 100px; - padding-right: 100px -} - -@media(max-width: 1365px) { - .readerMemberCardTips { - max-width:760px; - padding-left: 72px; - padding-right: 72px - } -} - -@media(max-width: 1023px) { - .readerMemberCardTips { - max-width:560px; - padding-left: 36px; - padding-right: 36px - } -} - -@media(max-width: 767px) { - .readerMemberCardTips { - max-width:100%; - padding-left: 20px; - padding-right: 20px - } -} - -@media(max-width: 767px) { - .readerBottomBar { - display:flex; - opacity: 0; - transform: translateY(56px) - } - - .bookInfo_right_header_addShelfBtn { - display: none - } - - .readerBottomBar.active { - opacity: 1; - transform: translate(0) - } - - .readerBottomSettingPanel { - display: block - } - - .readerControls,.readerTopBar { - display: none - } - - .navBarOffset { - padding-top: 36px - } - - .wr_page_reader .navBar { - display: none - } - - .wr_page_reader .app_content_navBarOffset { - padding-top: 0 - } - - .wr_page_reader .navBarOffset { - padding-top: 36px - } - - .bookInfo_more .bookInfo_more_rating { - flex: 1; - margin-right: 10px - } - - .bookInfo_more .bookInfo_more_reading { - flex: 1 - } - - .bookInfo_more .bookInfo_more_addShelf { - display: none - } - - .readerMemberCardTips { - top: auto; - bottom: 56px - } - - .readerMemberCardTips.atBottom { - bottom: 0 - } -} - -.viewer-canvas img { - background: #fff -} - -.dev_panel { - position: fixed; - top: 0; - right: 0; - background: rgba(0,0,0,.4); - color: #fff; - padding: 8px; - font-weight: 700; - z-index: 9999 -} - -.renderTargetWatermark { - position: absolute; - bottom: 0; - height: 30%; - width: 100%; - pointer-events: none -} diff --git a/src/frontend/www/style/search.css b/src/frontend/www/style/search.css deleted file mode 100644 index 8aeaf8b..0000000 --- a/src/frontend/www/style/search.css +++ /dev/null @@ -1,54 +0,0 @@ -form { - width: 100%; - background: white; - padding: 3rem; -} - -.search_input { - position: relative; -} - -.search_input_left { - position: absolute; - top: 14px; - left: 18px; - content: ""; - width: 24px; - height: 24px; - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/search_magnifier_focus_white.197e0b86.png) no-repeat; - background-size: 100%; -} - -.search_input_text { - background-color: #fff; - color: #212832; - width: 100%; - padding: 0 52px; - box-sizing: border-box; - height: 52px; - border-radius: 26px; - font-size: 16px; - background-color: rgba(238, 240, 244, .12); - border: 1px solid #d1d1d1; - - &::placeholder { - color: #b8b8b8; - } -} -.search_input_right { - background: url(https://weread-1258476243.file.myqcloud.com/web/wrwebnjlogic/image/search_return_white.0c921c5a.png) no-repeat; - background-size: 100%; - position: absolute; - top: 10px; - right: 10px; - content: ""; - width: 32px; - height: 32px; - cursor: pointer; - outline: none; - border: none; -} -.search_input_loading { - right: 26px; - top: 23px; -} diff --git a/src/frontend/www/user.html b/src/frontend/www/user.html deleted file mode 100644 index 5c32109..0000000 --- a/src/frontend/www/user.html +++ /dev/null @@ -1,85 +0,0 @@ - - - - - User - - - -
      - 头像 -

      -

      -

      -
      - - - - - - diff --git a/src/kv/credential.ts b/src/kv/credential.ts index bab6d77..0778938 100644 --- a/src/kv/credential.ts +++ b/src/kv/credential.ts @@ -1,35 +1,36 @@ -import kv from "./db.ts" +import runtime from "../runtime.ts"; + +const kv = runtime.kv; /** * 用户凭证 */ export interface Credential { - token: string; - vid: number; - name: string; - skey: string; - rt: string; - updatedAt: number; + token: string; + vid: number; + name: string; + skey: string; + rt: string; + updatedAt: number; } - /** * 根据 token 获取用户凭证 * @param token 用户token */ export async function getByToken(token: string): Promise { - const credentialEntry = await kv.get(["credentials", token]); - if (!credentialEntry.value) { - return { - token: '', - vid: -1, - name: 'unknown', - skey: '', - rt: '', - updatedAt: 0 - } - } - return credentialEntry.value as Credential; + const credentialEntry = await kv.get(["credentials", token]); + if (!credentialEntry.value) { + return { + token: "", + vid: -1, + name: "unknown", + skey: "", + rt: "", + updatedAt: 0, + }; + } + return credentialEntry.value as Credential; } /** @@ -38,12 +39,12 @@ export async function getByToken(token: string): Promise { * @param vid */ export async function getTokenByVid(vid: number): Promise { - const tokenEntry = await kv.get(["vid", vid]) - if (tokenEntry.value) { - return tokenEntry.value as string - } else { - return null - } + const tokenEntry = await kv.get(["vid", vid]); + if (tokenEntry.value) { + return tokenEntry.value as string; + } else { + return null; + } } /** @@ -51,8 +52,8 @@ export async function getTokenByVid(vid: number): Promise { * @param credential */ export function getCookieByCredential(credential: Credential) { - const {vid, skey, rt} = credential; - return `wr_vid=${vid};wr_skey=${skey};wr_rt=${rt};`; + const { vid, skey, rt } = credential; + return `wr_vid=${vid};wr_skey=${skey};wr_rt=${rt};`; } /** @@ -60,8 +61,8 @@ export function getCookieByCredential(credential: Credential) { * @param credential */ export async function update(credential: Credential) { - await kv.atomic() - .set(["credentials", credential.token], credential) - .set(["vid", credential.vid], credential.token) - .commit() + await kv.atomic() + .set(["credentials", credential.token], credential) + .set(["vid", credential.vid], credential.token) + .commit(); } diff --git a/src/kv/db.ts b/src/kv/db.ts deleted file mode 100644 index ca5cbb1..0000000 --- a/src/kv/db.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {dotenv} from "../deps.ts" -import {runInDenoDeploy} from "../utils/index.ts"; - -let kv: Deno.Kv - -if (runInDenoDeploy()) { - kv = await Deno.openKv() -} else { - const env = await dotenv.load() - Deno.env.set('DENO_KV_ACCESS_TOKEN', env["DENO_KV_ACCESS_TOKEN"]) - kv = await Deno.openKv( - `https://api.deno.com/databases/${env["DENO_KV_UUID"]}/connect`, - ); -} - -export default kv diff --git a/src/kv/download.ts b/src/kv/download.ts index 4aa425f..2278b8c 100644 --- a/src/kv/download.ts +++ b/src/kv/download.ts @@ -1,13 +1,13 @@ import { MAX_DOWNLOAD_COUNT_PER_MONTH } from "../config.ts"; -import kv from "./db.ts" -import {now} from "../utils/index.ts"; -import {insertDownloadRecords} from "../database/download.ts"; +import { now, runInDenoDeploy } from "../utils/index.ts"; +import { insertDownloadRecords } from "../database/download.ts"; import type { Credential } from "./credential.ts"; +import runtime from "../runtime.ts"; +const kv = runtime.kv; interface DownloadSecret { bookId: string; - chapterUids: number[]; } /** @@ -24,15 +24,25 @@ export async function checkDownloadCount(credential: Credential) { * @param credential * @param bookId */ -export async function incrementDownloadCount(credential: Credential, bookId: string) { +export async function incrementDownloadCount( + credential: Credential, + bookId: string, +) { await kv.atomic().sum(["download", credential.vid], 1n).commit(); - // 记录下载的书 - await insertDownloadRecords([{ - vid: credential.vid.toString(), - book_id: bookId, - timestamp: now(), - }]) + // 如果是运行在 Deno Deploy 上面,则记录下载的书 + if (runInDenoDeploy()) { + // 可能没有配置,所以包在 try catch 里面执行 + try { + await insertDownloadRecords([{ + vid: credential.vid.toString(), + book_id: bookId, + timestamp: now(), + }]); + } catch (_) { + console.log("没有配置 DATABASE_URL 环境变量,下载记录保存失败"); + } + } } /** @@ -44,21 +54,17 @@ export async function incrementDownloadCount(credential: Credential, bookId: str export async function newDownloadSecret( credential: Credential, bookId: string, - chapterUids: number[], ) { const secret = crypto.randomUUID(); const payload: DownloadSecret = { bookId: bookId, - chapterUids: chapterUids, - } + }; await kv.set(["download", credential.token, secret], payload, { expireIn: 1000 * 60 * 5, // 5分钟有效 }); return secret; } - - /** * 使用下载凭证,有效期内(5分钟)可重复使用 * @param credential @@ -67,10 +73,14 @@ export async function newDownloadSecret( export async function useSecret( credential: Credential, secret: string, -): Promise<[boolean, string, number[]]> { - const entry = await kv.get(["download", credential.token, secret]); +): Promise<[boolean, string]> { + const entry = await kv.get([ + "download", + credential.token, + secret, + ]); if (entry.value) { - return [true, entry.value.bookId, entry.value.chapterUids]; + return [true, entry.value.bookId]; } - return [false, "", []]; + return [false, ""]; } diff --git a/src/kv/setting.ts b/src/kv/setting.ts new file mode 100644 index 0000000..f05f567 --- /dev/null +++ b/src/kv/setting.ts @@ -0,0 +1,128 @@ +import type { Credential } from "./credential.ts"; +import { getUlid, timestamp } from "../utils/index.ts"; +import runtime from "../runtime.ts"; + +interface EmailPreSetting { + vid: number; + email: string; +} + +type NotifyMethodType = "email" | "mp" | "ding"; + +interface NotifyMethod { + id: string; + type: NotifyMethodType; + value: string; + created: number; +} + +const kv = runtime.kv; + +/** + * 检查该用户是否已经发送了验证邮件 + * @param credential + */ +export async function hasAlreadySend(credential: Credential) { + for await (const it of kv.list({ prefix: ["secret", credential.vid] })) { + if ((it.value as EmailPreSetting).vid === credential.vid) { + return true; + } + } + return false; +} + +/** + * 检查该邮箱是否已被绑定 + * @param credential + * @param email + */ +export async function hasAlreadyBind(credential: Credential, email: string) { + const setting = await kv.get(["setting", credential.vid]); + if (setting.value) { + return (setting.value as NotifyMethod[]).some((_) => + _.type === "email" && _.value === email + ); + } else { + return false; + } +} + +/** + * 设置邮件验证的secret + * @param credential + * @param email + * @param secret + */ +export async function setupEmailVerifyToken( + credential: Credential, + email: string, + secret: string, +) { + const payload: EmailPreSetting = { + vid: credential.vid, + email: email, + }; + await kv.set(["secret", credential.vid, secret], payload, { + expireIn: 1000 * 60 * 60 * 2, // 2小时有效 + }); +} + +export async function deletePreSetting(credential: Credential, secret: string) { + await kv.delete(["secret", credential.vid, secret]); +} + +/** + * 确认邮箱绑定 + * @param vid + * @param secret + */ +export async function confirmEmailBind(vid: number, secret: string) { + const emailEntry = await kv.get(["secret", vid, secret]); + if (emailEntry.value) { + // 邮箱验证成功 + const emailEntryPayload: EmailPreSetting = emailEntry + .value as EmailPreSetting; + + let notifies: NotifyMethod[] = []; + const oldSetting = await kv.get(["setting", vid]); + if (oldSetting.value) { + notifies = oldSetting.value as NotifyMethod[]; + } + + notifies.push({ + id: getUlid(), + created: timestamp(), + type: "email", + value: emailEntryPayload.email, + }); + + await kv.set(["setting", vid], notifies); + return true; + } + return false; +} + +/** + * 获取全部配置 + * @param credential + */ +export async function getNotifies(credential: Credential) { + const entry = await kv.get(["setting", credential.vid]); + return (entry.value as NotifyMethod[]) || []; +} + +/** + * 删除配置 + * @param credential + * @param id + */ +export async function deleteNotify(credential: Credential, id: string) { + const entry = await kv.get(["setting", credential.vid]); + if (entry.value) { + const list = (entry.value as NotifyMethod[]).filter((_) => _.id !== id); + await kv.set(entry.key, list); + return [true, list]; + } else { + return [false, []]; + } +} diff --git a/src/kv/task.ts b/src/kv/task.ts index ddc8a62..ef39cc8 100644 --- a/src/kv/task.ts +++ b/src/kv/task.ts @@ -1,31 +1,35 @@ -import kv from "./db.ts" -import type {Credential} from "./credential.ts"; +import type { Credential } from "./credential.ts"; +import { getNotifies } from "./setting.ts"; +import { getTaskPauseHtml, sendEmail } from "../utils/email.ts"; +import runtime from "../runtime.ts"; +import {timestamp} from "../utils/index.ts"; + +const kv = runtime.kv; // 自动阅读的书籍信息 export interface BookInfo { - bookId: string - title: string - author: string + bookId: string; + title: string; + author: string; } // 自动阅读任务 export interface ReadingTask { - credential: Credential - book: BookInfo - params: Record - seconds: number - createdAt: number - updatedAt: number - isActive: boolean + credential: Credential; + book: BookInfo; + params: Record; + seconds: number; + createdAt: number; + updatedAt: number; + isActive: boolean; } - export async function setReaderToken(readerToken: string) { - await kv.set(["reader.token"], readerToken) + await kv.set(["reader.token"], readerToken); } export async function getReaderToken(): Promise { - return (await kv.get(["reader.token"])).value + return (await kv.get(["reader.token"])).value; } /** @@ -36,21 +40,27 @@ export async function getReaderToken(): Promise { * @param ps * @param createdAt */ -export async function addReadingTask(credential: Credential, bookInfo: BookInfo, pc: number, ps: number, createdAt = Date.now()) { - // 添加新的任务 - const task: ReadingTask = { - credential: credential, - book: bookInfo, - params: { - pc, - ps, - }, - seconds: 0, - createdAt: createdAt, - updatedAt: Date.now(), - isActive: true, - } - await kv.set(["task", "read", credential.vid], task) +export async function addReadingTask( + credential: Credential, + bookInfo: BookInfo, + pc: number, + ps: number, + createdAt = Date.now(), +) { + // 添加新的任务 + const task: ReadingTask = { + credential: credential, + book: bookInfo, + params: { + pc, + ps, + }, + seconds: 0, + createdAt: createdAt, + updatedAt: Date.now(), + isActive: true, + }; + await kv.set(["task", "read", credential.vid], task); } /** @@ -59,38 +69,41 @@ export async function addReadingTask(credential: Credential, bookInfo: BookInfo, * @param seconds */ export async function updateReadingTask(credential: Credential, seconds = 0) { - const entry = await kv.get(["task", "read", credential.vid]) - if (!entry.value) { - // 任务不存在 - console.warn(`任务不存在: (vid: ${credential.vid}, name: ${credential.name})`, entry) - return - } + const entry = await kv.get(["task", "read", credential.vid]); + if (!entry.value) { + // 任务不存在 + console.warn( + `任务不存在: (vid: ${credential.vid}, name: ${credential.name})`, + entry, + ); + return; + } - const task = entry.value as ReadingTask - - // 执行时间(中国时间) - const date = new Intl.DateTimeFormat("zh-CN", { - dateStyle: "short", - timeStyle: "medium", - timeZone: "Asia/Shanghai", - }).format(Date.now()).split(' ')[0] - const lastUpdateDate = new Intl.DateTimeFormat("zh-CN", { - dateStyle: "short", - timeStyle: "medium", - timeZone: "Asia/Shanghai", - }).format(task.updatedAt).split(' ')[0] - - if (date > lastUpdateDate) { - // 当天第一次执行 - task.seconds = seconds - } else if (date === lastUpdateDate) { - task.seconds += seconds - } else { - console.warn(`task更新时间:${date}, 上次更新时间:${lastUpdateDate}`) - console.warn(credential, seconds) - } - task.updatedAt = Date.now() - await kv.set(["task", "read", credential.vid], task) + const task = entry.value as ReadingTask; + + // 执行时间(中国时间) + const date = new Intl.DateTimeFormat("zh-CN", { + dateStyle: "short", + timeStyle: "medium", + timeZone: "Asia/Shanghai", + }).format(Date.now()).split(" ")[0]; + const lastUpdateDate = new Intl.DateTimeFormat("zh-CN", { + dateStyle: "short", + timeStyle: "medium", + timeZone: "Asia/Shanghai", + }).format(task.updatedAt).split(" ")[0]; + + if (date > lastUpdateDate) { + // 当天第一次执行 + task.seconds = seconds; + } else if (date === lastUpdateDate) { + task.seconds += seconds; + } else { + console.warn(`task更新时间:${date}, 上次更新时间:${lastUpdateDate}`); + console.warn(credential, seconds); + } + task.updatedAt = Date.now(); + await kv.set(["task", "read", credential.vid], task); } /** @@ -98,8 +111,25 @@ export async function updateReadingTask(credential: Credential, seconds = 0) { * @param task */ export async function pauseReadTask(task: ReadingTask) { - task.isActive = false - await kv.set(["task", "read", task.credential.vid], task) + task.isActive = false; + await kv.set(["task", "read", task.credential.vid], task); + + // 发送提醒通知 + const notifies = await getNotifies(task.credential); + for (const notifyMethod of notifies) { + if (notifyMethod.type === "email") { + // 发送邮件通知 + const result = await sendEmail( + notifyMethod.value, + "任务暂停通知", + getTaskPauseHtml(runtime.deployDomain), + ); + console.log(`发送任务暂停提醒邮件${notifyMethod.value}`); + if (!result) { + console.warn("通知邮件发送失败"); + } + } + } } /** @@ -108,37 +138,39 @@ export async function pauseReadTask(task: ReadingTask) { * @param credential */ export async function updateTaskToken(credential: Credential) { - const taskEntry = await kv.get(["task", "read", credential.vid]) - if (taskEntry.value) { - const task = taskEntry.value as ReadingTask - task.credential = credential - task.isActive = true - await kv.set(taskEntry.key, task) - } + const taskEntry = await kv.get(["task", "read", credential.vid]); + if (taskEntry.value) { + const task = taskEntry.value as ReadingTask; + task.credential = credential; + task.isActive = true; + await kv.set(taskEntry.key, task); + } } /** * 检索用户的任务 * @param credential */ -export async function getReadingTask(credential: Credential): Promise { - const entry = await kv.get(["task", "read", credential.vid]) - if (entry.value) { - return entry.value as ReadingTask - } else { - return null - } +export async function getReadingTask( + credential: Credential, +): Promise { + const entry = await kv.get(["task", "read", credential.vid]); + if (entry.value) { + return entry.value as ReadingTask; + } else { + return null; + } } /** * 查询所有用户的阅读任务 */ export async function getAllReadingTask(): Promise { - const tasks: ReadingTask[] = [] - for await (const task of kv.list({prefix: ["task", "read"]})) { - tasks.push(task.value) - } - return tasks + const tasks: ReadingTask[] = []; + for await (const task of kv.list({ prefix: ["task", "read"] })) { + tasks.push(task.value); + } + return tasks; } /** @@ -146,5 +178,19 @@ export async function getAllReadingTask(): Promise { * @param credential */ export async function removeReadingTask(credential: Credential) { - await kv.delete(["task", "read", credential.vid]) + await kv.delete(["task", "read", credential.vid]); +} + +export async function runningReadTask() { + const entry = await kv.get(["state", "cron::runReadTask"]); + return entry.value === "running"; +} +export async function setReadTaskState() { + await kv.set(["state", "cron::runReadTask"], { + state: "running", + timestamp: timestamp(), + }); +} +export async function clearReadTaskState() { + await kv.delete(["state", "cron::runReadTask"]); } diff --git a/src/router.ts b/src/router.ts index 59cd4c4..ec0eca4 100644 --- a/src/router.ts +++ b/src/router.ts @@ -3,8 +3,8 @@ import { bookChapters, bookDetail, bookDownload, + bookHash, bookList, - bookSearch, getDownloadSecret, } from "./frontend/apis/shelf.ts"; import {reviewList} from "./frontend/apis/review.ts"; @@ -18,6 +18,11 @@ import { import {runExchangeTask} from "./cron/exchange.ts"; import {runReadTask} from "./cron/read.ts"; import {getPdfUrl} from "./frontend/apis/misc.ts"; +import {downloadAsset} from "./frontend/apis/assets.ts"; +import {bindEmail, deleteNotifyMethod, getSettings, sendVerifyEmail} from "./frontend/apis/notify.ts"; + + +import {pauseDownload, resumeDownload} from "./frontend/apis/downloadSSE.ts"; type APIHandler = (req: Request) => Response | Promise @@ -30,8 +35,8 @@ const config: Record = { '/api/book/chapters': bookChapters, '/api/book/download/secret': getDownloadSecret, '/api/book/download': bookDownload, - '/api/book/search': bookSearch, '/api/book/getUrl': getPdfUrl, + '/api/book/hash': bookHash, '/api/review/list': reviewList, @@ -42,6 +47,16 @@ const config: Record = { '/cron/exchange-awards': runExchangeTask, // 兑换体验卡 '/cron/read/v2': runReadTask, // 自动阅读任务 + + '/api/asset/download': downloadAsset, // 代理前端进行资源下载 + + '/api/getSettings': getSettings, // 获取用户设置 + '/api/notify/deleteNotifyMethod': deleteNotifyMethod, + '/api/notify/sendVerifyEmail': sendVerifyEmail, + '/api/bind/email': bindEmail, // 绑定邮箱 + '/api/download/pause': pauseDownload, + '/api/download/resume': resumeDownload, + } /** diff --git a/src/runtime.ts b/src/runtime.ts new file mode 100644 index 0000000..391ed6a --- /dev/null +++ b/src/runtime.ts @@ -0,0 +1,61 @@ +import {dotenv} from "./deps.ts" +import {runInDenoDeploy} from "./utils/index.ts"; + +let env = await dotenv.load() + +if (Object.keys(env).length === 0) { + env = { + DATABASE_URL: "postgresql://postgres:1@example.com:5432/postgres" + } +} + +let deployDomain: string +if (runInDenoDeploy()) { + deployDomain = Deno.env.get("DEPLOY_DOMAIN")! || ''; +} else { + deployDomain = env["DEPLOY_DOMAIN"] || ''; +} +deployDomain = deployDomain.replace(/\/$/g, '') + + +let resendDomain: string +if (runInDenoDeploy()) { + resendDomain = Deno.env.get("RESEND_DOMAIN")! || '' +} else { + resendDomain = env["RESEND_DOMAIN"] || '' +} +resendDomain = resendDomain.replace(/\/$/g, '').replace(/^https?:\/\//i, '') + + +let kv: Deno.Kv +if (runInDenoDeploy() || Deno.args.includes("local")) { + kv = await Deno.openKv() +} else { + Deno.env.set('DENO_KV_ACCESS_TOKEN', env["DENO_KV_ACCESS_TOKEN"]) + kv = await Deno.openKv( + `https://api.deno.com/databases/${env["DENO_KV_UUID"]}/connect`, + ); +} + + +let databaseUrl: string +if (runInDenoDeploy()) { + databaseUrl = Deno.env.get("DATABASE_URL")! || env["DATABASE_URL"] || ''; +} else { + databaseUrl = env["DATABASE_URL"] || ''; +} + +let cronKey: string +if (runInDenoDeploy()) { + cronKey = Deno.env.get("CRON_KEY")! || '' +} else { + cronKey = env["CRON_KEY"] || '' +} + +export default { + deployDomain, + resendDomain, + kv, + databaseUrl, + cronKey, +} diff --git a/src/utils/email.ts b/src/utils/email.ts new file mode 100644 index 0000000..779d7f7 --- /dev/null +++ b/src/utils/email.ts @@ -0,0 +1,92 @@ +import runtime from "../runtime.ts"; + +const RESEND_API_KEY = Deno.env.get("RESEND_API_KEY")!; + +const template1 = ` + + + + + 通知 + + + +

      绑定邮箱通知

      +

      您正在请求绑定该邮箱用于 WeReadX(https://weread.deno.dev/) 发送通知消息之目的。

      +

      若同意绑定,请点击下面的链接。

      +__NOTIFY_URL__ + +

      若不是您发起的请求,请忽略该邮件。

      + + +`; +const template2 = ` + + + + + 通知 + + + +

      自动阅读任务已被暂停

      +

      由于 cookie 失效,自动阅读任务已被暂停,请重新扫码登录即可重启任务

      +__NOTIFY_URL__ + + +`; + +export function getEmailVerifyHtml(notifyUrl: string) { + return template1.replace(/__NOTIFY_URL__/g, notifyUrl); +} + +export function getTaskPauseHtml(notifyUrl: string) { + return template2.replace(/__NOTIFY_URL__/g, notifyUrl); +} + +/** + * 发送电子邮件 + * @param receiver 接收者邮箱 + * @param subject 主题 + * @param html 邮件内容 + */ +export async function sendEmail( + receiver: string, + subject: string, + html: string, +) { + const res = await fetch("https://api.resend.com/emails", { + method: "POST", + headers: { + "Content-Type": "application/json", + "Authorization": `Bearer ${RESEND_API_KEY}`, + }, + body: JSON.stringify({ + from: `WeReadX提醒 `, + to: receiver, + subject: subject, + html: html, + }), + }); + + if (res.ok) { + return await res.json(); + } else { + console.warn(`邮件发送失败: (${receiver}:${subject}:${res.status})`); + return false; + } +} diff --git a/src/utils/encode.ts b/src/utils/encode.ts index 5ccf97b..d86c14d 100644 --- a/src/utils/encode.ts +++ b/src/utils/encode.ts @@ -1,12 +1,12 @@ -import {base64, crypto} from "../deps.ts" +import { base64, crypto } from "../deps.ts"; /** * md5 哈希 * @param raw */ export function md5(raw: string): string { - const buf = new TextEncoder().encode(raw).buffer; - return crypto.toHashString(crypto.crypto.subtle.digestSync("MD5", buf)); + const buf = new TextEncoder().encode(raw).buffer; + return crypto.toHashString(crypto.crypto.subtle.digestSync("MD5", buf)); } /** @@ -14,37 +14,56 @@ export function md5(raw: string): string { * @param raw */ export function sha256(raw: string): string { - const buf = new TextEncoder().encode(raw).buffer; - return crypto.toHashString(crypto.crypto.subtle.digestSync("SHA-256", buf)); + const buf = new TextEncoder().encode(raw).buffer; + return crypto.toHashString(crypto.crypto.subtle.digestSync("SHA-256", buf)); } /** * base64 解码 * @param input */ -export function base64Decode(input: string) { - return new TextDecoder().decode(base64.decode(input)); +// export function base64Decode(input: string) { +// return new TextDecoder().decode(base64.decode(input)); +// } +export function base64Decode(input: string): string { + try { + // 清理字符串 + const cleaned = input.replace(/\s+/g, ''); // 去除空格 + if (!/^[A-Za-z0-9+/]+={0,2}$/.test(cleaned)) { + console.log(input); + throw new Error("Invalid Base64 string"); + } + return new TextDecoder().decode(base64.decode(cleaned)); // 使用 cleaned 进行解码 + } catch (error) { + console.error("Base64 decode error:", error); + return ""; // 返回空字符串以保持正常执行 + } } + + /** * base64 编码 * @param input */ export function base64Encode(input: string) { - return base64.encode(input); + return base64.encode(input); } // todo: 用户登录后的token采用 aes(vid + '一个固定的随机数') // 这样可以避免因用户删除本地缓存后重新登录,token变化的问题 export async function aes() { - const key = await crypto.crypto.subtle.generateKey( - { name: "AES-CBC", length: 128 }, - true, - ["encrypt", "decrypt"], - ) - console.log(key) - const jwk = await crypto.crypto.subtle.exportKey("jwk", key) - - const k = await crypto.crypto.subtle.importKey("jwk", jwk, "AES-CBC", true, ["encrypt", "decrypt"]) - return k + const key = await crypto.crypto.subtle.generateKey( + { name: "AES-CBC", length: 128 }, + true, + ["encrypt", "decrypt"], + ); + console.log(key); + const jwk = await crypto.crypto.subtle.exportKey("jwk", key); + + const k = await crypto.crypto.subtle.importKey("jwk", jwk, "AES-CBC", true, [ + "encrypt", + "decrypt", + ]); + return k; } diff --git a/src/utils/html.ts b/src/utils/html.ts index a210612..5aa3f82 100644 --- a/src/utils/html.ts +++ b/src/utils/html.ts @@ -1,25 +1,27 @@ +// deno-lint-ignore-file no-explicit-any + /// -import {xss, parse5} from "../deps.ts" +import { parse5, xss } from "../deps.ts"; import m1039 from "./style.ts"; interface TagInfo { - tag: string; - srcHtml: string; - src?: string; - isClosing: boolean; - pos: number; - srcPos: number; + tag: string; + srcHtml: string; + src?: string; + isClosing: boolean; + pos: number; + srcPos: number; } interface BodyContentLengthAndIndex { - contentLength: number; - indexInFullHtml: number; + contentLength: number; + indexInFullHtml: number; } interface ParsedBodyHtmlResult { - allContentMerged: string; - contentLengthAndIndex: BodyContentLengthAndIndex[]; + allContentMerged: string; + contentLengthAndIndex: BodyContentLengthAndIndex[]; } let filterXSSInstance: xss.FilterXSS | undefined = undefined; @@ -28,583 +30,583 @@ let _0x470115: BodyContentLengthAndIndex[] = []; let charTotal = 0; function newFilterXSSInstance() { - const baseAttrs = ["class", "id"]; - const options = { - "whiteList": { - "body": baseAttrs.concat(["class", "style"]), - "a": baseAttrs.concat(["target", "href", "title"]), - "abbr": baseAttrs.concat(["title"]), - "address": baseAttrs, - "area": baseAttrs.concat(["shape", "coords", "href", "alt"]), - "article": baseAttrs, - "aside": baseAttrs, - "audio": baseAttrs.concat([ - "autoplay", - "controls", - "loop", - "preload", - "src", - ]), - "b": baseAttrs, - "bdi": baseAttrs.concat(["dir"]), - "bdo": baseAttrs.concat(["dir"]), - "big": baseAttrs, - "blockquote": baseAttrs.concat(["cite"]), - "br": baseAttrs, - "caption": baseAttrs, - "center": baseAttrs, - "cite": baseAttrs, - "code": baseAttrs, - "col": baseAttrs.concat(["align", "valign", "span", "width"]), - "colgroup": baseAttrs.concat(["align", "valign", "span", "width"]), - "dd": baseAttrs, - "del": baseAttrs.concat(["datetime"]), - "details": baseAttrs.concat(["open"]), - "div": baseAttrs, - "dl": baseAttrs, - "dt": baseAttrs, - "em": baseAttrs, - "font": baseAttrs.concat(["color", "size", "face"]), - "footer": baseAttrs, - "h1": baseAttrs, - "h2": baseAttrs, - "h3": baseAttrs, - "h4": baseAttrs, - "h5": baseAttrs, - "h6": baseAttrs, - "header": baseAttrs, - "hr": baseAttrs, - "i": baseAttrs, - "img": baseAttrs.concat([ - "src", - "alt", - "title", - "width", - "height", - "data-w", - "data-ratio", - "data-w-new", - ]), - "ins": baseAttrs.concat(["datetime"]), - "li": baseAttrs, - "mark": baseAttrs, - "nav": baseAttrs, - "ol": baseAttrs, - "p": baseAttrs, - "pre": baseAttrs, - "s": baseAttrs, - "section": baseAttrs, - "small": baseAttrs, - "span": baseAttrs, - "sub": baseAttrs, - "sup": baseAttrs, - "strong": baseAttrs, - "table": baseAttrs.concat(["width", "border", "align", "valign"]), - "tbody": baseAttrs.concat(["align", "valign"]), - "td": baseAttrs.concat([ - "width", - "rowspan", - "colspan", - "align", - "valign", - ]), - "tfoot": baseAttrs.concat(["align", "valign"]), - "th": baseAttrs.concat([ - "width", - "rowspan", - "colspan", - "align", - "valign", - ]), - "thead": baseAttrs.concat(["align", "valign"]), - "tr": baseAttrs.concat(["rowspan", "align", "valign"]), - "tt": baseAttrs, - "u": baseAttrs, - "ul": baseAttrs, - "video": baseAttrs.concat([ - "autoplay", - "controls", - "loop", - "preload", - "src", - "height", - "width", - ]), - }, - "onTag": function ( - tag: string, - html: string, - options: Record, - ) { - if (options.isWhite) { - tagInfos.push({ - "tag": tag, - "srcHtml": html, - "isClosing": options.isClosing, - "pos": options.position, - "srcPos": options.sourcePosition, - }); - } - }, - "onIgnoreTag": function ( - _tag: string, - _html: string, - _options: Record, - ) { - return ""; - }, - "onIgnoreTagAttr": function (_tag: string, name: string, value: string) { - if ("style" === name) { - return 'style="' + value + '"'; - } - }, - "safeAttrValue": function ( - tag: string, - name: string, - value: string, - _0x1ca484: any, - ) { - const safeAttrValue = xss.safeAttrValue(tag, name, value, _0x1ca484); - - if ( - "video" === tag && "src" === name && "" === safeAttrValue && - 0 === value.indexOf("../") - ) { - return value; - } else if ("img" === tag && "src" === name) { - if (tagInfos.length && "img" === tagInfos[tagInfos.length - 1].tag) { - tagInfos[tagInfos.length - 1].src = value; - } - return value; - } else { - return safeAttrValue; - } - }, - }; - return new xss.FilterXSS(options); + const baseAttrs = ["class", "id"]; + const options = { + "whiteList": { + "body": baseAttrs.concat(["class", "style"]), + "a": baseAttrs.concat(["target", "href", "title"]), + "abbr": baseAttrs.concat(["title"]), + "address": baseAttrs, + "area": baseAttrs.concat(["shape", "coords", "href", "alt"]), + "article": baseAttrs, + "aside": baseAttrs, + "audio": baseAttrs.concat([ + "autoplay", + "controls", + "loop", + "preload", + "src", + ]), + "b": baseAttrs, + "bdi": baseAttrs.concat(["dir"]), + "bdo": baseAttrs.concat(["dir"]), + "big": baseAttrs, + "blockquote": baseAttrs.concat(["cite"]), + "br": baseAttrs, + "caption": baseAttrs, + "center": baseAttrs, + "cite": baseAttrs, + "code": baseAttrs, + "col": baseAttrs.concat(["align", "valign", "span", "width"]), + "colgroup": baseAttrs.concat(["align", "valign", "span", "width"]), + "dd": baseAttrs, + "del": baseAttrs.concat(["datetime"]), + "details": baseAttrs.concat(["open"]), + "div": baseAttrs, + "dl": baseAttrs, + "dt": baseAttrs, + "em": baseAttrs, + "font": baseAttrs.concat(["color", "size", "face"]), + "footer": baseAttrs, + "h1": baseAttrs, + "h2": baseAttrs, + "h3": baseAttrs, + "h4": baseAttrs, + "h5": baseAttrs, + "h6": baseAttrs, + "header": baseAttrs, + "hr": baseAttrs, + "i": baseAttrs, + "img": baseAttrs.concat([ + "src", + "alt", + "title", + "width", + "height", + "data-w", + "data-ratio", + "data-w-new", + ]), + "ins": baseAttrs.concat(["datetime"]), + "li": baseAttrs, + "mark": baseAttrs, + "nav": baseAttrs, + "ol": baseAttrs, + "p": baseAttrs, + "pre": baseAttrs, + "s": baseAttrs, + "section": baseAttrs, + "small": baseAttrs, + "span": baseAttrs, + "sub": baseAttrs, + "sup": baseAttrs, + "strong": baseAttrs, + "table": baseAttrs.concat(["width", "border", "align", "valign"]), + "tbody": baseAttrs.concat(["align", "valign"]), + "td": baseAttrs.concat([ + "width", + "rowspan", + "colspan", + "align", + "valign", + ]), + "tfoot": baseAttrs.concat(["align", "valign"]), + "th": baseAttrs.concat([ + "width", + "rowspan", + "colspan", + "align", + "valign", + ]), + "thead": baseAttrs.concat(["align", "valign"]), + "tr": baseAttrs.concat(["rowspan", "align", "valign"]), + "tt": baseAttrs, + "u": baseAttrs, + "ul": baseAttrs, + "video": baseAttrs.concat([ + "autoplay", + "controls", + "loop", + "preload", + "src", + "height", + "width", + ]), + }, + "onTag": function ( + tag: string, + html: string, + options: Record, + ) { + if (options.isWhite) { + tagInfos.push({ + "tag": tag, + "srcHtml": html, + "isClosing": options.isClosing, + "pos": options.position, + "srcPos": options.sourcePosition, + }); + } + }, + "onIgnoreTag": function ( + _tag: string, + _html: string, + _options: Record, + ) { + return ""; + }, + "onIgnoreTagAttr": function (_tag: string, name: string, value: string) { + if ("style" === name) { + return 'style="' + value + '"'; + } + }, + "safeAttrValue": function ( + tag: string, + name: string, + value: string, + _0x1ca484: any, + ) { + const safeAttrValue = xss.safeAttrValue(tag, name, value, _0x1ca484); + + if ( + "video" === tag && "src" === name && "" === safeAttrValue && + 0 === value.indexOf("../") + ) { + return value; + } else if ("img" === tag && "src" === name) { + if (tagInfos.length && "img" === tagInfos[tagInfos.length - 1].tag) { + tagInfos[tagInfos.length - 1].src = value; + } + return value; + } else { + return safeAttrValue; + } + }, + }; + return new xss.FilterXSS(options); } function _0x4e3ea2(tagInfo: TagInfo) { - let _0x49a03d = tagInfo.srcPos, - _0x530bce = 0; - for (let i = 0; i < _0x470115.length; i++) { - const _0x25038b = _0x470115[i]; - if ( - tagInfo.srcPos >= _0x530bce && - tagInfo.srcPos < _0x530bce + _0x25038b.contentLength - ) { - _0x49a03d += _0x25038b.indexInFullHtml - _0x530bce; - break; - } - _0x530bce += _0x25038b.contentLength; + let _0x49a03d = tagInfo.srcPos, + _0x530bce = 0; + for (let i = 0; i < _0x470115.length; i++) { + const _0x25038b = _0x470115[i]; + if ( + tagInfo.srcPos >= _0x530bce && + tagInfo.srcPos < _0x530bce + _0x25038b.contentLength + ) { + _0x49a03d += _0x25038b.indexInFullHtml - _0x530bce; + break; } - return _0x49a03d; + _0x530bce += _0x25038b.contentLength; + } + return _0x49a03d; } function _0x476ae0(safeHtml: string, tagInfos: TagInfo[], sectionStep: number) { - if (!safeHtml || 0 === safeHtml.length) { - return []; - } - - const result = [""]; - const _0xee0a6b: TagInfo[] = []; - - let _0x56f74b = 0, - _0x1f3df2 = 0, - _0x400a12 = 0; - - const _0x16ef8e = function () { - const tagInfo = tagInfos[_0x400a12]; - if (tagInfo.isClosing) { - // 闭合标签 - _0xee0a6b.length && _0xee0a6b[_0xee0a6b.length - 1].tag === tagInfo.tag - ? _0xee0a6b.pop() - : console.log( - "Close tag no opened match:" + JSON.stringify(_0xee0a6b) + - JSON.stringify(tagInfo.tag), - ); - _0x1f3df2 = safeHtml.indexOf(">", tagInfo.pos) + 1; - result[result.length - 1] += safeHtml.slice(_0x56f74b, _0x1f3df2); - _0x56f74b = _0x1f3df2; - - const _0x1e0e64 = _0x400a12 + 1 < tagInfos.length - ? tagInfos[_0x400a12 + 1] - : undefined; - if (_0x1e0e64) { - const _0x374624 = _0x1e0e64.pos, - _0x5980fd = _0x4e3ea2(tagInfo) + tagInfo.srcHtml.length; - - result[result.length - 1] += parseParagraph( - safeHtml, - _0x56f74b, - _0x374624, - _0x5980fd, - ); - _0x56f74b = _0x374624; - if (!result[Math.floor(charTotal / sectionStep)]) { - let _0x30c112 = ""; - if (_0xee0a6b.length) { - _0xee0a6b.forEach((_0x10d1d8) => { - _0x30c112 += _0x10d1d8.srcHtml; - }); - const _0x5b0ef3 = ([] as TagInfo[]).concat(_0xee0a6b); - _0x5b0ef3.reverse(); - for (let i = 0; i < _0x5b0ef3.length; i++) { - const _0x7f55d8 = _0x5b0ef3[i]; - result[result.length - 1] += ""; - } - } - result.push(_0x30c112); - } - } - _0x400a12++; - } else { - if ( - "img" !== tagInfo.tag && "br" !== tagInfo.tag && "hr" !== tagInfo.tag && - "pre" !== tagInfo.tag && "video" !== tagInfo.tag - ) { - _0xee0a6b.push(tagInfo); - } - _0x1f3df2 = tagInfo.pos + 1 + tagInfo.tag.length; - result[result.length - 1] += safeHtml.slice(_0x56f74b, _0x1f3df2); - const _0x44d767 = _0x4e3ea2(tagInfo); - result[result.length - 1] += ' data-wr-co="' + _0x44d767 + '"'; - _0x56f74b = _0x1f3df2; - const _0x2fce5f = safeHtml.indexOf(">", tagInfo.pos) + 1; - let _0x39bed3 = safeHtml.slice(_0x56f74b, _0x2fce5f); - - if ( - "img" === tagInfo.tag && tagInfo.src && -1 !== _0x39bed3.indexOf("src=") - ) { - const url = - 'src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" data-src="'; - _0x39bed3 = _0x39bed3.replace( - 'src="' + tagInfo.src + '"', - url + tagInfo.src + '"', - ); - } - if ("img" === tagInfo.tag && -1 !== _0x39bed3.indexOf("data-w=")) { - try { - const _0x4ae1fd = _0x39bed3.match(/style="([^"]*)"/), - _0x19dd28 = _0x4ae1fd && _0x4ae1fd[1] ? _0x4ae1fd[1] : "", - _0x3f4cbd = _0x39bed3.match(/data-w="([^"]*)"/), - _0x673fcb = _0x39bed3.match(/data-w-new="([^"]*)"/), - _0x39a2c5 = _0x3f4cbd && _0x3f4cbd[1] ? _0x3f4cbd[1] : "", - _0x388c79 = _0x673fcb && _0x673fcb[1] ? _0x673fcb[1] : "", - _0x2584a3 = (_0x39a2c5 ? "max-width:" + _0x39a2c5 + ";" : "") + - (_0x388c79 ? "max-height:" + _0x388c79 + ";" : "") + _0x19dd28; - _0x39bed3 = _0x4ae1fd - ? _0x39bed3.replace(_0x19dd28, _0x2584a3) - : _0x39bed3.replace(">", ' style="' + _0x2584a3 + '">'); - } catch (err) { - console.error(err); - } - } - result[result.length - 1] += _0x39bed3; - _0x56f74b = _0x2fce5f; - if ("pre" === tagInfo.tag) { - const _0x543159 = function (_0x29bbb9, _0x43d76d, _0x500708) { - if (_0x500708 >= _0x29bbb9.length) { - return -1; - } - for (let i = _0x500708; i < _0x29bbb9.length; i++) { - if (_0x43d76d(_0x29bbb9[i])) { - return i; - } - } - return -1; - }( - tagInfos, - (_: TagInfo) => _.tag === tagInfo.tag && _.isClosing, - _0x400a12, - ); - - if (-1 !== _0x543159) { - const _0xe6313 = tagInfos[_0x543159]; - result[result.length - 1] += safeHtml.slice(_0x56f74b, _0xe6313.pos); - _0x56f74b = _0xe6313.pos; - _0x400a12 = _0x543159 + 1; - } else { - _0x400a12++; - } - } else { - const _0x5634c1 = _0x400a12 + 1 < tagInfos.length - ? tagInfos[_0x400a12 + 1] - : undefined; - if (_0x5634c1) { - const _0x39627f = _0x5634c1.pos, - _0x1ea28c = _0x44d767 + tagInfo.srcHtml.length; - result[result.length - 1] += parseParagraph( - safeHtml, - _0x56f74b, - _0x39627f, - _0x1ea28c, - ); - _0x56f74b = _0x39627f; - } - _0x400a12++; + if (!safeHtml || 0 === safeHtml.length) { + return []; + } + + const result = [""]; + const _0xee0a6b: TagInfo[] = []; + + let _0x56f74b = 0, + _0x1f3df2 = 0, + _0x400a12 = 0; + + const _0x16ef8e = function () { + const tagInfo = tagInfos[_0x400a12]; + if (tagInfo.isClosing) { + // 闭合标签 + _0xee0a6b.length && _0xee0a6b[_0xee0a6b.length - 1].tag === tagInfo.tag + ? _0xee0a6b.pop() + : console.log( + "Close tag no opened match:" + JSON.stringify(_0xee0a6b) + + JSON.stringify(tagInfo.tag), + ); + _0x1f3df2 = safeHtml.indexOf(">", tagInfo.pos) + 1; + result[result.length - 1] += safeHtml.slice(_0x56f74b, _0x1f3df2); + _0x56f74b = _0x1f3df2; + + const _0x1e0e64 = _0x400a12 + 1 < tagInfos.length + ? tagInfos[_0x400a12 + 1] + : undefined; + if (_0x1e0e64) { + const _0x374624 = _0x1e0e64.pos, + _0x5980fd = _0x4e3ea2(tagInfo) + tagInfo.srcHtml.length; + + result[result.length - 1] += parseParagraph( + safeHtml, + _0x56f74b, + _0x374624, + _0x5980fd, + ); + _0x56f74b = _0x374624; + if (!result[Math.floor(charTotal / sectionStep)]) { + let _0x30c112 = ""; + if (_0xee0a6b.length) { + _0xee0a6b.forEach((_0x10d1d8) => { + _0x30c112 += _0x10d1d8.srcHtml; + }); + const _0x5b0ef3 = ([] as TagInfo[]).concat(_0xee0a6b); + _0x5b0ef3.reverse(); + for (let i = 0; i < _0x5b0ef3.length; i++) { + const _0x7f55d8 = _0x5b0ef3[i]; + result[result.length - 1] += ""; } + } + result.push(_0x30c112); } - }; - for (; _0x400a12 < tagInfos.length;) { - _0x16ef8e(); - } + } + _0x400a12++; + } else { + if ( + "img" !== tagInfo.tag && "br" !== tagInfo.tag && "hr" !== tagInfo.tag && + "pre" !== tagInfo.tag && "video" !== tagInfo.tag + ) { + _0xee0a6b.push(tagInfo); + } + _0x1f3df2 = tagInfo.pos + 1 + tagInfo.tag.length; + result[result.length - 1] += safeHtml.slice(_0x56f74b, _0x1f3df2); + const _0x44d767 = _0x4e3ea2(tagInfo); + result[result.length - 1] += ' data-wr-co="' + _0x44d767 + '"'; + _0x56f74b = _0x1f3df2; + const _0x2fce5f = safeHtml.indexOf(">", tagInfo.pos) + 1; + let _0x39bed3 = safeHtml.slice(_0x56f74b, _0x2fce5f); + + if ( + "img" === tagInfo.tag && tagInfo.src && -1 !== _0x39bed3.indexOf("src=") + ) { + const url = + 'src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==" data-src="'; + _0x39bed3 = _0x39bed3.replace( + 'src="' + tagInfo.src + '"', + url + tagInfo.src + '"', + ); + } + if ("img" === tagInfo.tag && -1 !== _0x39bed3.indexOf("data-w=")) { + try { + const _0x4ae1fd = _0x39bed3.match(/style="([^"]*)"/), + _0x19dd28 = _0x4ae1fd && _0x4ae1fd[1] ? _0x4ae1fd[1] : "", + _0x3f4cbd = _0x39bed3.match(/data-w="([^"]*)"/), + _0x673fcb = _0x39bed3.match(/data-w-new="([^"]*)"/), + _0x39a2c5 = _0x3f4cbd && _0x3f4cbd[1] ? _0x3f4cbd[1] : "", + _0x388c79 = _0x673fcb && _0x673fcb[1] ? _0x673fcb[1] : "", + _0x2584a3 = (_0x39a2c5 ? "max-width:" + _0x39a2c5 + ";" : "") + + (_0x388c79 ? "max-height:" + _0x388c79 + ";" : "") + _0x19dd28; + _0x39bed3 = _0x4ae1fd + ? _0x39bed3.replace(_0x19dd28, _0x2584a3) + : _0x39bed3.replace(">", ' style="' + _0x2584a3 + '">'); + } catch (err) { + console.error(err); + } + } + result[result.length - 1] += _0x39bed3; + _0x56f74b = _0x2fce5f; + if ("pre" === tagInfo.tag) { + const _0x543159 = function (_0x29bbb9, _0x43d76d, _0x500708) { + if (_0x500708 >= _0x29bbb9.length) { + return -1; + } + for (let i = _0x500708; i < _0x29bbb9.length; i++) { + if (_0x43d76d(_0x29bbb9[i])) { + return i; + } + } + return -1; + }( + tagInfos, + (_: TagInfo) => _.tag === tagInfo.tag && _.isClosing, + _0x400a12, + ); - if (_0x56f74b < safeHtml.length) { - result[result.length - 1] += safeHtml.slice(_0x56f74b); + if (-1 !== _0x543159) { + const _0xe6313 = tagInfos[_0x543159]; + result[result.length - 1] += safeHtml.slice(_0x56f74b, _0xe6313.pos); + _0x56f74b = _0xe6313.pos; + _0x400a12 = _0x543159 + 1; + } else { + _0x400a12++; + } + } else { + const _0x5634c1 = _0x400a12 + 1 < tagInfos.length + ? tagInfos[_0x400a12 + 1] + : undefined; + if (_0x5634c1) { + const _0x39627f = _0x5634c1.pos, + _0x1ea28c = _0x44d767 + tagInfo.srcHtml.length; + result[result.length - 1] += parseParagraph( + safeHtml, + _0x56f74b, + _0x39627f, + _0x1ea28c, + ); + _0x56f74b = _0x39627f; + } + _0x400a12++; + } } - return result; + }; + for (; _0x400a12 < tagInfos.length;) { + _0x16ef8e(); + } + + if (_0x56f74b < safeHtml.length) { + result[result.length - 1] += safeHtml.slice(_0x56f74b); + } + return result; } function _0x5007bc(html: string, style: string) { - let _0x3e3d05 = ""; - let _0x4e4ca0 = 0; - - const re1 = /]*>/g; - const re2 = /class="([^"]+)">/; - let searchResult = re1.exec(html); - for (; searchResult;) { - if (1 === searchResult.length) { - const _0x5aae48 = searchResult[0], - _0x224f62 = searchResult.index, - _0x3f028b = _0x224f62 + _0x5aae48.length; - let _0x3cdab5 = -1 !== _0x5aae48.indexOf("background-image"); - if (!_0x3cdab5) { - const _0x5806e7 = re2.exec(_0x5aae48); - if (_0x5806e7 && 2 === _0x5806e7.length) { - const _0x1db8e7 = _0x5806e7[1].split(" "); - for (let i = 0, _0x2d4038 = _0x1db8e7.length; i < _0x2d4038; i++) { - const _0x497e33 = _0x1db8e7[i], - _0x132da1 = style.indexOf(_0x497e33); - if (-1 !== _0x132da1) { - const _0x482bf8 = style.indexOf("{", _0x132da1); - if (-1 !== _0x482bf8) { - const _0x365cce = style.indexOf("}", _0x482bf8); - if (-1 !== _0x365cce) { - if ( - -1 !== - style.slice(_0x482bf8, _0x365cce).indexOf( - "background-image", - ) - ) { - _0x3cdab5 = true; - break; - } - } - } - } - } + let _0x3e3d05 = ""; + let _0x4e4ca0 = 0; + + const re1 = /]*>/g; + const re2 = /class="([^"]+)">/; + let searchResult = re1.exec(html); + for (; searchResult;) { + if (1 === searchResult.length) { + const _0x5aae48 = searchResult[0], + _0x224f62 = searchResult.index, + _0x3f028b = _0x224f62 + _0x5aae48.length; + let _0x3cdab5 = -1 !== _0x5aae48.indexOf("background-image"); + if (!_0x3cdab5) { + const _0x5806e7 = re2.exec(_0x5aae48); + if (_0x5806e7 && 2 === _0x5806e7.length) { + const _0x1db8e7 = _0x5806e7[1].split(" "); + for (let i = 0, _0x2d4038 = _0x1db8e7.length; i < _0x2d4038; i++) { + const _0x497e33 = _0x1db8e7[i], + _0x132da1 = style.indexOf(_0x497e33); + if (-1 !== _0x132da1) { + const _0x482bf8 = style.indexOf("{", _0x132da1); + if (-1 !== _0x482bf8) { + const _0x365cce = style.indexOf("}", _0x482bf8); + if (-1 !== _0x365cce) { + if ( + -1 !== + style.slice(_0x482bf8, _0x365cce).indexOf( + "background-image", + ) + ) { + _0x3cdab5 = true; + break; + } } + } } - - _0x3e3d05 += html.slice(_0x4e4ca0, _0x224f62); - _0x3e3d05 += _0x3cdab5 - ? _0x5aae48.replace("/g, ""); - return _0x3e3d05; + + searchResult = re1.exec(html); + } + if (_0x4e4ca0 < html.length) { + _0x3e3d05 += html.slice(_0x4e4ca0); + } + _0x3e3d05 = _0x3e3d05.replace(/<\/body>/g, ""); + return _0x3e3d05; } function parseBodyHtml(html: string) { - const result: ParsedBodyHtmlResult = { - "allContentMerged": "", - "contentLengthAndIndex": [], - }; - if (!html || 0 === html.length) { - return result; - } - - const re = /]*>\s*([\s\S]*?)\s*<\/body>/g; - let searchResult = re.exec(html); - for (; searchResult;) { - if (2 === searchResult.length) { - const bodyHtml = searchResult[0]; - const bodyIndex = searchResult.index; - - result.allContentMerged += bodyHtml; - result.contentLengthAndIndex.push({ - "contentLength": bodyHtml.length, - "indexInFullHtml": bodyIndex, - }); - } - searchResult = re.exec(html); - } + const result: ParsedBodyHtmlResult = { + "allContentMerged": "", + "contentLengthAndIndex": [], + }; + if (!html || 0 === html.length) { return result; + } + + const re = /]*>\s*([\s\S]*?)\s*<\/body>/g; + let searchResult = re.exec(html); + for (; searchResult;) { + if (2 === searchResult.length) { + const bodyHtml = searchResult[0]; + const bodyIndex = searchResult.index; + + result.allContentMerged += bodyHtml; + result.contentLengthAndIndex.push({ + "contentLength": bodyHtml.length, + "indexInFullHtml": bodyIndex, + }); + } + searchResult = re.exec(html); + } + return result; } const _0x4cd349 = function _0x4de281(_0x5bc41a: any) { - const _0x1842f8: any[] = []; - _0x5bc41a.childNodes && _0x5bc41a.childNodes.forEach((_0x20e51c: any) => { - if (_0x20e51c.attrs) { - const _0xe0b1f5 = _0x20e51c.attrs.find((_: Attr) => "style" === _.name); - _0xe0b1f5 && _0x1842f8.push(_0xe0b1f5); - } - _0x1842f8.push.apply(_0x1842f8, Array.from(_0x4de281(_0x20e51c))); - }); - return _0x1842f8; + const _0x1842f8: any[] = []; + _0x5bc41a.childNodes && _0x5bc41a.childNodes.forEach((_0x20e51c: any) => { + if (_0x20e51c.attrs) { + const _0xe0b1f5 = _0x20e51c.attrs.find((_: Attr) => "style" === _.name); + _0xe0b1f5 && _0x1842f8.push(_0xe0b1f5); + } + _0x1842f8.push.apply(_0x1842f8, Array.from(_0x4de281(_0x20e51c))); + }); + return _0x1842f8; }; function _0x20c767(html: string) { - const document = parse5.parse(html); - _0x4cd349(document).forEach((_0x15e014) => { - const _0x4c6b0f = "{" + _0x15e014.value + "}", - _0x11d36a = m1039.removeAllFontSizes(_0x4c6b0f); - _0x15e014.value = _0x11d36a.substring(1, _0x11d36a.length - 1); - }); - return parse5.serialize(document); + const document = parse5.parse(html); + _0x4cd349(document).forEach((_0x15e014) => { + const _0x4c6b0f = "{" + _0x15e014.value + "}", + _0x11d36a = m1039.removeAllFontSizes(_0x4c6b0f); + _0x15e014.value = _0x11d36a.substring(1, _0x11d36a.length - 1); + }); + return parse5.serialize(document); } function parseTxt(txt: string, sectionStep = 10000): string[] { - if (!txt || "string" != typeof txt) { - return []; + if (!txt || "string" != typeof txt) { + return []; + } + + const lines = txt.split(/\n/); + const lineContentInfos = []; + let offset = -1; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const lineContent = line.trim(); + offset += 1; + if (lineContent.length > 0) { + lineContentInfos.push({ + "content": lineContent, + "offset": offset + line.indexOf(lineContent), + }); } - - const lines = txt.split(/\n/); - const lineContentInfos = []; - let offset = -1; - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - const lineContent = line.trim(); - offset += 1; - if (lineContent.length > 0) { - lineContentInfos.push({ - "content": lineContent, - "offset": offset + line.indexOf(lineContent), - }); - } - offset += line.length; + offset += line.length; + } + + const result = [""]; + for (let i = 0; i < lineContentInfos.length; i++) { + const lineContentInfo = lineContentInfos[i]; + + const content = parseParagraph( + lineContentInfo.content, + 0, + lineContentInfo.content.length, + lineContentInfo.offset, + ); + result[result.length - 1] += '

      ' + content + "

      "; + + if (!result[Math.floor(lineContentInfo.offset / sectionStep)]) { + result.push(""); } - - const result = [""]; - for (let i = 0; i < lineContentInfos.length; i++) { - const lineContentInfo = lineContentInfos[i]; - - const content = parseParagraph( - lineContentInfo.content, - 0, - lineContentInfo.content.length, - lineContentInfo.offset, - ); - result[result.length - 1] += '

      ' + content + "

      "; - - if (!result[Math.floor(lineContentInfo.offset / sectionStep)]) { - result.push(""); - } - } - return result; + } + return result; } function splitChars(text: string, start: number, end: number) { - const content = text.slice(start, end); - let offset = 0; - const wordLengthArray = []; - - const re = /&#\d*;|&\w*;|[iftjl]*[iftjl]+[iftjl]*/g; - let searchResult = re.exec(content); - for (; searchResult;) { - if (searchResult.length > 0) { - // 搜索到了 - const matchIndex = searchResult.index, - matchLength = searchResult[0].length; - for (; matchIndex > offset;) { - // 处理中间存在空隙 - const blankArea = splitChars(text, start + offset, start + matchIndex); - wordLengthArray.push.apply(wordLengthArray, Array.from(blankArea)); - offset += blankArea.reduce((prev, cur) => prev + cur); - } - wordLengthArray.push(matchLength); - offset = matchIndex + matchLength; - } - searchResult = re.exec(content); + const content = text.slice(start, end); + let offset = 0; + const wordLengthArray = []; + + const re = /&#\d*;|&\w*;|[iftjl]*[iftjl]+[iftjl]*/g; + let searchResult = re.exec(content); + for (; searchResult;) { + if (searchResult.length > 0) { + // 搜索到了 + const matchIndex = searchResult.index, + matchLength = searchResult[0].length; + for (; matchIndex > offset;) { + // 处理中间存在空隙 + const blankArea = splitChars(text, start + offset, start + matchIndex); + wordLengthArray.push.apply(wordLengthArray, Array.from(blankArea)); + offset += blankArea.reduce((prev, cur) => prev + cur); + } + wordLengthArray.push(matchLength); + offset = matchIndex + matchLength; } - - if (wordLengthArray.length > 0) { - return wordLengthArray; - } - - // 没有匹配到正则 - const blankArea = new Array(end - start); - for (let i = 0; i < blankArea.length; i++) { - blankArea[i] = 1; - } - return blankArea; + searchResult = re.exec(content); + } + + if (wordLengthArray.length > 0) { + return wordLengthArray; + } + + // 没有匹配到正则 + const blankArea = new Array(end - start); + for (let i = 0; i < blankArea.length; i++) { + blankArea[i] = 1; + } + return blankArea; } function isEmpty(content: string) { - if (content.trim().replace(/ /g, "").length === 0) { - return true; - } - return /^\s*$/.test(content); + if (content.trim().replace(/ /g, "").length === 0) { + return true; + } + return /^\s*$/.test(content); } function parseParagraph( - text: string, - start: number, - end: number, - offset: number, + text: string, + start: number, + end: number, + offset: number, ) { - const content = text.slice(start, end); - if (isEmpty(content)) { - return content; - } - - let result = ""; - for (let i = start; i < end;) { - splitChars(text, i, end).forEach((charLen) => { - const s1 = ''.replace( - "%%OFFSET%%", - (offset + i - start).toString(), - ); - const char = text.slice(i, i + charLen); - result += s1 + char + ""; - - charTotal++; - i += charLen; - }); - } - return result; + const content = text.slice(start, end); + if (isEmpty(content)) { + return content; + } + + let result = ""; + for (let i = start; i < end;) { + splitChars(text, i, end).forEach((charLen) => { + const s1 = ''.replace( + "%%OFFSET%%", + (offset + i - start).toString(), + ); + const char = text.slice(i, i + charLen); + result += s1 + char + ""; + + charTotal++; + i += charLen; + }); + } + return result; } function parseHtml(html: string, style = "", sectionStep = 10000): string[] { - if (-1 === html.indexOf(" _0x5007bc(_, style)); - - try { - _0xdb20a7 = _0xdb20a7.map((_: string) => _0x20c767(_)); - } catch (err) { - console.log(err); - } - return _0xdb20a7; + if (-1 === html.indexOf(" _0x5007bc(_, style)); + + try { + _0xdb20a7 = _0xdb20a7.map((_: string) => _0x20c767(_)); + } catch (err) { + console.log(err); + } + return _0xdb20a7; } export default { - "parse": parseHtml, - "parseTxt": parseTxt, + "parse": parseHtml, + "parseTxt": parseTxt, }; diff --git a/src/utils/index.ts b/src/utils/index.ts index 4111f68..3e292a9 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,10 +1,10 @@ +// deno-lint-ignore-file no-explicit-any + import { ulid } from "../deps.ts"; import { md5 } from "./encode.ts"; - export const getUlid = ulid.monotonicFactory(); - /** * 根据 ua 生成 appid * @param ua 用户代理字符串 @@ -134,7 +134,7 @@ export function currentTime() { * 当前时间戳,单位是毫秒 */ export function timestamp() { - return new Date().getTime() + return new Date().getTime(); } export function generateQRCode(data: string) { @@ -150,8 +150,8 @@ export function generateQRCode(data: string) { * 是否在deploy中运行代码 */ export function runInDenoDeploy() { - const deploymentId = Deno.env.get("DENO_DEPLOYMENT_ID") - return !!deploymentId + const deploymentId = Deno.env.get("DENO_DEPLOYMENT_ID"); + return !!deploymentId; } /** @@ -164,7 +164,6 @@ export function sleep(duration: number) { }); } - export function now(): string { return new Intl.DateTimeFormat("zh-CN", { dateStyle: "short", @@ -174,17 +173,17 @@ export function now(): string { } function stringify(data: unknown) { - return JSON.stringify(data) + return JSON.stringify(data); } export function jsonResponse(data: unknown) { return new Response( - stringify(data), - { - headers: { - "Content-Type": "application/json", - }, + stringify(data), + { + headers: { + "Content-Type": "application/json", }, + }, ); } @@ -204,18 +203,18 @@ export function randomInteger(min: number, max: number) { * @param seconds */ export function formatSeconds(seconds: number) { - if (typeof seconds !== 'number') { - return seconds + if (typeof seconds !== "number") { + return seconds; } if (seconds < 60) { - return `${seconds}s` + return `${seconds}s`; } - const minutes = Math.floor(seconds / 60) - const second = seconds % 60 + const minutes = Math.floor(seconds / 60); + const second = seconds % 60; if (minutes < 60) { - return `${minutes}m${second}s` + return `${minutes}m${second}s`; } - const hours = Math.floor(minutes / 60) - const minute = minutes % 60 - return `${hours}h${minute}m${second}s` + const hours = Math.floor(minutes / 60); + const minute = minutes % 60; + return `${hours}h${minute}m${second}s`; } diff --git a/src/utils/process.ts b/src/utils/process.ts index 912180d..9c51974 100644 --- a/src/utils/process.ts +++ b/src/utils/process.ts @@ -1,3 +1,7 @@ +// @ts-nocheck: 使用 for of 遍历 node.attributes 会报错,实际上并没有问题 + +import { parseHTML } from "https://esm.sh/linkedom"; + /** * 8.js中的 UPDATE_READER_CONTENT_HTML 和 UPDATE_READER_CONTENT_STYLES 这两个 mutation */ @@ -20,6 +24,7 @@ export function processStyles(styles: string, bookId: string) { return ""; } + // 把 epub 内联图片地址替换成绝对地址,方便 html 进行访问 return matchArray.map((_0x4fc4e3) => { return ".readerChapterContent " + (_0x4fc4e3 = _0x4fc4e3.trim()).split("\n").map(function (_0xde9e6d) { @@ -37,11 +42,11 @@ export function processStyles(styles: string, bookId: string) { /** * 处理html - * @param htmls + * @param sections * @param bookId */ -export function processHtmls(htmls: string[], bookId: string) { - return htmls.map((html) => { +export function processHtmls(sections: string[], bookId: string) { + return sections.map((html) => { return function (html, bookId) { if (!html || html.length <= 0) { return ""; @@ -73,3 +78,63 @@ export function processHtmls(htmls: string[], bookId: string) { }(html || "", bookId); }); } + +/** + * 判断是否为相同的 span 节点 + * @param node1 + * @param node2 + */ +function hasSameAttributes(node1: Element, node2: Element) { + if (node1.attributes.length !== node2.attributes.length) { + return false; + } + + for (const attr of node2.attributes) { + if (attr.name === "data-wr-co") { + continue; + } + const node1Attr = node1.attributes.getNamedItem(attr.name); + if (!node1Attr || node1Attr.value !== attr.value) { + return false; + } + } + + return true; +} + +/** + * 合并相邻的 span 节点 + * @param html + */ +export function mergeSpanInHtml(html: string): string { + const { document } = parseHTML(html); + + const spanElements = Array.from(document.querySelectorAll("span")); + while (spanElements.length > 0) { + const current = spanElements.shift(); + let next; + while ((next = current!.nextSibling)) { + if (next.nodeType === 1) { + // 确认是否与前一个span样式相同 + if (hasSameAttributes(current!, next as Element)) { + // 合并span内容 + current!.innerHTML += (next as Element).innerHTML; + next.remove(); + spanElements.shift(); + } else { + // attributes 不相同,不合并 + break; + } + } else if (next.nodeType === 3) { + if ((next as Text).wholeText.replace(/\s/g, "")) { + // span后面有文本内容,不合并 + break; + } else { + next.remove(); + } + } + } + } + + return document.toString(); +} diff --git a/src/utils/request.ts b/src/utils/request.ts index 80dc495..043b928 100644 --- a/src/utils/request.ts +++ b/src/utils/request.ts @@ -1,4 +1,6 @@ -import { UserAgentForWeb } from "../config.ts"; +// deno-lint-ignore-file no-explicit-any + +import { UserAgentForWeb, Referer } from "../config.ts"; function stringifyQuery( query: Record = {}, @@ -21,6 +23,8 @@ export function get( } const headers: Record = { "User-Agent": UserAgentForWeb, + "Referer": Referer, + "Origin": "https://weread.qq.com", ...header, }; return fetch(url, { @@ -39,6 +43,8 @@ function post( let body; const headers: Record | undefined = { "User-Agent": UserAgentForWeb, + "Referer": Referer, + "Origin": "https://weread.qq.com", ...header, }; diff --git a/src/utils/style.ts b/src/utils/style.ts index 13908de..e520220 100644 --- a/src/utils/style.ts +++ b/src/utils/style.ts @@ -1,3 +1,5 @@ +// deno-lint-ignore-file no-explicit-any + /** * 实现 utils.js 中的 1039 模块: style-parser */ @@ -7,105 +9,105 @@ import * as csstree from "npm:css-tree@2.3.1"; interface ParseOptions { - removeFontSizes: boolean; - enableTranslate: boolean; + removeFontSizes: boolean; + enableTranslate: boolean; } function removeAllFontSizes(style: string) { - const ast = csstree.parse(style); - csstree.walk(ast, { - "visit": "Declaration", - "enter": function (node: any, item: any, list: any) { - if ("font-size" === node.property) { - list.remove(item); - } - }, - }); - return csstree.generate(ast); + const ast = csstree.parse(style); + csstree.walk(ast, { + "visit": "Declaration", + "enter": function (node: any, item: any, list: any) { + if ("font-size" === node.property) { + list.remove(item); + } + }, + }); + return csstree.generate(ast); } function removeTopClassSpanStyle(style: string) { - const ast = csstree.parse(style); - csstree.walk(ast, { - "visit": "Rule", - "enter": function (node: any, item: any, list: any) { - const selectorList = node.prelude; + const ast = csstree.parse(style); + csstree.walk(ast, { + "visit": "Rule", + "enter": function (node: any, item: any, list: any) { + const selectorList = node.prelude; - if ( - csstree.find( - selectorList, - (node: any) => node.type === "TypeSelector" && node.name === "span", - ) && - !csstree.find( - selectorList, - (node: any) => - node.type === "ClassSelector" || node.type === "IdSelector", - ) - ) { - list.remove(item); - } - }, - }); - return csstree.generate(ast); + if ( + csstree.find( + selectorList, + (node: any) => node.type === "TypeSelector" && node.name === "span", + ) && + !csstree.find( + selectorList, + (node: any) => + node.type === "ClassSelector" || node.type === "IdSelector", + ) + ) { + list.remove(item); + } + }, + }); + return csstree.generate(ast); } function parse(style: string, options: Partial = {}) { - // 添加字体 - style = style.replace( - /font-family:([^;]*?);/g, - 'font-family:$1,"PingFang SC", -apple-system, "SF UI Text", "Lucida Grande", STheiti, "Microsoft YaHei", sans-serif;', - ); + // 添加字体 + style = style.replace( + /font-family:([^;]*?);/g, + 'font-family:$1,"PingFang SC", -apple-system, "SF UI Text", "Lucida Grande", STheiti, "Microsoft YaHei", sans-serif;', + ); - if (options.removeFontSizes) { - style = removeAllFontSizes(style); - } + if (options.removeFontSizes) { + style = removeAllFontSizes(style); + } - style = removeTopClassSpanStyle(style); + style = removeTopClassSpanStyle(style); - // remove relative position - const ast1 = csstree.parse(style); - csstree.walk(ast1, { - "visit": "Declaration", - "enter": function (node: any, item: any, list: any) { - // todo: 感觉这里有问题 - // if (node.property === 'position' && node.value.children.size === 1 && node.value.children.first.name === 'relative') { - // list.remove(item) - // } - if ( - "position" === node.property && "Identifier" === node.value.type && - "relative" === node.value.name - ) { - list.remove(item); - } - }, - }); - style = csstree.generate(ast1); + // remove relative position + const ast1 = csstree.parse(style); + csstree.walk(ast1, { + "visit": "Declaration", + "enter": function (node: any, item: any, list: any) { + // todo: 感觉这里有问题 + // if (node.property === 'position' && node.value.children.size === 1 && node.value.children.first.name === 'relative') { + // list.remove(item) + // } + if ( + "position" === node.property && "Identifier" === node.value.type && + "relative" === node.value.name + ) { + list.remove(item); + } + }, + }); + style = csstree.generate(ast1); - // remove code style - const ast2 = csstree.parse(style); - csstree.walk(ast2, { - "visit": "Rule", - "enter": function (node: any, item: any, list: any) { - // todo: 这里也有问题,应该用find才能搜索到 - // if (csstree.find(node.prelude, (node: any) => node.type === 'TypeSelector' && node.name === 'code')) { - // list.remove(item) - // } - if ( - "TypeSelector" === node.prelude.type && "code" === node.prelude.name - ) { - list.remove(item); - } - }, - }); - style = csstree.generate(ast2); + // remove code style + const ast2 = csstree.parse(style); + csstree.walk(ast2, { + "visit": "Rule", + "enter": function (node: any, item: any, list: any) { + // todo: 这里也有问题,应该用find才能搜索到 + // if (csstree.find(node.prelude, (node: any) => node.type === 'TypeSelector' && node.name === 'code')) { + // list.remove(item) + // } + if ( + "TypeSelector" === node.prelude.type && "code" === node.prelude.name + ) { + list.remove(item); + } + }, + }); + style = csstree.generate(ast2); - if (options.enableTranslate) { - style = style.replace(/\.wr-translation\s*?\{(?:\n|.|\r)*?}/g, ""); - } - return style; + if (options.enableTranslate) { + style = style.replace(/\.wr-translation\s*?\{(?:\n|.|\r)*?}/g, ""); + } + return style; } export default { - "parse": parse, - "removeAllFontSizes": removeAllFontSizes, + "parse": parse, + "removeAllFontSizes": removeAllFontSizes, };