From 26d4e22cf30ec8d01838064a2ef9f3257d6274ed Mon Sep 17 00:00:00 2001
From: zhiyu <542716863@qq.com>
Date: Wed, 31 Jan 2024 14:39:33 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20=E6=9B=B4=E6=8D=A2=E6=B0=B4?=
=?UTF-8?q?=E5=8D=B0=E7=9A=84xhs=E8=A7=A3=E6=9E=90=E4=B8=BA=E6=97=A0?=
=?UTF-8?q?=E6=B0=B4=E5=8D=B0=E7=9A=84xhs=E8=A7=A3=E6=9E=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
1. 删除有水印的xhs解析中的CK冗余请求
2. 新增更换有水印的xhs解析为无水印的xhs解析
---
apps/tools.js | 67 +++++++++++++++++++++++--------------------
config/version.yaml | 3 +-
constants/constant.js | 21 +++++++++++++-
constants/xhs.js | 5 ++++
4 files changed, 63 insertions(+), 33 deletions(-)
create mode 100644 constants/xhs.js
diff --git a/apps/tools.js b/apps/tools.js
index 28f6386..fb67227 100644
--- a/apps/tools.js
+++ b/apps/tools.js
@@ -5,15 +5,14 @@ import fs from "node:fs";
import axios from "axios";
import _ from "lodash";
import tunnel from "tunnel";
-import HttpProxyAgent, { HttpsProxyAgent} from "https-proxy-agent";
+import HttpProxyAgent, { HttpsProxyAgent } from "https-proxy-agent";
import { mkdirIfNotExists, checkAndRemoveFile, deleteFolderRecursive } from "../utils/file.js";
import { downloadBFile, getAudioUrl, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js";
import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js";
import {
transMap,
douyinTypeMap,
- XHS_CK,
- RESTRICTION_DESCRIPTION,
+ RESTRICTION_DESCRIPTION, XHS_NO_WATERMARK_HEADER,
} from "../constants/constant.js";
import { formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js";
import config from "../model/index.js";
@@ -26,6 +25,7 @@ import querystring from "querystring";
import TokenBucket from "../utils/token-bucket.js";
import { getWbi } from "../utils/biliWbi.js";
import { BILI_SUMMARY } from "../constants/bili.js";
+import { XHS_VIDEO } from "../constants/xhs.js";
export class tools extends plugin {
constructor() {
@@ -65,7 +65,7 @@ export class tools extends plugin {
},
{
reg: "(xhslink.com|xiaohongshu.com)",
- fnc: "redbook",
+ fnc: "xhs",
},
{
reg: "(instagram.com)",
@@ -246,17 +246,17 @@ export class tools extends plugin {
// API链接
const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${ tiktokVideoId }`;
await fetch(API_URL, {
- headers: {
- "User-Agent":
- "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
- "Content-Type": "application/json",
- "Accept-Encoding": "gzip,deflate,compress",
- },
- // redirect: "follow",
- follow: 10,
- timeout: 10000,
- agent: new HttpsProxyAgent(this.myProxy),
- })
+ headers: {
+ "User-Agent":
+ "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Mobile Safari/537.36",
+ "Content-Type": "application/json",
+ "Accept-Encoding": "gzip,deflate,compress",
+ },
+ // redirect: "follow",
+ follow: 10,
+ timeout: 10000,
+ agent: new HttpsProxyAgent(this.myProxy),
+ })
.then(async resp => {
const respJson = await resp.json();
const data = respJson.aweme_list[0];
@@ -593,7 +593,7 @@ export class tools extends plugin {
}
// 小红书解析
- async redbook(e) {
+ async xhs(e) {
// 正则说明:匹配手机链接、匹配小程序、匹配PC链接
let msgUrl =
/(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec(
@@ -622,30 +622,35 @@ export class tools extends plugin {
}
const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 获取信息
- fetch(`https://www.xiaohongshu.com/discovery/item/${ id }`, {
- headers: {
- "user-agent":
- "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/110.0.0.0",
- cookie: Buffer.from(XHS_CK, "base64").toString("utf-8"),
- },
+ fetch(`https://www.xiaohongshu.com/explore/${ id }`, {
+ headers: XHS_NO_WATERMARK_HEADER,
}).then(async resp => {
const xhsHtml = await resp.text();
- const reg = /window.__INITIAL_STATE__=(.*?)<\/script>/;
- const resJson = xhsHtml.match(reg)[0];
- const res = JSON.parse(resJson.match(reg)[1]);
- const noteData = res.noteData.data.noteData;
+ const reg = /window\.__INITIAL_STATE__=(.*?)<\/script>/;
+ const res = xhsHtml.match(reg)[1].replace(/undefined/g, "null");
+ const resJson = JSON.parse(res);
+ const noteData = resJson.note.noteDetailMap[id].note
const { title, desc, type } = noteData;
- e.reply(`识别:小红书, ${ title }\n${ desc }`);
let imgPromise = [];
if (type === "video") {
- const url = noteData.video.url;
- this.downloadVideo(url).then(path => {
+ // 封面
+ const cover = noteData.imageList?.[0].urlDefault;
+ e.reply([segment.image(cover), `识别:小红书, ${ title }\n${ desc }`]);
+ // 构造xhs视频链接
+ const xhsVideoUrl = `${ XHS_VIDEO }${ noteData.video.consumer.originVideoKey.replace('pre_post\/', '') }`;
+ // 下载视频
+ this.downloadVideo(xhsVideoUrl).then(path => {
+ if (path === undefined) {
+ // 创建文件,如果不存在
+ path = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }/`;
+ }
e.reply(segment.video(path + "/temp.mp4"));
});
return true;
} else if (type === "normal") {
+ e.reply(`识别:小红书, ${ title }\n${ desc }`);
noteData.imageList.map(async (item, index) => {
- imgPromise.push(this.downloadImg(item.url, downloadPath, index.toString()));
+ imgPromise.push(this.downloadImg(item.urlDefault, downloadPath, index.toString()));
});
}
const paths = await Promise.all(imgPromise);
@@ -1045,7 +1050,7 @@ export class tools extends plugin {
writer.on("error", reject);
});
} catch (err) {
- logger.error("下载视频发生错误!");
+ logger.error(`下载视频发生错误!\ninfo:${err}`);
}
}
diff --git a/config/version.yaml b/config/version.yaml
index a1a693d..ad77098 100644
--- a/config/version.yaml
+++ b/config/version.yaml
@@ -1,7 +1,8 @@
- {
- version: 1.2.2,
+ version: 1.2.3,
data:
[
+ 新增小红书无水印下载功能,
新增哔哩哔哩官方AI总结功能,
新增哔哩哔哩音乐提取功能,
新增快手解析功能,
diff --git a/constants/constant.js b/constants/constant.js
index 88bde22..94b85b3 100644
--- a/constants/constant.js
+++ b/constants/constant.js
@@ -38,6 +38,25 @@ export const TEN_THOUSAND = 10000;
export const CAT_LIMIT = 10;
-export const XHS_CK = 'eGhzVHJhY2tlcklkPTczODhhYmY2LTI0MDgtNGU5YS04MTUyLTE0MGVhOGY1MTQ5ZjsgeGhzVHJhY2tlcklkLnNpZz1UcGUxTkNaX3B3UkFYdG01SVJmVEs0SWUxM0xBaGZuNmNZU2N4Vi1JYWxFOyBhMT0xODY2ZDkwMDM0NmI2NmppcjMzcGpxZ2MwM3JvcG1mczAydXMxdWNoeDEwMDAwMTM1MDUzOyB3ZWJJZD1mMTNkOGJkYjhiZGM3ZGE0MzY0NjA4NWJjYzQ1MDQ1YTsgZ2lkPXlZS0tmajg4SzA4MnlZS0tmajg4cUo3UzRLREtLVjNGcXFVVjd4Q0FrUzhxRk15OGxVNmlNeTg4OHlxMjgycThmMlk0UzAySjsgZ2lkLnNpZ249YlpzcFFzSUxEUmN5akZLQmN2L1FMWVhkU3lvPTsgd2ViX3Nlc3Npb249MDMwMDM3YTRjMDQyYjE1ZTVjMTg4OTUwOGIyNDRhZDExM2UwNTM7IHhoc1RyYWNrZXI9dXJsPW5vdGVEZXRhaWwmeGhzc2hhcmU9V2VpeGluU2Vzc2lvbjsgeGhzVHJhY2tlci5zaWc9YzdmcDVRclk2SGNvVERhUzluX2N3Z2RCRHh2MFZmWnpSU1NTcnlzbG5lQTsgZXh0cmFfZXhwX2lkcz1oNV8yMzAyMDExX29yaWdpbixoNV8xMjA4X2NsdCxoNV8xMTMwX2NsdCxpb3Nfd3hfbGF1bmNoX29wZW5fYXBwX2V4cCxoNV92aWRlb191aV9leHAzLHd4X2xhdW5jaF9vcGVuX2FwcF9kdXJhdGlvbl9vcmlnaW4scXVlc19jbHQyOyBleHRyYV9leHBfaWRzLnNpZz1DVUdrR3NYT3lBZmpVSXkyVGo3SjN4YmRNakFfSnpoR1JkYWd6cVlkbmJnOyB3ZWJCdWlsZD0xLjEuMjE7IHhzZWNhcHBpZD14aHMtcGMtd2ViOyB3ZWJzZWN0aWdhPTU5ZDNlZjFlNjBjNGFhMzdhN2RmM2MyMzQ2N2JkNDZkN2YxZGEwYjE5MThjZjMzNWVlN2YyZTllNTJhYzA0Y2Y7IHNlY19wb2lzb25faWQ9MTI0OTE1NWQtOWU5ZS00MzkyLTg2NTgtNTA1Yzc0YTUzMTM1'
+/**
+ * 有水印的头请求
+ * @type {{cookie: string, "User-Agent": string, accept: string}}
+ */
+export const XHS_WATERMARK_HEADER = {
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
+ 'cookie': '',
+ 'User-Agent':
+ "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1 Edg/110.0.0.0",
+}
+
+/**
+ * 无水印的头请求
+ * @type {{cookie: string, "User-Agent": string, accept: string}}
+ */
+export const XHS_NO_WATERMARK_HEADER = {
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 ',
+ 'cookie': '',
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 UBrowser/6.2.4098.3 Safari/537.36',
+}
export const RESTRICTION_DESCRIPTION = "\n-----------------------限制说明-----------------------"
\ No newline at end of file
diff --git a/constants/xhs.js b/constants/xhs.js
new file mode 100644
index 0000000..5a305c0
--- /dev/null
+++ b/constants/xhs.js
@@ -0,0 +1,5 @@
+/**
+ * 视频请求链接CDN
+ * @type {string}
+ */
+export const XHS_VIDEO = "http://sns-video-bd.xhscdn.com/"
\ No newline at end of file