mirror of
https://gitverse.ru/kpa39l/chronicle.nixg.ru.git
synced 2026-09-29 09:55:08 +00:00
Phase 0 MVP: Telegram Archiver fully functional (992 posts tested)
This commit is contained in:
+379
-48
@@ -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` проверять тип медиа
|
||||
- Вместо `` использовать 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
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user