Сделал собственный newsfeeds aggregator

Что: b10a0aa678fd8759885c9af0d9abba7bafd88efb

Когда: 2022-02-17 22:39:04+03:00

Темы: go mail redo zsh

Сделал собственный newsfeeds aggregator

http://www.feeder.stargrave.org/
http://www.feeder.stargrave.org/Usage.html
Видимо не давал моей голове покоя sfeed
(571ce0c3d2c17e5562ff41866ae4948c701cf54b) и я проснулся с мыслью о том
что надобно или написать свой или понять что это отнюдь не тривиальная
задача. В итоге получилось гораздо проще чем ожидал, причём работает
существенно быстрее Newsboat при парсинге/индексации за счёт
распараллеливания.

Вовсю переиспользуются существующие инструменты. curl, как оказалось,
прекрасно умеет самостоятельно отправлять If-Modified-Since и ETag
заголовки, храня эту информацию в отдельном для ETag-а файле и mtime.
Прекрасно поддерживает сжатый Content-Encoding, в том числе Zstandard.

Хранить сообщения из feed-ов я решил в Maildir-ах и использовать MUA в
качестве интерфейса для этого. Каждый feed это отдельная директория, по
совместительству Maildir, в которой и состояние для скачивания curl-ом
хранится.

Использую github.com/mmcdole/gofeed библиотеку для парсинга всевозможных
форматов. Поддерживает даже JSON, которого в Newsboat не было. Она
просто выплёвывает простые структуры идентичные для любых форматов
feed-ов, из которой я руками формирую почтовые MIME сообщения. Тело
сообщений -- только HTML. Ибо даже я в своих feed-ах его использую для
простоты.

Названия файлов для писем: SHA512/2(title+date). Изначально вообще
использовал дату обновления/публикация для имён, но, оказалось, очень
много feed-ов вообще не несут никакой информации о датах. А ещё могут
иметь одну и ту же дату для кучи разных записей. Честно выставляю mtime
и для файлов и для Maildir директорий, чтобы MUA понимал когда последний
раз были сообщения в feed-е.

Всё попадает в new/, что в Mutt-е честно будет показываться с флагом
"N". Всё что не прочтённое, но уже и не новое, будет old-ом ("O").
feed2mdir утилита умеет ограничивать кол-во обрабатываемых записей.
Удалять старые записи тривиально можно сортировкой по mtime и отсеканию
ненужного множества файлов (rm *(om[101,-1])).

Распараллеливать скачивание можно либо через redo, либо через parallel:

    $ parallel "redo {}/feed.download" ::: feeds/*
    $ parallel "redo {}/feed.parse" ::: feeds/*

С redo вышла засада: сама по себе команда redo выполняет цели без
распараллеливания, последовательно, чтобы можно было написать: redo lib
install clean. Так делает не только goredo. Но redo-ifchange делает
проверку на "надо ли это вообще собирать", а так как явно зависимостей
никаких нет, то он ничего выполнять и не будет. Я добавил в goredo "-f"
флаг для redo-ifchange, но вообще думаю что redo тут наверное вообще
излишен. Честно для tracking-а зависимостей он использует для решения
надо ли запускать feed2mdir и для пересборки mutt.rc файла, если список
feed-ов и их названий поменялся. Но то, что feed.download, feed.parse,
feed.clean являются виртуальными целями, как будто присутствующими в
директории -- мне эстетически нравится.

Mutt запускается в режиме броузера почтовых ящиков. Для всего этого дела
автоматически генерируется mutt.rc, в котором все feed-и прописаны в
качестве почтовых ящиков с человеческими названиями. Сортировка по дате,
быстрый переход к списку feed-ов/ящиков, компактные форматы index-ов,
отображение авторов, категорий и ссылок новостей в виде X--заголовков
сообщений.

Можно запускать (что я и делаю) mu index для индексации этого всего и
добавлены макросы в Mutt для быстрого вызова поиска и просмотра
результатов. Так как в результатах поиска мешанина из элементов разных
feed-ов, то названия feed-ов в этом индексе тоже отображаются. Я привык
в Newsboat нажимать "A" для помечания всех элементов текущего feed-а
прочтёнными -- легко было написать аналогичный макрос и для Mutt.

В общем всё это получилось шустро работающим, сильно гибким из-за куда
более мощных инструментов. Я думал что подвохов будет гораздо больше.
Хотя по сути то самое главное это парсинг и раскладывание в БД: это
делается на Go. redo скорее не нужен будет -- можно будет заменить
только parallel.

оставить комментарий

Сгенерирован: SGBlog 0.34.0