From 028835c2c440b87bc538e7bdcc82d49b9fab9c4e Mon Sep 17 00:00:00 2001 From: huangxd- <649924757@qq.com> Date: Sat, 18 Apr 2026 11:58:44 +0800 Subject: [PATCH] =?UTF-8?q?douban=E6=BA=90=E6=90=9C=E7=B4=A2=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=A2=9E=E5=8A=A0=E5=85=AC=E5=BC=80api=E5=85=9C?= =?UTF-8?q?=E5=BA=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- danmu_api/configs/globals.js | 2 +- danmu_api/sources/douban.js | 73 ++++++++++++++++++++++++++++++++-- danmu_api/utils/douban-util.js | 7 ++++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/danmu_api/configs/globals.js b/danmu_api/configs/globals.js index a6d04a4..582c89b 100644 --- a/danmu_api/configs/globals.js +++ b/danmu_api/configs/globals.js @@ -13,7 +13,7 @@ export const Globals = { accessedEnvVars: {}, // 静态常量 - VERSION: '1.18.7', + VERSION: '1.18.8', MAX_LOGS: 1000, // 日志存储,最多保存 1000 行 MAX_RECORDS: 100, // 请求记录最大数量 diff --git a/danmu_api/sources/douban.js b/danmu_api/sources/douban.js index 4b59e94..8fd9d0f 100644 --- a/danmu_api/sources/douban.js +++ b/danmu_api/sources/douban.js @@ -1,6 +1,6 @@ import BaseSource from './base.js'; import { log } from "../utils/log-util.js"; -import { getDoubanDetail, searchDoubanTitles } from "../utils/douban-util.js"; +import { getDoubanDetail, searchDoubanTitles, searchDoubanTitlesByPublic } from "../utils/douban-util.js"; // ===================== // 获取豆瓣源播放链接 @@ -17,9 +17,24 @@ export default class DoubanSource extends BaseSource { async search(keyword) { try { - const response = await searchDoubanTitles(keyword); + let response = await searchDoubanTitles(keyword); + let data = response?.data; - const data = response.data; + // 兜底策略:如果 searchDoubanTitles 失败或返回空结果,使用 searchDoubanTitlesByPublic + if (!data || (!data?.subjects?.items?.length && !data?.smart_box?.length)) { + log("info", "searchDoubanTitles failed or empty, trying searchDoubanTitlesByPublic"); + const fallbackResponse = await searchDoubanTitlesByPublic(keyword); + const fallbackData = fallbackResponse?.data; + + if (fallbackData?.subjects?.length > 0) { + // 将 searchDoubanTitlesByPublic 返回的数据转换为原格式 + data = { + subjects: { + items: fallbackData.subjects.map(item => this.convertToOriginalFormat(item)), + } + }; + } + } let tmpAnimes = []; if (data?.subjects?.items?.length > 0) { @@ -43,6 +58,58 @@ export default class DoubanSource extends BaseSource { } } + // 将 searchDoubanTitlesByPublic 返回的数据格式转换为原格式 + convertToOriginalFormat(item) { + // subtype: "movie" -> "电影", "tv" -> "电视剧" + const typeMap = { + 'movie': '电影', + 'tv': '电视剧' + }; + const typeName = typeMap[item.subtype] || item.subtype; + + // 构建 cover_url:从原始图片URL中提取图片ID,然后构造固定格式的URL + const originalImageUrl = item.images?.large || item.images?.medium || item.images?.small || ''; + let coverUrl = ''; + if (originalImageUrl) { + // 从类似 https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2887095203.jpg 的URL中提取 p2887095203 + const match = originalImageUrl.match(/\/(p\d+)\.jpg/); + if (match && match[1]) { + const imageId = match[1]; // 例如 p2887095203 + coverUrl = `https://qnmob3.doubanio.com/view/photo/large/public/${imageId}.jpg?imageView2/0/q/80/w/9999/h/120/format/jpg`; + } + } + + // 构建 card_subtitle,包含地区、类型、导演、演员等信息 + const directors = item.directors?.map(d => d.name).join(' ') || ''; + const casts = item.casts?.slice(0, 3).map(c => c.name).join(' ') || ''; + const cardSubtitle = `${item.year} / ${item.genres?.join(' / ') || ''} / ${directors}${casts ? ' / ' + casts : ''}`; + + return { + layout: 'subject', + type_name: typeName, + target_id: String(item.id), + target: { + rating: { + count: item.collect_count || 0, + max: item.rating?.max || 10, + star_count: item.rating?.stars ? parseInt(item.rating.stars) / 10 : 0, + value: item.rating?.average || 0 + }, + controversy_reason: '', + title: item.title, + abstract: '', + has_linewatch: false, + uri: `douban://douban.com/${item.subtype === 'movie' ? 'movie' : 'tv'}/${item.id}`, + cover_url: coverUrl, + year: String(item.year || ''), + card_subtitle: cardSubtitle, + id: String(item.id), + null_rating_reason: '' + }, + target_type: item.subtype === 'movie' ? 'movie' : 'tv' + }; + } + async getEpisodes(id) {} async handleAnimes(sourceAnimes, queryTitle, curAnimes, detailStore = null) { diff --git a/danmu_api/utils/douban-util.js b/danmu_api/utils/douban-util.js index 8cad1fc..8c59fa8 100644 --- a/danmu_api/utils/douban-util.js +++ b/danmu_api/utils/douban-util.js @@ -70,6 +70,13 @@ export async function searchDoubanTitles(keyword, count = 20) { return await doubanApiGet(url); } +// 使用 豆瓣 公开 API 查询片名 +export async function searchDoubanTitlesByPublic(keyword, count = 20) { + const url = `/movie/search`; + const data = { q: keyword, start: 0, count: count }; + return await doubanApiPost(url, data); +} + // 使用 豆瓣 API 查询详情 export async function getDoubanDetail(doubanId) { const url = `/movie/${doubanId}?for_mobile=1`;