feat: 更换水印的xhs解析为无水印的xhs解析

1. 删除有水印的xhs解析中的CK冗余请求
2. 新增更换有水印的xhs解析为无水印的xhs解析
This commit is contained in:
zhiyu 2024-01-31 14:39:33 +08:00
parent b6a167c7dd
commit 26d4e22cf3
4 changed files with 63 additions and 33 deletions

View File

@ -5,15 +5,14 @@ import fs from "node:fs";
import axios from "axios"; import axios from "axios";
import _ from "lodash"; import _ from "lodash";
import tunnel from "tunnel"; 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 { mkdirIfNotExists, checkAndRemoveFile, deleteFolderRecursive } from "../utils/file.js";
import { downloadBFile, getAudioUrl, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js"; import { downloadBFile, getAudioUrl, getDownloadUrl, mergeFileToMp4 } from "../utils/bilibili.js";
import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js"; import { parseUrl, parseM3u8, downloadM3u8Videos, mergeAcFileToMp4 } from "../utils/acfun.js";
import { import {
transMap, transMap,
douyinTypeMap, douyinTypeMap,
XHS_CK, RESTRICTION_DESCRIPTION, XHS_NO_WATERMARK_HEADER,
RESTRICTION_DESCRIPTION,
} from "../constants/constant.js"; } from "../constants/constant.js";
import { formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js"; import { formatBiliInfo, getIdVideo, secondsToTime } from "../utils/common.js";
import config from "../model/index.js"; import config from "../model/index.js";
@ -26,6 +25,7 @@ import querystring from "querystring";
import TokenBucket from "../utils/token-bucket.js"; import TokenBucket from "../utils/token-bucket.js";
import { getWbi } from "../utils/biliWbi.js"; import { getWbi } from "../utils/biliWbi.js";
import { BILI_SUMMARY } from "../constants/bili.js"; import { BILI_SUMMARY } from "../constants/bili.js";
import { XHS_VIDEO } from "../constants/xhs.js";
export class tools extends plugin { export class tools extends plugin {
constructor() { constructor() {
@ -65,7 +65,7 @@ export class tools extends plugin {
}, },
{ {
reg: "(xhslink.com|xiaohongshu.com)", reg: "(xhslink.com|xiaohongshu.com)",
fnc: "redbook", fnc: "xhs",
}, },
{ {
reg: "(instagram.com)", reg: "(instagram.com)",
@ -246,17 +246,17 @@ export class tools extends plugin {
// API链接 // API链接
const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${ tiktokVideoId }`; const API_URL = `https://api16-normal-c-useast1a.tiktokv.com/aweme/v1/feed/?aweme_id=${ tiktokVideoId }`;
await fetch(API_URL, { await fetch(API_URL, {
headers: { headers: {
"User-Agent": "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", "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", "Content-Type": "application/json",
"Accept-Encoding": "gzip,deflate,compress", "Accept-Encoding": "gzip,deflate,compress",
}, },
// redirect: "follow", // redirect: "follow",
follow: 10, follow: 10,
timeout: 10000, timeout: 10000,
agent: new HttpsProxyAgent(this.myProxy), agent: new HttpsProxyAgent(this.myProxy),
}) })
.then(async resp => { .then(async resp => {
const respJson = await resp.json(); const respJson = await resp.json();
const data = respJson.aweme_list[0]; const data = respJson.aweme_list[0];
@ -593,7 +593,7 @@ export class tools extends plugin {
} }
// 小红书解析 // 小红书解析
async redbook(e) { async xhs(e) {
// 正则说明匹配手机链接、匹配小程序、匹配PC链接 // 正则说明匹配手机链接、匹配小程序、匹配PC链接
let msgUrl = let msgUrl =
/(http:|https:)\/\/(xhslink|xiaohongshu).com\/[A-Za-z\d._?%&+\-=\/#@]*/.exec( /(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 }`; const downloadPath = `${ this.defaultPath }${ this.e.group_id || this.e.user_id }`;
// 获取信息 // 获取信息
fetch(`https://www.xiaohongshu.com/discovery/item/${ id }`, { fetch(`https://www.xiaohongshu.com/explore/${ id }`, {
headers: { headers: XHS_NO_WATERMARK_HEADER,
"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"),
},
}).then(async resp => { }).then(async resp => {
const xhsHtml = await resp.text(); const xhsHtml = await resp.text();
const reg = /window.__INITIAL_STATE__=(.*?)<\/script>/; const reg = /window\.__INITIAL_STATE__=(.*?)<\/script>/;
const resJson = xhsHtml.match(reg)[0]; const res = xhsHtml.match(reg)[1].replace(/undefined/g, "null");
const res = JSON.parse(resJson.match(reg)[1]); const resJson = JSON.parse(res);
const noteData = res.noteData.data.noteData; const noteData = resJson.note.noteDetailMap[id].note
const { title, desc, type } = noteData; const { title, desc, type } = noteData;
e.reply(`识别:小红书, ${ title }\n${ desc }`);
let imgPromise = []; let imgPromise = [];
if (type === "video") { 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")); e.reply(segment.video(path + "/temp.mp4"));
}); });
return true; return true;
} else if (type === "normal") { } else if (type === "normal") {
e.reply(`识别:小红书, ${ title }\n${ desc }`);
noteData.imageList.map(async (item, index) => { 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); const paths = await Promise.all(imgPromise);
@ -1045,7 +1050,7 @@ export class tools extends plugin {
writer.on("error", reject); writer.on("error", reject);
}); });
} catch (err) { } catch (err) {
logger.error("下载视频发生错误!"); logger.error(`下载视频发生错误!\ninfo:${err}`);
} }
} }

View File

@ -1,7 +1,8 @@
- { - {
version: 1.2.2, version: 1.2.3,
data: data:
[ [
新增<span class="cmd">小红书无水印下载</span>功能,
新增<span class="cmd">哔哩哔哩官方AI总结</span>功能, 新增<span class="cmd">哔哩哔哩官方AI总结</span>功能,
新增<span class="cmd">哔哩哔哩音乐提取</span>功能, 新增<span class="cmd">哔哩哔哩音乐提取</span>功能,
新增<span class="cmd">快手解析</span>功能, 新增<span class="cmd">快手解析</span>功能,

View File

@ -38,6 +38,25 @@ export const TEN_THOUSAND = 10000;
export const CAT_LIMIT = 10; 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-----------------------限制说明-----------------------" export const RESTRICTION_DESCRIPTION = "\n-----------------------限制说明-----------------------"

5
constants/xhs.js Normal file
View File

@ -0,0 +1,5 @@
/**
* 视频请求链接CDN
* @type {string}
*/
export const XHS_VIDEO = "http://sns-video-bd.xhscdn.com/"