From 1cd8c33983ebeef8854833dc37d57fff047ee846 Mon Sep 17 00:00:00 2001 From: huangjianwu Date: Mon, 23 Mar 2026 13:18:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(note):=20=E5=9C=A8=E7=AC=94=E8=AE=B0?= =?UTF-8?q?=E5=BC=80=E5=A4=B4=E6=B7=BB=E5=8A=A0=E6=9D=A5=E6=BA=90=E9=93=BE?= =?UTF-8?q?=E6=8E=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/utils/note_helper.py | 63 ++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/backend/app/utils/note_helper.py b/backend/app/utils/note_helper.py index 91de87e..2e368d1 100644 --- a/backend/app/utils/note_helper.py +++ b/backend/app/utils/note_helper.py @@ -1,9 +1,39 @@ import re + +def prepend_source_link(markdown: str | None, source_url: str) -> str | None: + """ + 在笔记开头添加来源链接;若首个非空行已包含来源链接,则更新该行并避免重复。 + """ + if markdown is None: + return None + + source = (source_url or "").strip() + if not source: + return markdown + + header = f"> 来源链接:{source}" + lines = markdown.splitlines() + first_non_empty_idx = None + for idx, line in enumerate(lines): + if line.strip(): + first_non_empty_idx = idx + break + + if first_non_empty_idx is not None: + first_line = lines[first_non_empty_idx].strip() + if first_line.startswith("> 来源链接:") or first_line.startswith("来源链接:"): + lines[first_non_empty_idx] = header + return "\n".join(lines) + + if markdown.strip(): + return f"{header}\n\n{markdown}" + return header + + def replace_content_markers(markdown: str, video_id: str, platform: str = 'bilibili') -> str: """ - 替换 *Content-04:16*、Content-04:16 或 Content-[04:16] 为超链接 - 目标格式:- [04:16](https://www.bilibili.com/video/BVxxx?t=256#t=04:16) + 替换 *Content-04:16*、Content-04:16 或 Content-[04:16] 为超链接,跳转到对应平台视频的时间位置 """ # 匹配三种形式:*Content-04:16*、Content-04:16、Content-[04:16] pattern = r"(?:\*?)Content-(?:\[(\d{2}):(\d{2})\]|(\d{2}):(\d{2}))" @@ -14,28 +44,23 @@ def replace_content_markers(markdown: str, video_id: str, platform: str = 'bilib mm = match.group(1) or match.group(3) ss = match.group(2) or match.group(4) total_seconds = int(mm) * 60 + int(ss) - time_str = f"{mm}:{ss}" if platform == 'bilibili': - # 处理多 P 情况,如果是 BV123_p3 转换为 BV123?p=3 - actual_video_id = video_id.replace("_p", "?p=") - - # 判断连接符是 ? 还是 & (如果 video_id 里已经有了 ?p=,则时间参数用 &t=) - connector = "&t=" if "?" in actual_video_id else "?t=" - - # 拼接最终 URL,并在末尾加上 #t=MM:SS 锚点 - url = f"https://www.bilibili.com/video/{actual_video_id}{connector}{total_seconds}#t={time_str}" - return f"- [{time_str}]({url})" - + video_id = video_id.replace("_p", "?p=") + url = f"https://www.bilibili.com/video/{video_id}&t={total_seconds}" + parsed_video_id = safe_video_id.replace("_p", "?p=") + url = f"https://www.bilibili.com/video/{parsed_video_id}&t={total_seconds}" elif platform == 'youtube': url = f"https://www.youtube.com/watch?v={video_id}&t={total_seconds}s" - return f"- [{time_str}]({url})" - + url = f"https://www.youtube.com/watch?v={safe_video_id}&t={total_seconds}s" elif platform == 'douyin': url = f"https://www.douyin.com/video/{video_id}" - return f"[原片 @ {time_str}]({url})" - + url = f"https://www.douyin.com/video/{safe_video_id}" + return f"[原片 @ {mm}:{ss}]({url})" else: - return f"({time_str})" + return f"({mm}:{ss})" + + return f"[原片 @ {mm}:{ss}]({url})" + + return re.sub(pattern, replacer, markdown) - return re.sub(pattern, replacer, markdown) \ No newline at end of file