rss
RSS
Концепция
Любая заметка — это RSS лента. Markdown AST страницы преобразуется в RSS feed.
Каждая ссылка в заметке становится RSS item. Заголовок ссылки → <title>, URL → <link>. Если ссылка ведёт на внутреннюю заметку — подтягиваются её метаданные (description, created_at).
URL схема
/path/to/note.rss.xml — RSS фид для любой заметки.
Преобразование Markdown AST → RSS
Парсим AST заметки, извлекаем все ссылки. Порядок items = порядок ссылок в документе.
Каждая ссылка → RSS item:
<title>— текст ссылки<link>— URL (абсолютный)<description>— description целевой заметки (если внутренняя ссылка)<pubDate>—rss_created_atилиcreated_atцелевой заметки
Frontmatter (опционально)
| Поле | Тип | Описание |
|---|---|---|
rss_title |
string |
Заголовок фида (по умолчанию title заметки) |
rss_description |
string |
Описание фида (по умолчанию description заметки) |
Реализация
Структура кода
| Компонент | Путь | Описание |
|---|---|---|
| Package | internal/rssfeed/ |
Генерация RSS 2.0 XML |
| Middleware | cmd/server/main.go:handleRSSFeed() |
Перехват *.rss.xml запросов |
| Config | model.SiteConfig.EnableRSS |
Булев конфиг (default true) |
| Frontmatter | NoteView.RSSTitle, RSSDescription |
Переопределение заголовка/описания |
Middleware: handleRSSFeed
cmd/server/main.go:1763-1796
func (a *app) handleRSSFeed(req *appreq.Request) bool {
// 1. Проверка суффикса .rss.xml
if !strings.HasSuffix(req.Path, ".rss.xml") {
return false
}
// 2. Проверка конфига enable_rss
cfg := a.SiteConfig(context.Background())
if !cfg.EnableRSS {
return false
}
// 3. Извлечение пути заметки
notePath := strings.TrimSuffix(req.Path, ".rss.xml")
// 4. Поиск заметки в LiveNoteViews
notes := a.LiveNoteViews()
note := notes.GetByPath(notePath)
if note == nil {
return false
}
// 5. Генерация RSS
xmlBytes, err := rssfeed.Generate(note, a.PublicURL(), notes)
// 6. Отдача XML
req.Req.SetContentType("application/rss+xml; charset=utf-8")
req.Req.SetBody(xmlBytes)
return true
}
Generator: rssfeed.Generate()
internal/rssfeed/rssfeed.go:50
Входные данные:
note *model.NoteView— заметка для конвертацииpublicURL string— base URL сайтаnotes *model.NoteViews— для резолва internal links
Алгоритм:
-
Извлечение ссылок (
extractLinks()строка 96):- Обход AST заметки через
ast.Walk() - Поиск
wikilink.Nodeиast.KindLink - Skip embedded images/videos
- Для wikilinks: резолв через
note.ResolvedLinks[target] - Для markdown links: используется
l.Destinationкак есть
- Обход AST заметки через
-
Построение feed:
feedTitle := note.RSSTitle != "" ? note.RSSTitle : note.Title feedDesc := note.RSSDescription != "" ? note.RSSDescription : note.Description -
Генерация items:
- Каждая ссылка →
RSSItem - Для internal links: обогащение метаданными (
enrichItem()строка 191)
- Каждая ссылка →
-
Сериализация в XML
Обогащение внутренних ссылок
enrichItem() (строка 191-204):
func enrichItem(item *RSSItem, notes *model.NoteViews, path string) {
target := notes.GetByPath(path)
if target == nil {
return
}
if target.Description != nil {
item.Description = *target.Description
}
if !target.CreatedAt.IsZero() {
item.PubDate = target.CreatedAt.Format(time.RFC1123Z)
}
}
Метаданные целевой заметки:
Description→<description>CreatedAt→<pubDate>(RFC1123Z format)
AST Walking
Поддерживаются два типа ссылок:
| Тип | AST Node | Пример | Обработка |
|---|---|---|---|
| Wikilink | wikilink.Node |
[[target|text]] |
Резолв через ResolvedLinks |
| Markdown link | ast.KindLink |
[text](url) |
URL используется как есть |
Skip rules:
- Embedded media:
![[image.png]]— пропускается (строка 116) - Image links:
[img](file.jpg)— пропускается (строка 146)
Конфиг: enable_rss
Таблица: config_bools (строка value_id = 'enable_rss')
Загружается в app.SiteConfig() (cmd/server/main.go:521-558):
cfg := model.SiteConfig{
EnableRSS: true, // default
}
bools, err := a.AllLatestConfigBools(ctx)
for _, b := range bools {
if b.ValueID == "enable_rss" {
cfg.EnableRSS = b.Value
}
}
Frontmatter поля
| Поле | Тип | Default | Использование |
|---|---|---|---|
rss_title |
string |
note.Title |
Заголовок RSS канала |
rss_description |
string |
note.Description |
Описание RSS канала |
Парсятся через goldmark-meta в mdloader, хранятся в NoteView.RawMeta.
Формат RSS 2.0
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>Feed Title</title>
<link>https://example.com/page</link>
<description>Feed description</description>
<item>
<title>Link text</title>
<link>https://example.com/target</link>
<description>Target description</description>
<pubDate>Mon, 02 Jan 2006 15:04:05 -0700</pubDate>
<guid>https://example.com/target</guid>
</item>
</channel>
</rss>
Sitemap.xml
Отдельная задача — генерация sitemap.xml из всех опубликованных страниц.