diff --git a/apps/tools.js b/apps/tools.js index d861f9b..208c0a5 100644 --- a/apps/tools.js +++ b/apps/tools.js @@ -582,7 +582,7 @@ export class tools extends plugin { const reg = /https?:\/\/x.com\/[0-9-a-zA-Z_]{1,20}\/status\/([0-9]*)/; const twitterUrl = reg.exec(e.msg)[0]; // 提取视频 - const videoUrl = GENERAL_REQ_LINK.replace("{}", twitterUrl); + const videoUrl = GENERAL_REQ_LINK.link.replace("{}", twitterUrl); e.reply("识别:小蓝鸟"); axios.get(videoUrl, { headers: { @@ -982,33 +982,12 @@ export class tools extends plugin { * @return {Promise} */ async general(e) { - const linkAdapter = new GeneralLinkAdapter(e.msg); - const adapter = await linkAdapter.build(); - logger.mark(adapter.link) - e.reply(`识别:${adapter.name}`); - // 发送GET请求 - axios.get(adapter.link, { - headers: { - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', - 'Accept-Language': 'zh-CN,zh;q=0.9', - 'Cache-Control': 'no-cache', - 'Connection': 'keep-alive', - 'Pragma': 'no-cache', - 'Sec-Fetch-Dest': 'document', - 'Sec-Fetch-Mode': 'navigate', - 'Sec-Fetch-Site': 'none', - 'Sec-Fetch-User': '?1', - 'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', - - }, - timeout: 10000 // 设置超时时间 - }).then(resp => { - // 图片:https://kph8gvfz.m.chenzhongtech.com/fw/photo/3x45s52s9wchwwm - - if (resp.data.data?.imageUrl) { - const imageUrl = resp.data.data.imageUrl; - const images = imageUrl.map(item => { + try { + const adapter = await GeneralLinkAdapter.create(e.msg); + e.reply(`识别:${ adapter.name }${ adapter.desc ? `, ${ adapter.desc }` : '' }`); + logger.mark(adapter); + if (adapter.images && adapter.images.length > 0) { + const images = adapter.images.map(item => { return { message: segment.image(item), nickname: this.e.sender.card || this.e.user_id, @@ -1016,14 +995,20 @@ export class tools extends plugin { } }) e.reply(Bot.makeForwardMsg(images)); - } else { + } else if (adapter.video && adapter.video !== '') { // 视频:https://www.kuaishou.com/short-video/3xhjgcmir24m4nm - const url = resp.data.data.url; + const url = adapter.video; this.downloadVideo(url).then(path => { e.reply(segment.video(path + "/temp.mp4")); }); + } else { + e.reply("解析失败:无法获取到资源"); } - }); + } catch (err) { + logger.error("解析失败 ", err); + return true + } + return true } /** diff --git a/config/version.yaml b/config/version.yaml index 3a79d85..672c761 100644 --- a/config/version.yaml +++ b/config/version.yaml @@ -1,5 +1,5 @@ - { - version: 1.5.8, + version: 1.5.9, data: [ 优化哔哩哔哩简介功能, diff --git a/constants/tools.js b/constants/tools.js index a6a8b93..a40a3a2 100644 --- a/constants/tools.js +++ b/constants/tools.js @@ -81,7 +81,14 @@ export const XHS_REQ_LINK = "https://www.xiaohongshu.com/explore/" * 🍉 的请求链接 * @type {string} */ -export const GENERAL_REQ_LINK = "http://47.99.158.118/video-crack/v2/parse?content={}" +export const GENERAL_REQ_LINK = { + link: "http://47.99.158.118/video-crack/v2/parse?content={}", + sign: 1 +} +export const GENERAL_REQ_LINK_2 = { + link: "https://acid.jiuzige.com.cn/web/index/analysis?url={}", + sign: 2 +} /** * 获取网易云歌曲下载链接 diff --git a/utils/general-link-adapter.js b/utils/general-link-adapter.js index 88b6c66..9ed9400 100644 --- a/utils/general-link-adapter.js +++ b/utils/general-link-adapter.js @@ -1,24 +1,41 @@ -import { GENERAL_REQ_LINK } from "../constants/tools.js"; +import { + GENERAL_REQ_LINK, + GENERAL_REQ_LINK_2 +} from "../constants/tools.js"; /** * 第三方接口适配器,用户大面积覆盖解析视频的内容 */ class GeneralLinkAdapter { - #url; - constructor(link) { - console.log("============",link) - if (/share.xiaochuankeji.cn/.test(link)) { - this.#url = this.zuiyou(link); - } else if (/kuaishou.com/.test(link)) { - this.#url = this.ks(link); - } else if (/ixigua.com/.test(link)) { - this.#url = this.xigua(link); - } else if (/h5.pipix.com/.test(link)) { - this.#url = this.pipixia(link); - } else if (/h5.pipigx.com/.test(link)) { - this.#url = this.pipigx(link); - } + constructor() { + } + + /** + * 暂时用这个来处理短链接 + * @param url + * @param includeRedirect + * @returns {Promise} + */ + async fetchUrl(url, includeRedirect = false) { + let response = await fetch(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', + } + }); + return includeRedirect ? response.url : response; + } + + /** + * 辅助函数,该函数接收原始链接和需要插入的视频请求链接(videoReq),然后返回一个新的链接对象 + * @param originalLink + * @param videoReq + * @returns {*} + */ + createReqLink(originalLink, videoReq) { + let reqLink = { ...originalLink }; + reqLink.link = reqLink.link.replace("{}", videoReq); + return reqLink; } async ks(link) { @@ -28,13 +45,7 @@ class GeneralLinkAdapter { let msg = /(?:https?:\/\/)?(www|v)\.kuaishou\.com\/[A-Za-z\d._?%&+\-=\/#]*/g.exec(link)[0]; // 跳转短号 if (msg.includes("v.kuaishou")) { - await fetch(msg, { - headers: { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', - } - }).then(resp => { - msg = resp.url; - }) + msg = await this.fetchUrl(msg, true); } let video_id; if (msg.includes('/fw/photo/')) { @@ -42,19 +53,21 @@ class GeneralLinkAdapter { } else if (msg.includes("short-video")) { video_id = msg.match(/short-video\/([^/?]+)/)[1]; } else { - throw "无法提取快手的信息,请重试或者换一个视频!"; + throw Error("无法提取快手的信息,请重试或者换一个视频!"); } + const reqLink = this.createReqLink(GENERAL_REQ_LINK, `https://www.kuaishou.com/short-video/${video_id}`); // 提取视频 return { name: "快手", - link: GENERAL_REQ_LINK.replace("{}", `https://www.kuaishou.com/short-video/${ video_id }`) + reqLink }; } async zuiyou(link) { // #最右#分享一条有趣的内容给你,不好看算我输。请戳链接>>https://share.xiaochuankeji.cn/hybrid/share/post?pid=365367131&zy_to=applink&share_count=1&m=dc114ccc8e55492642f6a702b510c1f6&d=9e18ca2dace030af656baea96321e0ea353fe5c46097a7f3962b93f995641e962796dd5faa231feea5531ac65547045f&app=zuiyou&recommend=r0&name=n0&title_type=t0 const msg = /(?:https?:\/\/)?(share|share.xiaochuankeji)\.cn\/[A-Za-z\d._?%&+\-=\/#]*/.exec(link)[0]; - return {name: "最右", link: GENERAL_REQ_LINK.replace("{}", msg)}; + const reqLink = this.createReqLink(GENERAL_REQ_LINK, msg); + return { name: "最右", reqLink }; } async xigua(link) { @@ -64,32 +77,108 @@ class GeneralLinkAdapter { let msg = /(?:https?:\/\/)?(www|v|m)\.ixigua\.com\/[A-Za-z\d._?%&+\-=\/#]*/g.exec(link)[0]; // 跳转短号 if (msg.includes("v.ixigua")) { - await fetch(msg, { - headers: { - 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', - } - }).then(resp => { - msg = resp.url; - }) + msg = await this.fetchUrl(msg, true); } const id = /ixigua\.com\/(\d+)/.exec(msg)[1] || /\/video\/(\d+)/.exec(msg)[1]; const videoReq = `https://www.ixigua.com/${ id }`; - return {name: "西瓜", link: GENERAL_REQ_LINK.replace("{}", videoReq)}; + const reqLink = this.createReqLink(GENERAL_REQ_LINK, videoReq); + return { name: "西瓜", reqLink }; } async pipixia(link) { const msg = /https:\/\/h5\.pipix\.com\/s\/[A-Za-z0-9]+/.exec(link)?.[0]; - return {name: "皮皮虾", link: GENERAL_REQ_LINK.replace("{}", msg)}; + // 这里必须使用{ ...GENERAL_REQ_LINK_2 }赋值,不然就是对象的引用赋值,会造成全局数据问题! + const reqLink = this.createReqLink(GENERAL_REQ_LINK_2, msg); + return { name: "皮皮虾", reqLink }; } async pipigx(link) { const msg = /https:\/\/h5\.pipigx\.com\/pp\/post\/[A-Za-z0-9]+/.exec(link)?.[0]; - return {name: "皮皮搞笑", link: GENERAL_REQ_LINK.replace("{}", msg)}; + const reqLink = this.createReqLink(GENERAL_REQ_LINK, msg); + return { name: "皮皮搞笑", reqLink }; } - async build() { - return this.#url; + /** + * 初始化通用适配器 + * @param link 通用链接 + * @returns {Promise<*>} + */ + async init(link) { + logger.mark("[R插件][通用解析]", link) + const handlers = new Map([ + [/share.xiaochuankeji.cn/, this.zuiyou.bind(this)], + [/kuaishou.com/, this.ks.bind(this)], + [/ixigua.com/, this.xigua.bind(this)], + [/h5.pipix.com/, this.pipixia.bind(this)], + [/h5.pipigx.com/, this.pipigx.bind(this)], + ]); + + for (let [regex, handler] of handlers) { + if (regex.test(link)) { + return handler(link); + } + } + } + + /** + * 通用解析适配器,将其他的第三方接口转换为统一的接口 + * @param adapter 通用解析适配器 + * @param sign 通用解析标识:1、2 【在适配器的reqLink中】 + * @returns {Promise} + */ + async resolve(adapter, sign) { + // 发送GET请求 + return fetch(adapter.reqLink.link, { + headers: { + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', + 'Accept-Language': 'zh-CN,zh;q=0.9', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Pragma': 'no-cache', + 'Sec-Fetch-Dest': 'document', + 'Sec-Fetch-Mode': 'navigate', + 'Sec-Fetch-Site': 'none', + 'Sec-Fetch-User': '?1', + 'Upgrade-Insecure-Requests': '1', + 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36', + + }, + timeout: 10000 + }).then(async resp => { + const data = await resp.json(); + if (sign === 1) { + // @link GENERAL_REQ_LINK + return { + name: adapter.name, + images: data.data?.imageUrl, + video: data.data?.url, + } + } else if (sign === 2) { + // @link GENERAL_REQ_LINK_2 + return { + name: adapter.name, + images: data.data?.images, + video: data.data?.videoUrl, + desc: data.data?.desc + } + } else { + throw Error("[R插件][通用解析]错误Sign标识"); + } + }) + } + + /** + * 通过工厂方式创建一个通用解析的JSON对象 + * @param link + * @returns {Promise<*>} + */ + static async create(link) { + // 先正则匹配到函数进行出策略处理 + const adapter = await new GeneralLinkAdapter(); + const adapterHandler = await adapter.init(link); + // 对处理完的信息进行通用解析 + return adapter.resolve(adapterHandler, adapterHandler.reqLink.sign); } }