commit b873cc2430b5c007434cf046cfef4d3af45ecd19 Author: npmrun <154946975@qq.com> Date: Thu Jun 4 00:19:31 2026 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9b1ee42 --- /dev/null +++ b/.gitignore @@ -0,0 +1,175 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..64886e3 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# pic + +To install dependencies: + +```bash +bun install +``` + +To run: + +```bash +bun run index.ts +``` + +This project was created using `bun init` in bun v1.1.18. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/backup-file/index copy.ts b/backup-file/index copy.ts new file mode 100644 index 0000000..01e5aa5 --- /dev/null +++ b/backup-file/index copy.ts @@ -0,0 +1,53 @@ +import { IncomingMessage } from "http" +import { fetch } from "bun" +import https from "https" +import fs from "fs" + +const maxNum = 3 +function request(opts: any, cb: any, num = 0) { + https.get(opts, function (res: IncomingMessage) { + if (res.statusCode === 302) { + if (num > maxNum) { + console.error("重定向次数超过三次,已强制终止"); + return + } + let url = new URL(res.headers['location']!) + if (url) { + console.log(`重定向:`, url.href); + num++ + // 重定向 + request({ + ...opts, + hostname: url.hostname, + path: url.pathname + url.search, + }, cb, num) + } + } else if (res.statusCode === 200) { + cb && cb(res) + } else { + console.log(`当前${opts.hostname}请求${opts.path}未成功`, res.statusCode); + // res.on('data', (d) => { + // process.stdout.write(d); + // }); + } + }) +} + +// 会重定向,需要想重定向请求 +request({ + hostname: "api.zzzmh.cn", + path: "/v2/bz/v3/getUrl/1b87e2c5880511ebb6edd017c2d2eca211", + headers: { + 'Accept': '*/*', + 'Accept-Encoding': 'gzip, deflate', + // "User-Agent": getRandomUserAgent(), + // 'Connection': 'keep-alive', + 'Referer': 'https://bz.zzzmh.cn/' + } +}, function (res: IncomingMessage) { + const write = fs.createWriteStream("./a.jpg") + res.pipe(write) + write.on("error", function (err) { + console.log(err) + }) +}) diff --git a/backup-file/index.ts b/backup-file/index.ts new file mode 100644 index 0000000..70c8248 --- /dev/null +++ b/backup-file/index.ts @@ -0,0 +1,111 @@ +import { fetch } from "bun" +import fs from "node:fs" +import * as cheerio from "cheerio" + +// https://bz.zzzmh.cn/index + +// const stream = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getUrl/1b87e2c5880511ebb6edd017c2d2eca211")).arrayBuffer() +// const stream = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getUrl/393204c88fff4715a4b4aa88aabdb2ed21")).arrayBuffer() +// fs.writeFileSync("./a.png", Buffer.from(stream!)) + +let totalPage = 1 +async function downImageByPage(current: number) { + const res = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getData", { + method: "POST", + headers: { + 'Content-Type': 'application/json;charset=utf-8', + referer: "https://bz.zzzmh.cn/" + }, + body: `{ "size": 24, "current": ${current}, "sort": 0, "category": 0, "resolution": 0, "color": 0, "categoryId": 0, "ratio": 0 }` + })).json() + totalPage = res.data.totalPage + for (let i = 0; i < res.data.list.length; i++) { + const item = res.data.list[i]; + console.log(`正在下载第${i + 1}张图片`); + await (() => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(1) + }, Math.random() * 2000 + 500); + }) + })(); + const stream = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getUrl/" + item.i + (item.t == 2 ? "21" : "11"))).arrayBuffer() + const p = "./dist/" + "page-" + current + "/" + item.i + ".png" + if (!await checkExist("./dist/" + "page-" + current)) { + fs.mkdirSync("./dist/" + "page-" + current, { recursive: true }) + } + const isExist = await checkExist(p) + if (!isExist) { + fs.writeFileSync(p, Buffer.from(stream!), { flag: "w" }) + } else { + console.log("文件已存在,跳过下载", item.i + ".png"); + } + } +} + +downImageByPage(2) + +function checkExist(path: string) { + return new Promise((resolve, reject) => { + fs.access(path, fs.constants.F_OK, (err) => { + if (err) { + resolve(false) + } else { + resolve(true) + } + }) + }) +} + +// async function readAllChunks(readableStream: any) { +// const reader = readableStream.getReader(); +// const chunks = []; + +// let done, value; +// while (!done) { +// ({ value, done } = await reader.read()); +// if (done) { +// return chunks; +// } +// chunks.push(value); +// } +// } +// const rr = await readAllChunks(stream) +// fs.writeFileSync("./a.png", Buffer.from(rr!)) + +// const maxNum = 3 +// function request(opts: any, cb: any, num = 0) { +// https.get(opts, function (res: IncomingMessage) { +// if (res.statusCode === 302) { +// if (num > maxNum) { +// console.error("重定向次数超过三次,已强制终止"); +// return +// } +// let url = new URL(res.headers['location']!) +// if (url) { +// console.log(`重定向:`, url.href); +// num++ +// // 重定向 +// request({ +// ...opts, +// hostname: url.hostname, +// path: url.pathname + url.search, +// }, cb, num) +// } +// } else if (res.statusCode === 200) { +// cb && cb(res) +// } else { +// console.log(`当前${opts.hostname}请求${opts.path}未成功`, res.statusCode); +// // res.on('data', (d) => { +// // process.stdout.write(d); +// // }); +// } +// }) +// } + +// fetch("https://bz.zzzmh.cn/index") +// .then((res) => res.text()) +// .then((html) => { +// const $ = cheerio.load(html) +// console.log($("title").text()); +// }); \ No newline at end of file diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000..5280b3e Binary files /dev/null and b/bun.lockb differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..d5d6f61 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "pic", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@types/node": "^22.7.9", + "cheerio": "^1.0.0" + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..238655f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + } +} diff --git a/wallhaven/index.ts b/wallhaven/index.ts new file mode 100644 index 0000000..ff9b59d --- /dev/null +++ b/wallhaven/index.ts @@ -0,0 +1,64 @@ +import { fetch } from "bun"; +import * as cheerio from "cheerio" +import fs from "node:fs"; +import path from "node:path"; + +const output = path.resolve(__dirname, "../dist/wallhaven") + +async function downImageByPage(page: number) { + const html = await (await fetch("https://wallhaven.cc/search?categories=110&purity=100&topRange=1M&sorting=toplist&order=desc&ai_art_filter=1&page=" + page, { + method: "GET" + })).text() + + const $ = cheerio.load(html); + + const previewList: string[] = [] + + $("#thumbs > section > ul > li > figure > a").each((index, el) => { + previewList[index] = $(el).attr("href") as string + }); + + for (let i = 0; i < previewList.length; i++) { + const previewURL = previewList[i]; + console.log(`正在下载第${i + 1}张图片`); + await (() => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(1) + }, Math.random() * 2000 + 500); + }) + })(); + const html = await (await fetch(previewURL, { + method: "GET" + })).text() + const $ = cheerio.load(html); + const imageURL = $("#wallpaper").attr("src") as string + const p = path.resolve(output, "page-" + page + "/" + imageURL.split('/').slice(-1).join('')) + console.log("图片地址:", imageURL); + console.log("图片保存地址:", p); + if (!await checkExist(path.resolve(output, "page-" + page))) { + fs.mkdirSync(path.resolve(output, "page-" + page), { recursive: true }) + } + const isExist = await checkExist(p) + if (!isExist) { + const stream = await (await fetch(imageURL)).arrayBuffer() + fs.writeFileSync(p, Buffer.from(stream!), { flag: "w" }) + } else { + console.log("文件已存在,跳过下载", imageURL); + } + } +} + +function checkExist(path: string) { + return new Promise((resolve, reject) => { + fs.access(path, fs.constants.F_OK, (err) => { + if (err) { + resolve(false) + } else { + resolve(true) + } + }) + }) +} + +downImageByPage(1) diff --git a/zzzmh/index.ts b/zzzmh/index.ts new file mode 100644 index 0000000..6405437 --- /dev/null +++ b/zzzmh/index.ts @@ -0,0 +1,54 @@ +import { fetch } from "bun" +import fs from "node:fs" +import path from "node:path" + +const output = path.resolve(__dirname, "../dist/zzzmh") + +let totalPage = 1 +async function downImageByPage(current: number) { + const res = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getData", { + method: "POST", + headers: { + 'Content-Type': 'application/json;charset=utf-8', + referer: "https://bz.zzzmh.cn/" + }, + body: `{ "size": 24, "current": ${current}, "sort": 0, "category": 0, "resolution": 0, "color": 0, "categoryId": 0, "ratio": 0 }` + })).json() + totalPage = res.data.totalPage + for (let i = 0; i < res.data.list.length; i++) { + const item = res.data.list[i]; + console.log(`正在下载第${i + 1}张图片`); + await (() => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(1) + }, Math.random() * 2000 + 500); + }) + })(); + const stream = await (await fetch("https://api.zzzmh.cn/v2/bz/v3/getUrl/" + item.i + (item.t == 2 ? "21" : "11"))).arrayBuffer() + const p = path.resolve(output, "page-" + current + "/" + item.i + ".png") + if (!await checkExist(path.resolve(output, "page-" + current))) { + fs.mkdirSync(path.resolve(output, "page-" + current), { recursive: true }) + } + const isExist = await checkExist(p) + if (!isExist) { + fs.writeFileSync(p, Buffer.from(stream!), { flag: "w" }) + } else { + console.log("文件已存在,跳过下载", item.i + ".png"); + } + } +} + +function checkExist(path: string) { + return new Promise((resolve, reject) => { + fs.access(path, fs.constants.F_OK, (err) => { + if (err) { + resolve(false) + } else { + resolve(true) + } + }) + }) +} + +downImageByPage(2) \ No newline at end of file