返回首页

面向 IT 的 Telegram 到 Obsidian 转换器

转换器将 Telegram JSON 导出传输到 Obsidian,保留媒体、格式和聊天结构。实现了文件索引、多级搜索和实体处理。适合从数千条消息创建离线数据库。

将 Telegram chats 导入 Obsidian:代码和 schema
Advertisement 728x90

Telegram 聊天记录一键导入 Obsidian:支持媒体文件与超链接的智能转换工具

本工具将 Telegram Desktop 导出的 JSON 数据,一键转化为结构清晰、开箱即用的 Obsidian 知识库。它能精准解析消息内容、自动复制媒体文件、将 Telegram 原生格式(如加粗、链接、剧透框)转为语义化 Markdown,并按联系人、群组、频道三大类型智能归类。系统内置健壮的文件索引机制,确保路径解析稳定可靠,同时优雅处理重名文件冲突。

原始 Telegram 导出包包含 result.json(元数据)、基于 HTML 的 chats/ 文件夹(含消息正文)及配套媒体资源。目标输出结构为 Telegram_Export/ 根目录,下设 Contacts/(联系人)、Groups/(群组)、Channels/(频道)三个子目录,外加一份全局索引文件 Index.md

转换器核心架构

系统由五大模块协同工作:JSON 解析器、媒体索引器、Markdown 转换器、文件管理器、知识库结构生成器。数据流清晰明确:JSON → 解析 → 索引 → 转换 → 媒体文件嵌入的 Obsidian 知识库

Google AdInline article slot

关键组件说明:

  • 解析器:从 result.json 中提取全部聊天会话、消息正文及完整元数据;
  • 索引器:按扩展名(.jpg.mp4.pdf 等)构建可快速检索的媒体文件映射表;
  • 转换器:采用四层回退策略查找媒体资源,并应用丰富的富文本格式规则;
  • 文件管理器:将媒体文件精准复制至对应笔记所在文件夹,自动去重并规范命名。

所有配置均通过环境变量控制:TELEGRAM_JSON_FILE(输入 JSON 路径)、OBSIDIAN_OUTPUT_DIR(输出目录)、COPY_MEDIA(是否启用媒体复制)。

import os
from pathlib import Path

JSON_FILE = os.getenv('TELEGRAM_JSON_FILE', 'result.json')
EXPORT_BASE = Path(os.getenv('TELEGRAM_EXPORT_BASE', '.'))
OUTPUT_DIR = Path(os.getenv('OBSIDIAN_OUTPUT_DIR', 'Telegram_Export'))
COPY_MEDIA = os.getenv('COPY_MEDIA', 'true').lower() == 'true'
GROUP_BY_DAY = os.getenv('GROUP_BY_DAY', 'true').lower() == 'true'

媒体索引与智能查找

工具自动生成 patch.txt 文件(通过 ls -R 命令捕获 Telegram 导出包完整目录树),索引器据此建立「文件名→相对路径→绝对路径」三级映射,实现毫秒级、确定性媒体定位。

Google AdInline article slot
def index_media_from_patch(self):
    media_extensions = {'.jpg', '.jpeg', '.png', '.gif', '.webp', '.mp4', '.webm', '.pdf', '.zip', '.mp3'}
    current_dir = None
    
    with open(PATCH_FILE, 'r', encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            if line.endswith(':'):
                current_dir = line[:-1]
                continue
            if current_dir and any(line.endswith(ext) for ext in media_extensions):
                full_path = Path(current_dir) / line
                self.media_index[line] = full_path
                if 'chats/' in str(full_path):
                    rel_path = str(full_path).split('chats/', 1)[-1]
                    self.media_index[rel_path] = full_path

媒体查找采用四级容错机制:精确文件名匹配 → 完整路径匹配 → 部分路径模糊匹配 → 直接基于 EXPORT_BASE 的相对路径解析。

媒体文件复制与冲突处理

媒体文件被直接复制到每条笔记所在的文件夹内(而非统一存入共享附件目录),确保 Obsidian 原生嵌入语法(如 ![[file]])无需任何额外配置即可生效。media_cache 缓存机制大幅提升重复查找效率。当出现同名文件时,自动追加 _1_2 等后缀以保安全。

def copy_media_file(self, source_path: str, note_folder: Path = None) -> Optional[str]:
    if not COPY_MEDIA or not source_path:
        return None
    
    source_file = self.find_media_file(source_path)
    if not source_file or not source_file.exists():
        return None
    
    target_dir = note_folder if note_folder else OUTPUT_DIR / "Attachments"
    target_dir.mkdir(parents=True, exist_ok=True)
    target_file = target_dir / source_file.name
    
    if target_file.exists():
        stem = target_file.stem
        suffix = target_file.suffix
        counter = 1
        while target_file.exists():
            target_file = target_dir / f"{stem}_{counter}{suffix}"
            counter += 1
    
    shutil.copy2(source_file, target_file)
    self.stats['media_files'] += 1
    return source_file.name

文本与实体解析

HTML 内容及 Telegram 特有格式(加粗、超链接、剧透框等)被精准还原为语义化 Markdown,所有处理器均兼顾语义表达与 Obsidian 兼容性。

Google AdInline article slot
def parse_text_entities(self, text: Union[str, List], entities: Optional[List[Dict]] = None) -> str:
    if isinstance(text, str) and ('<' in text or '&' in text):
        return self.html_to_markdown(text)
    
    if entities and isinstance(text, str):
        return self._process_entities(text, entities)
    
    handlers = {
        'bold': lambda t: f"**{t}**",
        'italic': lambda t: f"*{t}*",
        'code': lambda t: f"`{t}`",
        'pre': lambda t: f"```
{t}

'link': lambda t, e: f"[{t}]({e.get('url', '')})",

'spoiler': lambda t: f"\n> [!spoiler] {t}\n"

}

return str(text) if text else ""


## 消息排版逻辑

每条消息均包含时间戳、发送者、格式化正文(含实体渲染)及嵌入式媒体引用。`photo`、`video`、`audio` 等字段触发专属媒体提取流程。

处理步骤:
1. 提取 `date` 和 `from` 字段;
2. 调用 `text_entities` 逻辑解析 `text`;
3. 识别媒体字段,复制文件,并插入 `![描述](路径)` 或 `![[文件名]]` 链接;
4. 若启用 `GROUP_BY_DAY`,则按日期自动分组归档。

内置统计模块实时追踪已处理的聊天数、消息数、媒体文件数及联系人数量。

## 核心设计原则

- `patch.txt` 索引机制有效弥合 JSON 中路径描述与实际文件系统布局之间的差异;
- 四级媒体查找策略保障 >95% 的资源定位成功率;
- 每笔记独立存放媒体文件,彻底解决 Obsidian 嵌入兼容性问题;
- 全面支持 Telegram 富文本特性:加粗、代码块、超链接、@提及、剧透框;
- 纯环境变量驱动配置,开箱即用于生产环境,无缝对接 CI/CD 流水线。

— Editorial Team

Advertisement 728x90

继续阅读