Перейти к основному содержанию

freshgo 0.3.14: месяц спустя это уже не FreshRSS

14 ноября 2026

В этой статье

Первый коммит freshgo сделан 6 октября. Задумывался он как порт FreshRSS на Go1, а к версии 0.3.9 в нём было уже много своего2. С тех пор вышли 0.3.10–0.3.13 и две предварительные версии 0.3.14, всего 39 коммитов. Сегодня вышла 0.3.14-rc.2, и на моём сервере работает уже она.

В этот раз я поставил FreshRSS 1.30.1 и freshgo рядом, на одних и тех же лентах, и снял одинаковые экраны в обоих. Данные в freshgo пришли из этого же FreshRSS командой freshgo import, так что статьи совпадают.

Что сделано сегодня

Все три изменения выросли из одного наблюдения: страница «Непрочитанные» открывалась чуть дольше секунды. Это мало, но задержку видно3.

Подготовка «Непрочитанных». Пока открыта другая страница, браузер заранее скачивает «Непрочитанные» и держит ответ в памяти. При переходе сервер всё равно проверяет вход и заново собирает страницу. Если она совпала с заготовленной, он отвечает 304 без тела, и браузер показывает то, что уже скачал. Если что-то изменилось, приходит обычный ответ. Заготовка одна, не больше 2 МиБ, живёт 15 секунд. На скрытой вкладке и при экономии трафика её не делают.

Замер шёл в Chrome на 250 непрочитанных статьях по 6 КБ, со связью, искусственно замедленной до 40 мс задержки и 1 МБ/с. Переход на «Непрочитанные» внутри читалки до готового кадра занимал 1108 мс, теперь 185 мс (медианы из пяти прогонов). Прямое открытие страницы по адресу не ускорилось: те же 898 КБ надо скачать. Теперь список появляется целиком, когда разобран, а не заполняется строками по мере загрузки.

Подгрузка следующей страницы. Раньше сто новых статей вставлялись в список по одной, теперь одним блоком, собранным вне документа. Время подгрузки от этого не изменилось, его по-прежнему определяет сеть. Меняется то, что список больше не растёт на глазах.

Две находки по дороге. Пока шла проверка, упали два теста, которые к изменению отношения не имели. Форма настроек ленты на экране шириной 360 точек уезжала вбок на 6 точек: блок с выбором значка не сжимался уже ширины своего поля для файла. Хватило одного свойства CSS, min-width: 04. Второй тест проверял, что разбор огромной ленты укладывается в 20 секунд, и падал, когда машина была занята другими тестами. Теперь он не смотрит на часы: разбирает документы двух размеров, восьмикратно отличающиеся, и сравнивает, во сколько раз выросли процессорное время и выделенная память. Больше 24 раз означает, что разбор стал квадратичным5.

Что появилось с 0.3.9

Вход по passkey. В профиле можно завести passkey для каждого устройства, и вход проходит по отпечатку, лицу или PIN-коду, без пароля и без кода из приложения. Администратор может отключить вход по паролю совсем. Пароли для приложений при этом продолжают работать, а freshgo user passwd для администратора включает вход по паролю обратно, если все passkeys потеряны.

Страница входа freshgo с кнопкой входа по passkey

Перевод для приложений. Перевод статьи языковой моделью был в веб-интерфейсе. Теперь его можно запросить и через Google Reader API, отдельным расширением по адресу /api/freshgo/translation. Перевод хранится на сервере, так что переведённая на телефоне статья в браузере уже переведена, и наоборот. Первым клиентом стал мой Android-клиент Brook. Уведомления о прочитанных и отмеченных статьях тоже теперь приходят в приложения, а не только в браузер.

Загрузки стали аккуратнее. Cookie, логин с паролем и дополнительные заголовки ленты уходят только на её собственный сайт, даже если статья или найденная на странице лента лежат на другом. Проверка адресов отсекает ещё несколько зарезервированных диапазонов IPv4 и IPv6. Адрес клиента из X-Forwarded-For теперь берётся справа, с пропуском своих прокси, и подделать его, дописав адрес слева, нельзя. Google Reader API отказывает пользователю без пароля для приложений: раньше его токен зависел только от соли установки6.

