Conversor de Telegram a Obsidian: Importa chats automáticamente con gestión de medios y enlaces
El conversor transforma la exportación JSON de Telegram Desktop en un almacén Obsidian bien organizado. Analiza los mensajes, copia los archivos multimedia, convierte el formato de Telegram a Markdown limpio y organiza los chats por tipo (contactos, grupos y canales). La solución genera un índice de archivos robusto para una resolución fiable de rutas y gestiona con elegancia los conflictos de nombres de archivo.
La exportación original de Telegram incluye result.json (metadatos), una carpeta HTML basada en chats/ con los mensajes y los archivos multimedia asociados. La estructura objetivo es Telegram_Export/, subdividida en Contactos/, Grupos/, Canales/, además de un archivo central Index.md.
Arquitectura del conversor
El sistema consta de cinco módulos principales: un analizador JSON, un indexador de medios, un convertidor a Markdown, un gestor de archivos y un generador de estructura de almacén. El flujo de datos es el siguiente: JSON → análisis → indexación → conversión → almacén Obsidian con los medios copiados en las carpetas de las notas.
Componentes clave:
- Analizador: extrae chats, mensajes y metadatos de
result.json. - Indexador: construye un mapa buscable de archivos multimedia por extensión (
.jpg,.mp4,.pdf, etc.). - Convertidor: aplica estrategias múltiples de búsqueda de medios y reglas de formateo de texto enriquecido.
- Gestor de archivos: copia los recursos en las carpetas correspondientes de las notas, eliminando duplicados en los nombres.
La configuración se gestiona mediante variables de entorno: TELEGRAM_JSON_FILE, OBSIDIAN_OUTPUT_DIR y 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'
Indexación y búsqueda de medios
Un archivo patch.txt —generado mediante ls -R— captura el árbol completo de directorios de la exportación de Telegram. El indexador mapea nombres de archivo, rutas relativas y rutas absolutas para búsquedas rápidas y deterministas.
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
La búsqueda de medios utiliza cuatro estrategias alternativas: coincidencia exacta por nombre, coincidencia por ruta completa, coincidencia parcial de ruta y resolución directa de ruta relativa desde EXPORT_BASE.
Copia de medios con gestión de colisiones
Los archivos se copian en la carpeta de cada nota, no en un directorio compartido de adjuntos —lo que garantiza que la sintaxis nativa de incrustación de Obsidian (![[archivo]]) funcione sin configuración adicional. Una media_cache acelera las búsquedas repetidas. En caso de colisión de nombres, se añaden sufijos como _1, _2 de forma automática.
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
Análisis de texto y entidades
Las entidades HTML y específicas de Telegram (negrita, enlaces, spoilers, etc.) se convierten a Markdown semántico. Controladores especializados preservan el significado y la compatibilidad con Obsidian.
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 ""
## Lógica de formateo de mensajes
Cada mensaje incluye marca de tiempo, remitente, texto formateado (con entidades) y referencias a medios incrustados. Claves como `photo`, `video` y `audio` activan una extracción precisa de medios.
Pasos de procesamiento:
1. Extraer los campos `date` y `from`.
2. Analizar `text` mediante la lógica de `text_entities`.
3. Detectar claves de medios, copiar los archivos e insertar enlaces como `` o `![[archivo]]`.
4. Agrupar mensajes por fecha si está habilitada la opción `GROUP_BY_DAY`.
Las estadísticas integradas registran chats, mensajes, archivos multimedia y contactos procesados.
## Principios clave de diseño
- La indexación mediante `patch.txt` resuelve inconsistencias entre las rutas del JSON y la estructura real del sistema de archivos.
- La búsqueda de medios en cuatro niveles alcanza una cobertura superior al 95 % en la resolución de recursos.
- La copia de medios por nota garantiza una integración perfecta con la funcionalidad de incrustación nativa de Obsidian.
- Soporte completo para las funciones avanzadas de texto enriquecido de Telegram: negrita, bloques de código, enlaces, menciones y spoilers.
- La configuración controlada por variables de entorno permite despliegues listos para producción e integración con CI/CD.
— Editorial Team
Aún no hay comentarios.