码桶

发现社区成员的开源项目

奶狗 /

ng-webot

公开
index.js3.8 KB
/**
 * 插件:每日简报
 * --------------------------------------------------
 * 发送「早报」/「简报」即可获取当日新闻图片。
 * 使用 v2.xxapi.cn 接口,缓存 30 分钟避免频繁请求。
 *
 * API: https://v2.xxapi.cn/api/hot60s
 * 返回: { code: 200, msg: "...", data: "https://v2.xxapi.cn/cache/60s/2026-07-16.jpg" }
 */
const axios = require('axios');
const path = require('path');
const fs = require('fs');

const API_URL = 'https://v2.xxapi.cn/api/hot60s';
const CACHE_TTL = 30 * 60 * 1000; // 30 分钟缓存
const TMP_DIR = path.join(__dirname, '..', '..', 'data', 'tmp');

let cache = null; // { imageUrl: string, time: timestamp }

async function fetchBriefingImage() {
  // 使用缓存
  if (cache && Date.now() - cache.time < CACHE_TTL) {
    return cache.imageUrl;
  }

  try {
    const { data: resp } = await axios.get(API_URL, {
      timeout: 10000,
      headers: { 'User-Agent': 'Mozilla/5.0 (compatible; BriefBot/1.0)' },
    });

    if (resp.code === 200 && resp.data) {
      cache = { imageUrl: resp.data, time: Date.now() };
      console.log('[daily-briefing] 获取简报图片:', resp.data);
      return resp.data;
    }

    console.warn('[daily-briefing] API 返回异常:', JSON.stringify(resp).substring(0, 200));
    return null;
  } catch (err) {
    console.warn('[daily-briefing] API 请求失败:', err.message);
    return null;
  }
}

module.exports = {
  meta: {
    id: 'daily-briefing',
    name: '每日简报',
    version: '2.0.0',
    author: '奶狗',
    category: '信息获取',
    description: '发送「早报」「简报」即获取当日新闻图片,让你快速了解天下事。',
    entry: 'daily-briefing/index.js',
    configurable: false,
  },

  async onMessage(msg, ctx) {
    const text = (msg.content || '').trim();
    if (text !== '早报' && text !== '简报') return false;

    try {
      // 1. 获取图片 URL
      const imageUrl = await fetchBriefingImage();
      if (!imageUrl) {
        await ctx.sendText('[简报] 暂时无法获取新闻,请稍后再试。');
        return true;
      }
      console.log('[daily-briefing] 图片 URL:', imageUrl);

      // 2. 下载图片到临时目录
      const ext = imageUrl.split('?')[0].split('.').pop().toLowerCase() || 'jpg';
      const tmpName = 'briefing_' + Date.now() + '.' + ext;
      if (!fs.existsSync(TMP_DIR)) fs.mkdirSync(TMP_DIR, { recursive: true });
      const tmpPath = path.join(TMP_DIR, tmpName);

      const response = await axios.get(imageUrl, {
        timeout: 15000,
        responseType: 'arraybuffer',
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
          'Referer': 'https://v2.xxapi.cn/',
        },
      });

      const buf = Buffer.from(response.data);
      console.log('[daily-briefing] 下载完成, size:', buf.length, 'type:', response.headers['content-type']);

      if (buf.length < 100) {
        console.error('[daily-briefing] 图片过小或无效, 内容:', buf.toString('utf-8').substring(0, 200));
        await ctx.sendText('[简报] 图片获取异常,请稍后再试。');
        return true;
      }

      fs.writeFileSync(tmpPath, buf);

      // 3. 发送图片
      console.log('[daily-briefing] 开始发送图片:', tmpPath);
      await ctx.sendMedia(tmpPath, 'image');
      console.log('[daily-briefing] 图片发送成功');

      // 4. 清理
      try { fs.unlinkSync(tmpPath); } catch (_) { /* ignore */ }

    } catch (err) {
      console.error('[daily-briefing] 出错:', err.message, err.stack?.split('\n').slice(0, 3).join(' | '));
      try { await ctx.sendText('[简报] 获取失败,请稍后再试。'); } catch (_) {}
    }
    return true;
  },
};