Skip to content

Commit

Permalink
feat: support to input userinfo from cli and hardcode PICA_SECRET_KEY
Browse files Browse the repository at this point in the history
  • Loading branch information
justorez committed Feb 21, 2024
1 parent d273153 commit 4a0eaf7
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 52 deletions.
2 changes: 0 additions & 2 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
# 密钥,不要修改
PICA_SECRET_KEY=~d}$Q7$eIni=V)9\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn
# 账号名
PICA_ACCOUNT=
# 账号密码
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ on:
env:
DEBUG: ${{ inputs.DEBUG && 'pica' }}
PICA_IN_GITHUB: true # 用于区分运行环境,不要修改
PICA_SECRET_KEY: ${{ secrets.PICA_SECRET_KEY }}
PICA_ACCOUNT: ${{ secrets.PICA_ACCOUNT }}
PICA_PASSWORD: ${{ secrets.PICA_PASSWORD }}
PICA_DL_CONCURRENCY: ${{ inputs.PICA_DL_CONCURRENCY }}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "pica-cli",
"author": "justorez",
"version": "1.4.1",
"version": "1.5.0",
"description": "😉 哔咔漫画下载器",
"packageManager": "[email protected]",
"type": "module",
Expand Down Expand Up @@ -69,6 +69,7 @@
"devDependencies": {
"@inquirer/checkbox": "^1.5.2",
"@inquirer/input": "^1.2.16",
"@inquirer/password": "^2.0.0",
"@inquirer/select": "^1.3.3",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.1.0",
Expand Down
37 changes: 37 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 10 additions & 14 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@

![演示](https://s2.loli.net/2024/02/01/Qc7L3qGZOWBPmkR.gif)

- 交互式命令行
- 排行榜:下载当前排行榜的全部漫画
- 收藏夹:下载当前用户收藏夹的全部漫画
- 搜索:支持关键字和漫画ID (多个用 # 隔开)。访问哔咔电脑端网站,进入漫画详情,地址栏链接里的 `cid` 就是漫画ID
- 自动过滤已下载的章节和图片,不会重复下载
- 如果没有相关环境变量,则启动交互命令界面;若有则直接执行
- 通过 `pica-zip` 命令分章节批量压缩,配合支持 zip 的漫画阅读软件使用,比如 [Perfect Viewer](https://play.google.com/store/apps/details?id=com.rookiestudio.perfectviewer)。不限于 `pica-cli` 下载的漫画,只要符合 [cmoics/漫画标题/漫画章节/漫画图片](#) 的目录结构即可。
- 按章节批量压缩,配合支持 zip 的漫画阅读软件使用,比如 [Perfect Viewer](https://play.google.com/store/apps/details?id=com.rookiestudio.perfectviewer)。不限于 `pica-cli` 下载的漫画,只要符合 [cmoics/漫画标题/漫画章节/漫画图片](#) 的目录结构即可。
- 借助 github action 实现飞速下载,支持从 github artifact 和 file.io 两种方式下载完整漫画包。file.io 无需注册,无需科学上网,文件保存两周,单文件最大 2GB,注意链接只能下载**一次**,下载后文件会自动删除
- [更新日志](#更新日志)

*一次性不要下载太多漫画,对哔咔服务器造成太多压力终归是不好的*
> *一次性不要下载太多漫画,对哔咔服务器造成太多压力终归是不好的*
如果用的开心,求个 star 支持一下,比心 ~ ❤️

Expand All @@ -29,16 +27,13 @@
利用 github 的免费服务器下载,最关键的是不用科学上网,网速飞快,孩子用了都说好。

```bash
# 必填,固定值,不要修改
# ~d}$Q7$eIni=V)9\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn
PICA_SECRET_KEY
# 必填,账号名
PICA_ACCOUNT
# 必填,账号密码
PICA_PASSWORD
```

fork 一份[本仓库](https://github.com/justorez/pica-cli)将上面三个环境变量,设置为仓库密钥:
fork 一份[本仓库](https://github.com/justorez/pica-cli)将上面两个环境变量,设置为仓库密钥:

![action secret](https://s2.loli.net/2024/01/30/5FxU7olyWC3VAe1.png)

Expand All @@ -64,18 +59,18 @@ pnpm add pica-cli -g
在自己电脑上配置好环境变量,所需的环境变量如下所示:

```bash
# 必填,固定值,不要修改
PICA_SECRET_KEY=~d}$Q7$eIni=V)9\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn
# 必填,账号名
# 账号名
# 若无配置,会提示手动输入
PICA_ACCOUNT=
# 必填,账号密码
# 账号密码
# 若无配置,会提示手动输入
PICA_PASSWORD=
# 代理地址,示例:http://127.0.0.1:7890
PICA_PROXY=
# 下载图片的并发数,默认 5
PICA_DL_CONCURRENCY=5
# leaderboard | favorites | search
# 下载内容,分别表示:排行榜 | 收藏夹 | 搜索
# search | favorites | leaderboard
# 下载内容,分别表示:搜索 | 收藏夹 | 排行榜
PICA_DL_CONTENT=
# 搜索关键字或漫画ID,多个用 # 隔开
# 尽量输入完整漫画名,避免返回过多结果
Expand Down Expand Up @@ -113,6 +108,7 @@ pnpm dev:zip

## 更新日志

- 2024/02/21 支持通过命令行输入账号密码,硬编码密钥
- 2024/02/08 支持下载指定章节
- 2024/02/01 支持通过漫画ID精确下载
- 2024/01/31 github action 同时将漫画包上传到 file.io
Expand Down
59 changes: 40 additions & 19 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,57 @@ import {
selectChapterByInput
} from './utils'
import ora from 'ora'
import input from '@inquirer/input'
import select from '@inquirer/select'
import checkbox from '@inquirer/checkbox'
import Input from '@inquirer/input'
import Password from '@inquirer/password'
import Select from '@inquirer/select'
import Checkbox from '@inquirer/checkbox'
import ProgressBar from 'progress'
import { Comic } from './types'
import pLimit from 'p-limit'
import pico from 'picocolors'

loadEnv()

const keysTip = [
`${pico.cyan('<space>')} 选中`,
`${pico.cyan('<a>')} 全选`,
`${pico.cyan('<i>')} 反选`,
`${pico.cyan('<enter>')} 确认`
]
const checkboxHelpTip = ` (${keysTip.join(', ')})`

async function main() {
const {
PICA_ACCOUNT,
PICA_PASSWORD,
PICA_DL_CONTENT,
PICA_DL_CHAPTER,
PICA_DL_CONCURRENCY,
PICA_IN_GITHUB
} = process.env
const PICA_DL_SEARCH_KEYWORDS = process.env.PICA_DL_SEARCH_KEYWORDS?.trim()

const keysTip = [
`${pico.cyan('<space>')} 选中`,
`${pico.cyan('<a>')} 全选`,
`${pico.cyan('<i>')} 反选`,
`${pico.cyan('<enter>')} 确认`
]
const checkboxHelpTip = ` (${keysTip.join(', ')})`
const account =
PICA_ACCOUNT ||
(await Input({
message: '请输入账户名称',
transformer: (val) => val.trim()
}))
const password =
PICA_PASSWORD ||
(await Password({
message: '请输入账户密码',
mask: true
}))

const spinner = ora('正在登录哔咔').start()
const pica = new Pica()
await pica.login(account, password)
spinner.stop()

const answer =
PICA_DL_CONTENT ||
(await select({
(await Select({
message: '想下载哪些漫画?',
choices: [
{ name: '去搜索', value: 'search' },
Expand All @@ -47,11 +68,6 @@ async function main() {
]
}))

const spinner = ora('正在登录哔咔').start()
const pica = new Pica()
await pica.login()
spinner.stop()

const comics: Comic[] = []
if (answer === 'leaderboard') {
const res = await pica.leaderboard()
Expand All @@ -73,7 +89,7 @@ async function main() {

const inputStr =
PICA_DL_SEARCH_KEYWORDS ||
(await input({
(await Input({
message: '请输入关键字或者漫画ID (多个用 # 隔开)',
transformer: (val) => val.trim()
}))
Expand Down Expand Up @@ -111,7 +127,7 @@ async function main() {

const selected = PICA_DL_SEARCH_KEYWORDS
? searchRes
: await checkbox({
: await Checkbox({
message: '请选择要下载的漫画',
pageSize: 10,
loop: false,
Expand All @@ -127,6 +143,11 @@ async function main() {
}
}

if (comics.length === 0) {
log.log('没有找到相应的漫画')
return
}

for (const comic of comics) {
const title = comic.title.trim()
const cid = comic._id
Expand All @@ -146,7 +167,7 @@ async function main() {
? selectChapterByInput(PICA_DL_CHAPTER, episodes)
: PICA_IN_GITHUB
? episodes
: await checkbox({
: await Checkbox({
message: '请选择要下载的章节',
pageSize: 10,
instructions: checkboxHelpTip,
Expand Down
21 changes: 12 additions & 9 deletions src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import {
Favorites
} from './types'

const PICA_SECRET_KEY =
process.env.PICA_SECRET_KEY ||
'~d}$Q7$eIni=V)9\\RK/P.RM4;9[7|@/CA}b~OW!3?EV`:<>M7pddUBL5n|0/*Cn'

export class Pica {
Order = {
default: 'ua', // 默认
Expand Down Expand Up @@ -48,10 +52,7 @@ export class Pica {
const timestamp = String(Date.now()).slice(0, -3)
const raw =
url + timestamp + headers.nonce + method + headers['api-key']
const hmac = createHmac(
'sha256',
process.env.PICA_SECRET_KEY as string
)
const hmac = createHmac('sha256', PICA_SECRET_KEY)
hmac.update(raw.toLowerCase())
headers.signature = hmac.digest('hex')
headers.time = timestamp
Expand All @@ -74,7 +75,7 @@ export class Pica {
return res
}

debug('%s %O', url, result)
debug('\n%s %O', url, result)

if (result.code != 200) {
throw new Error('请求失败')
Expand All @@ -93,16 +94,18 @@ export class Pica {
this.retryMap.delete(url)
}

debug('error %s %s %O', url, message, error.response?.data)
debug('\nerror %s %s %O', url, message, error.response?.data)
return Promise.reject(message)
}
)
}

async login() {
async login(account: string, password: string) {
debug('\n%s %s', account, password)

const res = await this.request<string>('post', 'auth/sign-in', {
email: process.env.PICA_ACCOUNT,
password: process.env.PICA_PASSWORD
email: account,
password: password
}).catch((err) => {
debug('\n登录异常 %s', err)
throw new Error('登录失败,请检查账号/密码/网络环境')
Expand Down
11 changes: 5 additions & 6 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,15 @@ export function normalizeName(s: string) {
.replace(/:/g, '-')
}

type LogMsg = string[] | number[]
// √ ✕
export const log = {
log: (...msg: LogMsg) => console.log(...msg),
info: (...msg: LogMsg) => console.log(pico.cyan('➡️'), ...msg),
warn: (...msg: LogMsg) =>
log: (...msg: unknown[]) => console.log(...msg),
info: (...msg: unknown[]) => console.log(pico.cyan('➡️'), ...msg),
warn: (...msg: unknown[]) =>
console.log(pico.yellow(`${figures.warning} ${msg.join(' ')}`)),
error: (...msg: LogMsg) =>
error: (...msg: unknown[]) =>
console.log(pico.red(`${figures.cross} ${msg.join(' ')}`)),
success: (...msg: LogMsg) =>
success: (...msg: unknown[]) =>
console.log(pico.green(`${figures.tick} ${msg.join(' ')}`))
}

Expand Down

0 comments on commit 4a0eaf7

Please sign in to comment.