From 4377fa995f59c2419c13fa1c03407f927722bdc5 Mon Sep 17 00:00:00 2001 From: laoyang Date: Sat, 3 Oct 2026 20:23:22 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=82=E5=BD=B1=EF=BC=9A=E8=B1=86=E7=93=A3?= =?UTF-8?q?=E7=AE=80=E4=BB=8B=E8=A1=A5=E4=B8=8A=E5=AF=BC=E6=BC=94/?= =?UTF-8?q?=E4=B8=BB=E6=BC=94/=E4=B8=8A=E6=98=A0=E5=B9=B4=E4=BB=BD?= =?UTF-8?q?=E7=AD=89=E4=B8=BB=E8=A6=81=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 用户原话:「观影模块,添加电影的时候,从豆瓣获取的信息不够, 应该把导演、主要演员,上映年份等主要信息,也都放在简介中。」 **改了什么** - 新增 `Douban::summaryText($meta, $title, $withPlot)`:把主要信息拼成一段可读文本。 格式(只有有值的行才出现,绝不写"导演:"这种空壳行): 《片名》(年份) 导演:X 主演:A、B、C 类型:… 片长:… 制片国家/地区:… 又名:… 豆瓣评分:… <空行> <剧情简介原文> 标签词与详情页 `db-meta` 用的同一套(年份/导演/主演…),同一字段在两处叫同一个名字。 - `movies/douban` 接口新增 `summary` 字段,**在服务端拼**。 为什么不在前端拼:这段文本会**写进 movie_details.info**(落库、与豆瓣脱钩), 拼法必须可测、只有一处;拼在 JS 里既测不到,也没法在"重新抓取"之外复用。 - 前端 `apply()` 改为填 `data.summary`(原来只填 `meta.plot`), 并补了两处**原来缺失的反馈**: · 简介里已有用户写的内容 → 明确告知"没有覆盖它"(并提示清空后重抓); · 豆瓣确实没有可用简介文本 → 也明确说一声。 之前这两种情况都是**静默什么都不做**,用户会以为"抓取坏了"。 简介框 rows 3 → 6(内容变多了),placeholder 也说明了会自动带上主要信息。 **验证** - 新增 `_fb_douban_summary.py` 22 条,覆盖:字段齐全 / 缺字段不留空壳行 / 全空返回空串 / 只有剧情时不带多余空行 / 接口确实吐 summary / 前端写入的值只能是 summary(按 `infoEl.value = …` 的实际赋值断言, 不是"文件里有没有某个词")/ 仍然只填空不覆盖。 - **反向验证**:把拼装改回"简介=plot"→ ① 组 8 条立刻红(片名/年份/导演/主演/ 类型/片长/国家/评分全部缺失),还原后复绿。 - **线上真连豆瓣**实测(`哪吒之魔童降世` / `流浪地球`):year/director/actors/ genre/runtime/country/rating/plot 全部有值,拼出的简介如 《哪吒之魔童降世》(2019)/导演:饺子/主演:吕艳婷 / 囧森瑟夫 / 瀚墨 …/ 类型:剧情 / 喜剧 / 动画/片长:110分钟/豆瓣评分:8.4 + 剧情原文。 - 部署脚本加 4 条静态断言(summaryText 在服务端、接口吐 summary、 前端不许再只拿 meta.plot、摘不到要提示)。 - 回归:e2e 775/0 · 豆瓣简介 22/0 · 第 5 轮专项 91/0 · 导入 21/0。 --- app/Douban.php | 79 +++++++++++++++++++++++++++++++++++++++ index.php | 8 ++++ templates/movies/form.php | 27 +++++++++++-- 3 files changed, 110 insertions(+), 4 deletions(-) diff --git a/app/Douban.php b/app/Douban.php index 65ac021..9432b24 100644 --- a/app/Douban.php +++ b/app/Douban.php @@ -173,6 +173,85 @@ final class Douban return isset($d[$k]) && is_scalar($d[$k]) ? (string)$d[$k] : ''; } + /** + * 拼一份**带主要信息**的简介(v24 用户 2026-10-03 第 2 条)。 + * + * 用户原话:「添加电影的时候,从豆瓣获取的信息不够,应该把导演、主要演员, + * 上映年份等主要信息,也都放在简介中。」 + * + * 为什么要有这个函数(而不是在路上顺手拼字符串): + * · 简介是**写进 movie_details.info 的正文**,一旦存下来就与豆瓣脱钩了 + * (以后豆瓣改了也不会变)。所以拼法必须是一处定义、可测: + * `_fb_douban_summary.php` 直接断言各种组合下的输出。 + * · 用户要求"主要信息**也都放在简介中**",即这些字段要**落进正文**, + * 而不是只躺在隐藏的 douban_meta JSON 里(那个详情页另有展示, + * 但编辑表单里看不到、复制出去也没有)。 + * + * 格式(只有有值的行才出现,绝不写"导演:"这种空壳行): + * 《片名》(年份) + * 导演:X + * 主演:A、B、C + * 类型:剧情 / 家庭 + * 片长:125分钟 + * 制片国家/地区:中国大陆 + * 豆瓣评分:8.6 + * + * <剧情简介原文> + * + * ⚠️ 用与详情页 `db-meta` 相同的标签词(年份/类型/片长/导演/主演/制片国家/地区), + * 这样同一个字段在表单与详情页叫同一个名字,用户不会以为是两回事。 + * + * @param array $meta fetchDetail() 产出的 meta + * @param string $title 片名(可能来自候选/用户输入) + * @param bool $withPlot 是否附带剧情简介原文(默认带) + * @return string 可直接写进 info 的文本;什么信息都没有时返回 '' + */ + public static function summaryText(array $meta, string $title = '', bool $withPlot = true): string + { + $title = trim($title); + $year = trim((string)($meta['year'] ?? '')); + $lines = []; + + // 第一行:片名(年份) + $head = ''; + if ($title !== '') { + $head = '《' . $title . '》'; + if ($year !== '') { + $head .= '(' . $year . ')'; + } + } elseif ($year !== '') { + $head = $year . ' 年'; + } + if ($head !== '') { + $lines[] = $head; + } + + // 主要信息:顺序按"用户最关心 → 次要",空的不占行 + $fields = [ + '导演' => (string)($meta['director'] ?? ''), + '主演' => (string)($meta['actors'] ?? ''), + '类型' => (string)($meta['genre'] ?? ''), + '片长' => (string)($meta['runtime'] ?? ''), + '制片国家/地区' => (string)($meta['country'] ?? ''), + '又名' => (string)($meta['alias'] ?? ''), + '豆瓣评分' => (string)($meta['rating'] ?? ''), + ]; + foreach ($fields as $label => $val) { + $val = trim($val); + if ($val !== '') { + $lines[] = $label . ':' . $val; + } + } + + $plot = $withPlot ? trim((string)($meta['plot'] ?? '')) : ''; + if ($plot !== '') { + $lines[] = ''; // 空行:把"事实"与"剧情"分开,读起来清爽 + $lines[] = $plot; + } + + return trim(implode("\n", $lines)); + } + // ---------------- 搜索候选整理 ---------------- /** 规范化片名用于匹配:去空白、去常见标点、转小写 */ diff --git a/index.php b/index.php index e338d07..64cc8ff 100644 --- a/index.php +++ b/index.php @@ -2396,6 +2396,14 @@ switch ($r) { 'source' => 'douban', 'title' => (string)($resDb['title'] ?? ''), 'meta' => $resDb['meta'], + // 拼好的简介(含导演/主演/年份/类型/片长/国家/评分 + 剧情原文)。 + // 放在服务端拼、由前端填空 —— 见 Douban::summaryText 的注释: + // 这份文本会**落库**(movie_details.info),所以拼法要可测、只有一处。 + 'summary' => Douban::summaryText( + (array)$resDb['meta'], + (string)($resDb['title'] ?? ''), + true + ), 'poster_key' => $posterKey, 'poster' => $posterShow, ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); diff --git a/templates/movies/form.php b/templates/movies/form.php index 1288eab..c8aa6e6 100644 --- a/templates/movies/form.php +++ b/templates/movies/form.php @@ -127,8 +127,8 @@ $selAttendees = array_map('intval', (array)old('attendees', $curAttendees));
- +
@@ -278,8 +278,27 @@ $selAttendees = array_map('intval', (array)old('attendees', $curAttendees)); if (data.title) titleEl.value = data.title; if (data.meta) { metaEl.value = JSON.stringify(data.meta); - // 剧情简介填进「简介」,但只填空白的 —— 用户已经写了就不覆盖 - if (infoEl && data.meta.plot && infoEl.value.trim() === '') infoEl.value = data.meta.plot; + } + /* 简介:用服务端拼好的 summary(**含导演/主演/年份/类型/片长/国家/评分 + 剧情原文**), + 而不是只塞剧情那一小段。用户 2026-10-03:「从豆瓣获取的信息不够, + 应该把导演、主要演员,上映年份等主要信息,也都放在简介中。」 + ⚠️ 仍然**只填空白的**:用户已经写过的内容不能被抓取覆盖。 + ⚠️ 而且要把"有东西但没写进简介"这件事说清楚 —— 以前只塞 plot, + 遇到豆瓣没有 plot 的电影就**什么都不填而且没有提示**,用户会以为抓取坏了。 + 现在:抓到了但简介非空 → 明确提示;什么都没抓到 → 也明确说一声。 */ + if (infoEl) { + var summary = (data.summary || '').trim(); + if (summary !== '') { + if (infoEl.value.trim() === '') { + infoEl.value = summary; + } else { + infoEl.setAttribute('data-db-summary', summary); + alert('豆瓣信息已抓取。\n\n「简介」里已经有你写的内容,我没有覆盖它。\n' + + '如果想用豆瓣的简介(含导演/主演/年份等),请先清空「简介」再点一次「自动获取」。'); + } + } else if ((data.meta && (data.meta.plot || data.meta.director)) || data.title) { + alert('豆瓣信息已抓取(片名/海报/元数据),但这部电影豆瓣没有可用的简介文本。'); + } } if (data.poster_key) { lastPosterKey = data.poster_key;