Skip to content

Commit

Permalink
feat: 下载进度条
Browse files Browse the repository at this point in the history
  • Loading branch information
sj817 committed Dec 9, 2024
1 parent 0203fd5 commit ecadea5
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ package-lock.json

test.js
test.ts
image.png
14 changes: 13 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
"type": "git",
"url": "git+https://github.com/KarinJS/puppeteer-core.git"
},
"exports": {
".": {
"import": "./lib/index.js",
"types": "./lib/index.d.ts"
},
"./puppeteer-core": {
"import": "./lib/puppeteer.js",
"types": "./lib/puppeteer.d.ts"
}
},
"license": "MIT",
"author": "shijin",
"type": "module",
Expand All @@ -33,11 +43,13 @@
},
"dependencies": {
"decompress": "4.2.1",
"puppeteer-core": "23.6.1"
"progress": "^2.0.3",
"puppeteer-core": "23.10.1"
},
"devDependencies": {
"@types/decompress": "^4.2.7",
"@types/node": "20.14.2",
"@types/progress": "^2.0.7",
"eslint": "latest",
"neostandard": "latest",
"sort-package-json": "2.10.0",
Expand Down
43 changes: 42 additions & 1 deletion src/common/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import path from 'path'
import https from 'https'
import { promisify } from 'util'
import { pipeline } from 'stream'
import ProgressBar from 'progress'
import decompress from 'decompress'
import { fileURLToPath } from 'url'
import { exec as execCmd, ExecOptions } from 'child_process'
import { EventEmitter } from 'events'
import { exec as execCmd, ExecOptions } from 'child_process'

const streamPipeline = promisify(pipeline)

Expand Down Expand Up @@ -113,6 +114,46 @@ export class Common extends EventEmitter {
return
}

/** 计算下载进度 */
const calculateProgress = (downloadedSize: number, total: number, startTime: number) => {
/** 耗时 */
const elapsedTime = (Date.now() - startTime) / 1000
/** 当前已下载 */
const data = downloadedSize / (1024 * 1024)
/** 下载速度 */
const speed = (data / elapsedTime).toFixed(2)
/** 总大小 */
const size = (total / (1024 * 1024)).toFixed(2)
/** 已过去时间 */
const time = Math.floor(elapsedTime)

return { speed, size, time, data: data.toFixed(2) }
}

/** 文件总大小 */
const total = Number(res.headers['content-length'] || '0')
let downloadedSize = 0
const startTime = Date.now()

/** 进度条 */
const progressBar = new ProgressBar('🚀 下载进度 [:bar] :percent :data/:size MB | :speed MB/s :times', {
total,
width: 30,
complete: '=',
incomplete: ' ',
})

/** 更新下载进度条 */
res.on('data', (chunk) => {
downloadedSize += chunk.length
const options = calculateProgress(downloadedSize, total, startTime)
progressBar.tick(chunk.length, options)
})

res.on('end', () => {
console.log('\n')
})

const fileStream = fs.createWriteStream(file)
streamPipeline(res, fileStream)
.then(() => resolve(true))
Expand Down
2 changes: 2 additions & 0 deletions src/puppeteer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from 'puppeteer-core'
export { default } from 'puppeteer-core'
6 changes: 3 additions & 3 deletions src/puppeteer/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { common } from '@Common'
import { ChildProcess } from 'child_process'
import puppeteer, { Browser, GoToOptions, HTTPRequest, Page, PuppeteerLaunchOptions, ScreenshotOptions } from 'puppeteer-core'
import puppeteer, { Browser, GoToOptions, HTTPRequest, Page, LaunchOptions, ScreenshotOptions } from 'puppeteer-core'

export interface screenshot extends ScreenshotOptions {
/** http地址或本地文件路径 */
Expand Down Expand Up @@ -91,14 +91,14 @@ export class Render {
/** 浏览器id */
id: number
/** 浏览器启动配置 */
config: PuppeteerLaunchOptions
config: LaunchOptions
/** 浏览器实例 */
browser!: Browser
/** 截图队列 存放每个任务的唯一标识 */
list: Map<string, any>
/** 浏览器进程 */
process!: ChildProcess | null
constructor (id: number, config: PuppeteerLaunchOptions) {
constructor (id: number, config: LaunchOptions) {
this.id = id
this.config = config
this.list = new Map()
Expand Down
19 changes: 13 additions & 6 deletions src/puppeteer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import crypto from 'crypto'
import InitChrome from './init'
import { common } from '@Common'
import { Render, RenderResult, screenshot } from './core'
import { PuppeteerLaunchOptions } from 'puppeteer-core'
import { PUPPETEER_REVISIONS } from 'puppeteer-core/lib/cjs/puppeteer/revisions.js'
import { LaunchOptions } from 'puppeteer-core'
import { PUPPETEER_REVISIONS } from 'puppeteer-core/internal/revisions.js'

export interface RunConfig extends PuppeteerLaunchOptions {
export interface RunConfig extends LaunchOptions {
/**
* 启动浏览器数量
* @default 1
Expand All @@ -31,6 +31,11 @@ export interface RunConfig extends PuppeteerLaunchOptions {
* 通过管道而不是 WebSocket 连接到浏览器。在大多数情况下,这将导致更快的页面加载。
*/
pipe?: boolean
/**
* 需要使用的浏览器标识
* @default 'chrome-headless-shell'
*/
chrome?: 'chrome-headless-shell' | 'chrome'
}

/**
Expand All @@ -44,14 +49,15 @@ export class Puppeteer {
/** 实例管理器配置 初始化的时候传递 */
config: RunConfig
/** 启动浏览器的参数 初始化后才产生 */
browserOptions: PuppeteerLaunchOptions
browserOptions: LaunchOptions
constructor (config?: RunConfig) {
this.index = 0
this.list = []
this.config = config || {
pipe: true,
headless: true,
devtools: false,
chrome: 'chrome',
args: [
'--enable-gpu',
'--no-sandbox',
Expand All @@ -62,6 +68,7 @@ export class Puppeteer {
],
}
this.browserOptions = this.config
if (!this.config.chrome) this.config.chrome = 'chrome'
}

async init () {
Expand All @@ -70,8 +77,8 @@ export class Puppeteer {

/** 浏览器执行路径 */
if (!this.config?.executablePath) {
const version = PUPPETEER_REVISIONS['chrome-headless-shell']
const init = new InitChrome(version)
const version = PUPPETEER_REVISIONS[this.config.chrome!]
const init = new InitChrome(version, this.config.chrome!)
const executablePath = await init.init()
this.browserOptions.executablePath = executablePath
}
Expand Down
24 changes: 14 additions & 10 deletions src/puppeteer/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@ export const enum ChromeUrl {
}

export default class InitChrome {
/**
* @param version - 传入下载的chrome版本
*/
/** 版本 */
version: string
/** 操作系统标识符 */
platform: Platform
/** chrome信息 */
info: Info
constructor (version: string) {
/** browser标识 暂不支持firefox */
browser: string
constructor (version: string, headless: 'chrome-headless-shell' | 'chrome') {
this.browser = headless
this.version = version
/** 获取系统版本 */
this.platform = common.Platform()
this.info = this.GetInfo()
}
Expand All @@ -53,6 +55,8 @@ export default class InitChrome {
if (common.exists(this.info.chrome)) {
console.info(`[chrome] ${this.info.chrome}`)
return this.info.chrome
} else {
console.info('[chrome][init] 未找到chrome,开始下载')
}

/** 下载chrome */
Expand Down Expand Up @@ -193,7 +197,7 @@ export default class InitChrome {
async GetDownloadUrl (host: ChromeUrl = ChromeUrl.Cnpm): Promise<string> {
try {
/** 组合url */
const url = `${host}/${this.version}/${this.platform}/chrome-headless-shell-${this.platform}.zip`
const url = `${host}/${this.version}/${this.platform}/${this.browser}-${this.platform}.zip`
console.info(`[chrome][init] 获取下载地址完成:${url}`)
return url
} catch (e) {
Expand All @@ -219,19 +223,19 @@ export default class InitChrome {
/** 是否为windows */
const isWin = os.platform() === 'win32'
/** 缓存目录 */
const cache = path.join(os.homedir(), '.cache', 'puppeteer', 'chrome-headless-shell')
const cache = path.join(os.homedir(), '.cache', 'puppeteer', this.browser)
/** 版本 */
const version = `${platform}-${this.version}`
/** 存放实际 Chrome 可执行文件的目录 */
const dir = path.join(cache, version)
/** 下载后压缩包的存放路径 */
const zip = path.join(dir, `chrome-headless-shell-${platform}.zip`)
const zip = path.join(dir, `${this.browser}-${platform}.zip`)
/** 解压路径 */
const chromeDir = dir
/** chrome二进制路径 */
const chrome = path.join(chromeDir, `chrome-headless-shell-${platform}`, `chrome-headless-shell${isWin ? '.exe' : ''}`)
const chrome = path.join(chromeDir, `${this.browser}-${platform}`, `${this.browser}${isWin ? '.exe' : ''}`)

// tips: 压缩包解压后会带一个文件夹: chrome-headless-shell-${platform}
// tips: 压缩包解压后会带一个文件夹: ${this.browser}-${platform}
return {
isWin,
platform,
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"target": "ES2022",
"baseUrl": "./",
"outDir": "./lib",
"moduleResolution": "node",
"moduleResolution": "bundler",
"module": "ES2022",
"paths": {
"@Common": [
Expand Down

0 comments on commit ecadea5

Please sign in to comment.