Phase 0 MVP: Telegram Archiver fully functional (992 posts tested)

This commit is contained in:
2026-03-06 22:15:50 +03:00
parent bb8c7766b4
commit b76e27afcb
14 changed files with 1171 additions and 134 deletions
+379 -48
View File
@@ -17,16 +17,34 @@
## 🗺️ Дорожная карта
### **Фаза 0: Telegram Archiver (MVP)** ⬜ (НЕ НАЧАТА)
### **Фаза 0: Telegram Archiver (MVP)** ✅ (В РАБОТЕ)
**Цель:** Базовый архиватор Telegram-канала в Markdown для Hugo
- [ ] Парсинг Telegram-канала (API / MTProto)
- [ ] Конвертация постов в Markdown (с сохранением форматирования)
- [ ] Экспорт медиа (изображения, видео, документы)
- [ ] Генерация структуры файлов для Hugo
- [ ] Front-matter для каждого поста (дата, теги, ID)
- [ ] Базовая дедупликация при повторном запуске
- [x] **0.1** Парсинг Telegram-канала (API / MTProto) ✅ ВЫПОЛНЕНА
- [x] **0.2** Конвертация постов в Markdown (с сохранением форматирования) ✅ ВЫПОЛНЕНА
- [x] **0.3** Экспорт медиа (изображения, видео, документы) ✅ ВЫПОЛНЕНА
- [x] **0.4** Генерация структуры файлов для Hugo ✅ ВЫПОЛНЕНА
- [x] **0.5** Front-matter для каждого поста (дата, теги, ID) ✅ ВЫПОЛНЕНА
- [x] **0.6** Базовая дедупликация при повторном запуске ✅ ВЫПОЛНЕНА
- [x] **0.7** Извлечение тегов из постов (#хэштеги) и добавление во front-matter ✅ ВЫПОЛНЕНА
- [x] **0.8** Обработка медиа: встраивание в Markdown для Hugo (image shortcode, video) ✅ ВЫПОЛНЕНА
- [ ] **0.9** Сохранение прямых ссылок на посты (для репостов и оригиналов)
- [ ] **0.10** Исправление бага: посты без index.md (только медиа в папке)
- [ ] **0.11** Конвертация видео-кружков и .bin файлов в нормальный формат (mp4)
- [ ] **0.12** Отчёт о неуспешно скачанных файлах (таймаут/размер) + список URL для дозагрузки
- [ ] **0.13** Корректная временная зона (GMT+3 Москва) вместо UTC
- [ ] **0.14** Прямые ссылки на скачивание файлов в front-matter (для дозагрузки)
- [ ] **0.15** Исправление: размер файла = 0 во front-matter (должен браться из Telegram)
- [ ] **0.16** Расширенный front-matter: ссылки на канал, автора, оригинальный пост
- [ ] **0.17** Многопоточное скачивание медиа (параллельные загрузки)
- [ ] **0.18** Валидация скачанных файлов (проверка целостности)
- [ ] **0.19** Очередь на скачивание: сбор URL → многопоточная загрузка
- [ ] **0.20** Аудио-файлы: длительность, waveform для Hugo (красивый плеер)
- [ ] **0.21** Resume: возобновление прерванной архивации (по последнему ID)
- [ ] **0.22** Формат тегов для Hugo: `tags: ["tag1", "tag2"]` вместо списка
- [ ] **0.23** Обработка трансляций (streaming messages) без текста
- [ ] **0.24** Голосовые сообщения: определение формата (ogg/mp3), метаданные
**Результат:** Консольная утилита, которая по ссылке на канал скачивает все посты в папку `content/posts/` для Hugo
@@ -38,14 +56,14 @@
**Цель:** Зарегистрировать бренд, запустить сайт-визитку
- [x] DNS для `c7e.ru` настроен
- [ ] SSL-сертификат (Caddy / Let's Encrypt)
- [ ] Лендинг (1 экран):
- [x] **1.1** DNS для `c7e.ru` настроен
- [ ] **1.2** SSL-сертификат (Caddy / Let's Encrypt)
- [ ] **1.3** Лендинг (1 экран):
- Заголовок + слоган
- Краткое описание идеи
- Email для связи / форма подписки на ранний доступ
- [ ] GitHub репозиторий: `github.com/evgenystor/c7e` или `github.com/evgenystor/chronicle`
- [ ] README.md с:
- [ ] **1.4** GitHub репозиторий: `github.com/evgenystor/c7e` или `github.com/evgenystor/chronicle`
- [ ] **1.5** README.md с:
- ASCII-арт логотипом
- Описанием проекта
- Roadmap
@@ -59,14 +77,14 @@
**Цель:** Дать тех-блогерам редактор, в котором можно писать статьи с кодом
- [ ] Веб-редактор (React / Vue)
- [ ] Интеграция Monaco Editor (как в VS Code)
- [ ] Поддержка языков: Python, JavaScript, Go, Rust, Bash, SQL
- [ ] Темы оформления (светлая / тёмная)
- [ ] Блоки кода с кнопкой «скопировать»
- [ ] Markdown-режим + WYSIWYG превью
- [ ] Сохранение черновиков (локально / в GitHub)
- [ ] Drag-and-drop изображений
- [ ] **2.1** Веб-редактор (React / Vue)
- [ ] **2.2** Интеграция Monaco Editor (как в VS Code)
- [ ] **2.3** Поддержка языков: Python, JavaScript, Go, Rust, Bash, SQL
- [ ] **2.4** Темы оформления (светлая / тёмная)
- [ ] **2.5** Блоки кода с кнопкой «скопировать»
- [ ] **2.6** Markdown-режим + WYSIWYG превью
- [ ] **2.7** Сохранение черновиков (локально / в GitHub)
- [ ] **2.8** Drag-and-drop изображений
**Результат:** Можно написать статью с кодом, и она будет выглядеть как в IDE
@@ -76,12 +94,12 @@
**Цель:** Объединить редактор и архив в единую систему
- [ ] Написанное в редакторе → автоматически в архив (Markdown-файлы)
- [ ] Импорт постов из Telegram (через Phase 0)
- [ ] Редактирование старых постов из архива
- [ ] Поиск по всему контенту (full-text)
- [ ] Теги и категории
- [ ] Версионность постов (как Git: история изменений, откат)
- [ ] **3.1** Написанное в редакторе → автоматически в архив (Markdown-файлы)
- [ ] **3.2** Импорт постов из Telegram (через Phase 0)
- [ ] **3.3** Редактирование старых постов из архива
- [ ] **3.4** Поиск по всему контенту (full-text)
- [ ] **3.5** Теги и категории
- [ ] **3.6** Версионность постов (как Git: история изменений, откат)
**Результат:** Весь контент в одном месте, можно редактировать и искать
@@ -91,17 +109,17 @@
**Цель:** Публикация в несколько соцсетей одной кнопкой
- [ ] Интеграция с Telegram Bot API (публикация в канал)
- [ ] Интеграция с VK API
- [ ] Интеграция с Habr API (или парсинг формы)
- [ ] Интеграция с Medium API
- [ ] Календарь публикаций
- [ ] Отложенные посты (очередь)
- [ ] Адаптация контента под платформы:
- [ ] **4.1** Интеграция с Telegram Bot API (публикация в канал)
- [ ] **4.2** Интеграция с VK API
- [ ] **4.3** Интеграция с Habr API (или парсинг формы)
- [ ] **4.4** Интеграция с Medium API
- [ ] **4.5** Календарь публикаций
- [ ] **4.6** Отложенные посты (очередь)
- [ ] **4.7** Адаптация контента под платформы:
- Telegram: коротко, без сложных блоков
- Habr: полная версия с кодом
- VK: адаптированный текст
- [ ] Превью: как пост будет выглядеть на каждой платформе
- [ ] **4.8** Превью: как пост будет выглядеть на каждой платформе
**Результат:** Написал один раз → опубликовал везде с адаптацией
@@ -111,14 +129,14 @@
**Цель:** Превратить Chronicle в полноценную платформу
- [ ] Сбор статистики по платформам (просмотры, реакции, комментарии)
- [ ] Аналитика вовлеченности
- [ ] Лучшее время для постов (рекомендации)
- [ ] Сбор комментариев с платформ обратно в Chronicle
- [ ] Командная работа (несколько авторов)
- [ ] API для разработчиков
- [ ] Мобильное приложение (черновики, заметки)
- [ ] White-label решения для брендов
- [ ] **5.1** Сбор статистики по платформам (просмотры, реакции, комментарии)
- [ ] **5.2** Аналитика вовлеченности
- [ ] **5.3** Лучшее время для постов (рекомендации)
- [ ] **5.4** Сбор комментариев с платформ обратно в Chronicle
- [ ] **5.5** Командная работа (несколько авторов)
- [ ] **5.6** API для разработчиков
- [ ] **5.7** Мобильное приложение (черновики, заметки)
- [ ] **5.8** White-label решения для брендов
**Результат:** Полноценная операционная система для технического креатора
@@ -152,14 +170,327 @@
---
## 📝 Детали задач Фазы 0
### Задача 0.7: Извлечение тегов (#хэштеги)
**Проблема:** В Telegram теги — это просто текст с `#`. Для Hugo нужно извлечь их и добавить во front-matter.
**Реализация:**
- Парсинг текста поста на наличие `#хэштегов` (regex: `#[\wа-яА-ЯёЁ\d_]+`)
- Извлечение в список `tags: [tag1, tag2, tag3]`
- Добавление во front-matter:
```yaml
---
message_id: 1044
date: 2026-03-05T18:05:47+00:00
author: Дед in АйТи
tags: [linux, debian, usermod, sudo]
---
```
- Удаление хэштегов из текста поста (опционально)
**Результат:** Hugo сможет генерировать страницу `/tags/linux/` со списком всех постов с этим тегом.
---
### Задача 0.8: Обработка медиа для Hugo
**Проблема:** Hugo имеет свои shortcodes для встраивания медиа. Нужно использовать их вместо стандартного Markdown.
**Hugo shortcodes для медиа:**
**Изображения:**
```markdown
{{< figure src="photo.jpg" alt="Описание" title="Заголовок" >}}
```
**Видео:**
```markdown
{{< video src="video.mp4" >}}
```
**Аудио:**
```markdown
{{< audio src="audio.mp3" >}}
```
**Документы:**
```markdown
{{< download-file href="document.pdf" title="Скачать PDF" >}}
```
**Реализация:**
- При генерации `index.md` проверять тип медиа
- Вместо `![caption](file.jpg)` использовать Hugo shortcodes
- Для изображений: извлекать `alt`, `title` из caption
- Для видео/аудио: определять формат и подбирать shortcode
**Пример выходного файла:**
```markdown
---
message_id: 1042
date: 2026-03-05T07:09:24+00:00
author: Дед in АйТи
media_files:
- filename: photo_20260305_070924.jpg
type: photo
caption: "Скриншот конфига"
---
{{< figure src="photo_20260305_070924.jpg" alt="Скриншот конфига" >}}
Текст поста...
```
**Альтернатива:** Оставить стандартный Markdown `![]()` — Hugo тоже его понимает. Shortcodes дают больше контроля (lightbox, подписи, размеры).
---
## 📝 Найденные проблемы при полном тестировании (992 поста)
### Задача 0.9: Прямые ссылки на посты
**Проблема:** При скачивании репоста сохраняется название канала и ID поста, но нет прямой ссылки на оригинал.
**Реализация:**
- Для репостов: `original_post_url: https://t.me/channel_name/12345`
- Для канала: `channel_url: https://t.me/dedinit`
- Сохранять в front-matter для каждой записи
**Пример:**
```yaml
---
message_id: 1015
repost_from: 987
repost_channel: "Some Channel"
original_post_url: "https://t.me/somechannel/987"
channel_url: "https://t.me/dedinit/1015"
---
```
---
### Задача 0.10: Посты без index.md
**Проблема:** Пост 987 — в папке только mp3 файл, index.md отсутствует.
**Причина:** Вероятно, ошибка при записи файла или пост был удалён/изменён.
**Решение:**
- Проверять наличие index.md после записи
- Создавать минимальный front-matter даже если текст пуст
- Логировать ошибки записи
---
### Задача 0.11: Видео-кружки и .bin файлы
**Проблема:** Пост 988 — видео-кружок сохранился как `.bin` файл.
**Причина:** Telethon не определяет расширение для video_note.
**Решение:**
- Определять тип по MIME (video/mp4 для кружков)
- Переименовывать `.bin` → `.mp4` после скачивания
- Опционально: конвертировать в нормальное видео через ffmpeg
---
### Задача 0.12: Отчёт о неуспешно скачанных файлах
**Проблема:** Файлы по таймауту или размеру пропускаются, но не сохраняется информация для последующей дозагрузки.
**Реализация:**
- Создавать `2big2get.md` (уже есть) + `to_download_later.md`
- Сохранять прямые ссылки на файлы: `https://t.me/dedinit/123/file.mp4`
- Добавить команду для дозагрузки: `python run_archiver.py --resume-downloads to_download_later.md`
---
### Задача 0.13: Временная зона (GMT+3 Москва)
**Проблема:** `date: '2026-01-18T08:11:24+00:00'` — UTC вместо Москвы (GMT+3).
**Пост был в 11:11 по Москве, а указано 08:11 UTC.**
**Решение:**
- Определять часовой пояс канала/автора
- Конвертировать время: `date.astimezone(timezone('Europe/Moscow'))`
- Сохранять с правильным offset: `+03:00`
---
### Задача 0.14: Прямые ссылки на файлы
**Проблема:** При таймауте нет ссылки для последующей загрузки.
**Решение:**
- Telethon может получить прямую ссылку: `await client.download_media(..., file=file_path)` → сохранить URL
- Добавлять во front-matter: `download_url: "https://..."`
- Для дозагрузки использовать список URL
---
### Задача 0.15: Размер файла = 0 во front-matter
**Проблема:** `size: 0` вместо реального размера.
**Причина:** Размер не проставляется после скачивания.
**Решение:**
- Брать размер из атрибутов Telegram: `doc.size`
- Либо проверять размер файла после записи: `Path(filepath).stat().st_size`
---
### Задача 0.16: Расширенный front-matter
**Проблема:** Нет ссылок на канал, автора, оригинальный пост.
**Текущий front-matter:**
```yaml
author: Дед in АйТи
```
**Нужно:**
```yaml
author: Дед in АйТи
author_username: "@dedinit"
channel_title: "Дед in АйТи"
channel_username: "@dedinit"
channel_url: "https://t.me/dedinit"
post_url: "https://t.me/dedinit/1234"
original_post_url: "https://t.me/otherchannel/987" # для репостов
```
---
### Задача 0.17: Многопоточное скачивание медиа
**Идея:** Скачивать медиафайлы параллельно (5-10 потоков).
**Оценка:**
- Telethon поддерживает `asyncio.gather()` для параллельных загрузок
- Ограничение: Telegram может блокировать при слишком частых запросах
- Реалистично: 3-5 одновременных загрузок
**План:**
- Создать очередь на скачивание
- Запускать 3-5 корутин параллельно
- Соблюдать rate limits (паузы между запросами)
---
### Задача 0.18: Валидация скачанных файлов
**Проблема:** Файл 618 — голосовуха 384 КБ, но нет проверки целостности.
**Решение:**
- Проверять размер после скачивания (сравнить с ожидаемым)
- Проверять заголовки файлов (magic bytes)
- Логировать битые файлы в `corrupted.md`
---
### Задача 0.19: Очередь на скачивание + многопоточность
**Идея:** Разделить на 2 прохода:
1. Сбор всех URL файлов (быстро)
2. Многопоточная загрузка по списку
**План:**
- Первый проход: собрать все `download_url`
- Сохранить в `queue.json`
- Второй проход: загружать параллельно (3-5 потоков)
- Resume: продолжать с места обрыва
---
### Задача 0.20: Аудио-файлы для Hugo
**Проблема:** Голосовые сообщения без метаданных (длительность, waveform).
**Вопросы:**
- Нужна ли длительность во front-matter? (`duration: 45` секунд)
- Как отобразить waveform в Hugo?
**Решение:**
- Извлекать длительность из атрибутов Telegram: `doc.attributes.duration`
- Для waveform: использовать Hugo shortcode с JS-библиотекой (wavesurfer.js)
- Пример: `{{< audio-player src="file.ogg" waveform="true" >}}`
---
### Задача 0.21: Resume прерванной архивации
**Проблема:** 2 часа на 1000 постов — при обрыве начинать заново.
**Решение:**
- Сохранять последний обработанный ID: `last_message_id: 992`
- Команда: `python run_archiver.py --resume`
- Пропускать уже скачанные посты (дедупликация по ID)
---
### Задача 0.22: Формат тегов для Hugo
**Проблема:** Сейчас:
```yaml
tags:
- 1с
- debian
```
Hugo предпочитает:
```yaml
tags: ["1с", "debian", "postgres"]
```
**Решение:**
- Изменить формат вывода YAML
- Протестировать оба варианта в Hugo
---
### Задача 0.23: Обработка трансляций
**Проблема:** Посты 122, 120 — трансляции без текста, только метаданные.
**Вопросы:**
- Что приходит от Telegram для streaming messages?
- Можно ли извлечь длительность, участников, тему?
**Решение:**
- Изучить `message.media` для трансляций
- Сохранять метаданные во front-matter
- Создавать index.md с информацией о трансляции
---
### Задача 0.24: Голосовые сообщения
**Проблема:** Голосовухи скачиваются как `.bin` или `.ogg`.
**Вопросы:**
- Как определить формат (ogg/mp3)?
- Нужны ли метаданные (длительность, размер)?
**Решение:**
- Определять по MIME: `audio/ogg` → `.ogg`, `audio/mp3` → `.mp3`
- Извлекать длительность из атрибутов
- Сохранять во front-matter: `duration: 45, size: 127359`
---
## 🚀 Ближайшие шаги (эта неделя)
- [x] DNS для `c7e.ru` настроен
- [ ] SSL-сертификат (Caddy)
- [ ] GitHub репозиторий
- [ ] README.md с ASCII-логотипом
- [ ] Лендинг (1 экран) на `c7e.ru`
- [ ] Начать Phase 0: парсинг Telegram
- [x] **1.1** DNS для `c7e.ru` настроен
- [ ] **1.2** SSL-сертификат (Caddy)
- [ ] **1.4** GitHub репозиторий
- [ ] **1.5** README.md с ASCII-логотипом
- [ ] **1.3** Лендинг (1 экран) на `c7e.ru`
- [ ] **0.1** Начать Phase 0: парсинг Telegram
---