Мелочи:

  • категория и метка с именем, отличающимся только регистром, больше не заводятся;
  • форма ленты не сохраняет CSS-селектор или фильтр с ошибкой, а раньше ошибка всплывала только при обновлении;
  • экспорт собирается во временном файле: на 3000 статей по 30 КБ память растёт на 43 МБ вместо 273 МБ;
  • ссылки из текста статьи открываются в новой вкладке.

Чем freshgo теперь отличается от FreshRSS

Хранение, импорт, язык поиска и Google Reader API остались совместимыми, клиенты переезда не замечают. Всё остальное разошлось.

Чтение. FreshRSS показывает дерево лент слева и список с кнопками над ним. В freshgo дерево свёрнуто в шапку потока и открывается клавишей t, а строка статьи несёт ещё и начало текста.

FreshRSS 1.30.1: категория «Новости»

freshgo 0.3.14-rc.2: та же категория

Статья в freshgo раскрывается на месте, как в Google Reader. Действия стоят между заголовком и текстом: прочитано, полный текст, оригинал, перевод, пересказ, метки.

FreshRSS: раскрытая статья

freshgo: та же статья

Телефон. FreshRSS на узком экране обрезает заголовки в одну строку. freshgo переносит их целиком, а внизу держит панель: предыдущая статья, прочитано, звёздочка, следующая.

Обновление лент. Во FreshRSS у ленты период обновления по умолчанию общий. freshgo опрашивает ленту так часто, как она публикует, учитывает Cache-Control и Expires её сервера и после сбоев ждёт дольше. На странице настроек ленты это пункт «Автоматически, по частоте публикаций».

FreshRSS: настройки ленты

freshgo: настройки той же ленты

На этом же стенде нашлось отличие, которого я не ждал. FreshRSS не прочитал ленту research.swtch.com: её сервер отдаёт документ с типом text/plain, и FreshRSS написал в журнал, что ленты по адресу нет. freshgo ту же ленту прочитал и забрал из неё 24 статьи.

Остальное, чего во FreshRSS нет, перечислю списком:

  • полный текст статьи без CSS-селектора, по клавише f для одной статьи, через настоящий браузер для сайтов за проверкой Cloudflare;
  • перевод, пересказ и подсказки меток языковой моделью;
  • картинки статей через сервер, чтобы их сайты не видели читателя;
  • переходы без перезагрузки страницы и счётчики, которые обновляются сами, при этом всё работает и без JavaScript;
  • палитра команд по Ctrl+K и управление с клавиатуры;
  • Web Push, ежедневное письмо с непрочитанным, сохранение в Linkding;
  • второй фактор (TOTP), passkeys, вход через OpenID Connect;
  • импорт из Miniflux и Tiny Tiny RSS, Fever API;
  • freshgo backup, restore -check и doctor для того, кто держит сервер.

Что дальше

0.3.14 пока предварительная версия. Если за несколько дней на моём сервере ничего не всплывёт, она выйдет как обычная. Проект по-прежнему проверен одной установкой, моей, а PHP-расширения FreshRSS в нём не работают. Код и инструкции лежат в juev/freshgo, список изменений по версиям на странице релизов7.


  1. freshgo: порт FreshRSS на Go, который перестал быть портом. ↩︎

  2. freshgo 0.3: что появилось за девять дней. ↩︎

  3. Issue #210 и замер: условия, все цифры и ограничения. ↩︎

  4. Issue #213 и разбор. ↩︎

  5. Issue #212 и описание проверки. ↩︎

  6. Так же поступает Miniflux 2.3.4. Клиент через ClientLogin такой токен и раньше не получал, но сервер его принимал. ↩︎

  7. Releases juev/freshgo. ↩︎