UNPKG

koishi-plugin-kbot

Version:
88 lines (87 loc) 4.61 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.apply = exports.Config = void 0; const jsx_runtime_1 = require("@satorijs/element/jsx-runtime"); const koishi_1 = require("koishi"); const logger = new koishi_1.Logger('plugins/youtube'); exports.Config = koishi_1.Schema.object({ youtubeDataApiKey: koishi_1.Schema.string() .required() .description('请提供YouTube Data API v3 (必填) 详情: https://developers.google.com/youtube/v3/getting-started'), useImage: koishi_1.Schema.boolean().default(false).description('是否使用图片模式 (需要 puppeteer 支持!)'), }); const apiEndPointPrefix = 'https://www.googleapis.com/youtube/v3/videos'; const youtubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/(?:watch\?(?=.*v=\w+)(?:\S+)?|embed\/\w+|\S+)|youtu\.be\/\w+)(?:\S+)?/ig; const videoRegex = /^(?:https?:\/\/)?(?:i\.|www\.|img\.)?(?:youtu\.be\/|youtube\.com\/|ytimg\.com\/)(?:embed\/|v\/|vi\/|vi_webp\/|watch\?v=|watch\?.+&v=)?((\w|-){11})(?:\S+)?$/; async function fetchDataFromAPI(ctx, config, videoId) { try { const data = await ctx.http.get(`${apiEndPointPrefix}?id=${videoId}&key=${config.youtubeDataApiKey}&part=snippet,contentDetails,statistics,status`); return data; } catch (error) { logger.error(`YouTube API 请求失败: ${error}`); throw new Error('YouTube API 请求失败'); } } function getIDFromURLByRegex(url) { const [, id] = url.match(videoRegex) || []; return id; } function apply(ctx, config) { ctx.middleware(async (session, next) => { const contentArray = session.content.match(youtubeRegex); const isYoutube = contentArray && contentArray.length > 0; if (!isYoutube) return next(); try { contentArray.map(async (content) => { logger.info(`捕获到 Youtube 视频链接: ${content}`); let id; let tagString = '无'; if (content.includes('https://youtu.be')) { const index = content.lastIndexOf('/'); id = content.substring(index + 1, content.length); } else { id = getIDFromURLByRegex(content); } const result = await fetchDataFromAPI(ctx, config, id); if (result.items.length === 0) return '未能成功解析, 或许视频不存在'; const { snippet: { title, description, channelTitle, thumbnails: { medium: { url }, }, publishedAt, tags, }, statistics, } = result.items[0]; if (tags) tagString = tags.length > 1 ? tags.join(', ') : tags[0]; logger.info(`Youtube视频解析成功: ${title}`); if (ctx.puppeteer && config.useImage) { // TODO 待优化样式 await session.send((0, jsx_runtime_1.jsxs)("html", { style: { padding: '1rem', color: '#fff', background: '#000', fontSize: '14px', lineHeight: '1.5', fontFamily: 'sans-serif', fontWeight: 'normal', }, children: [(0, jsx_runtime_1.jsx)("img", { src: url }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u9891\u9053: ", channelTitle] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u6807\u9898: ", title] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u63CF\u8FF0: ", description.length > 50 ? `${description.slice(0, 50)}...` : description] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u53D1\u5E03\u65F6\u95F4: ", publishedAt] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u6807\u7B7E: ", tagString] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u64AD\u653E\u91CF: ", statistics.viewCount] }), (0, jsx_runtime_1.jsxs)("p", { children: ["\u70B9\u8D5E: ", statistics.likeCount] })] })); } else { await session.send(`<image url="${url}" /> 频道: ${channelTitle} 标题: ${title} 描述: ${description.length > 50 ? `${description.slice(0, 50)}...` : description} 发布时间: ${publishedAt} 标签: ${tagString} 播放量: ${statistics.viewCount} 点赞: ${statistics.likeCount} `); } }); } catch (error) { logger.error(error); return 'Youtube视频解析发生错误'; } return next(); }); } exports.apply = apply;