Compare commits

..

2 commits

Author SHA1 Message Date
320f74b84e wip: generate RSS feed
Some checks failed
/ test-build (push) Failing after 20s
2025-07-17 23:52:56 -04:00
4f8979ae9b fixed incorrect codeberg links in readme 2025-07-17 23:52:47 -04:00
3 changed files with 31 additions and 13 deletions

View file

@ -1,5 +1,5 @@
import shutil import shutil
from datetime import date, datetime from datetime import date
from pathlib import Path from pathlib import Path
from feedgen.feed import FeedGenerator from feedgen.feed import FeedGenerator
@ -101,9 +101,11 @@ class ZonaBuilder:
items.append(item) items.append(item)
self.items = items self.items = items
def generate_feed(self) -> str: def generate_feed(self) -> bytes:
post_list = self._get_post_list() post_list = self._get_post_list()
config = self.config.feed config = self.config.feed
if config.link.endswith("/"):
config.link = config.link[:-2]
fg = FeedGenerator() fg = FeedGenerator()
fg.id(config.link) fg.id(config.link)
fg.title(config.title) fg.title(config.title)
@ -112,7 +114,11 @@ class ZonaBuilder:
"email": config.author.email, "email": config.author.email,
} }
fg.author(author) fg.author(author)
fg.link(href=config.link, rel="self") fg.link(
href=f"{config.link}/{config.path}",
rel="self",
type="application/rss+xml",
)
fg.language(config.language) fg.language(config.language)
fg.description(config.description) fg.description(config.description)
@ -120,14 +126,18 @@ class ZonaBuilder:
assert post.metadata assert post.metadata
fe = fg.add_entry() # pyright: ignore[reportUnknownVariableType] fe = fg.add_entry() # pyright: ignore[reportUnknownVariableType]
fe.id(f"{config.link}{util.normalize_url(post.url)}") # pyright: ignore[reportUnknownMemberType] fe.id(f"{config.link}{util.normalize_url(post.url)}") # pyright: ignore[reportUnknownMemberType]
fe.link( # pyright: ignore[reportUnknownMemberType]
href=f"{config.link}{util.normalize_url(post.url)}"
)
fe.title(post.metadata.title) # pyright: ignore[reportUnknownMemberType] fe.title(post.metadata.title) # pyright: ignore[reportUnknownMemberType]
fe.author(author) # pyright: ignore[reportUnknownMemberType] fe.author(author) # pyright: ignore[reportUnknownMemberType]
fe.description(post.metadata.description) # pyright: ignore[reportUnknownMemberType] desc = post.metadata.description
fe.description(desc) # pyright: ignore[reportUnknownMemberType]
date = post.metadata.date date = post.metadata.date
# ISSUE: lack of timezone causes an error, need to add TZ config option fe.pubDate(date) # pyright: ignore[reportUnknownMemberType]
dt = datetime.combine(date, datetime.min.time()) out: bytes = fg.rss_str(pretty=True) # pyright: ignore[reportUnknownVariableType]
fe.pubDate(dt) # pyright: ignore[reportUnknownMemberType] assert isinstance(out, bytes)
return fg.rss_str(pretty=True) # pyright: ignore[reportUnknownVariableType] return out
def _get_post_list(self) -> list[Item]: def _get_post_list(self) -> list[Item]:
assert self.items assert self.items
@ -218,4 +228,4 @@ class ZonaBuilder:
logger.debug("Building...") logger.debug("Building...")
self._build() self._build()
self.fresh = False self.fresh = False
# print(self.generate_feed()) print(self.generate_feed().decode())

View file

@ -1,7 +1,7 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import tzinfo from datetime import datetime, tzinfo
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from zoneinfo import ZoneInfo from zoneinfo import ZoneInfo
@ -10,7 +10,6 @@ import yaml
from dacite import Config as DaciteConfig from dacite import Config as DaciteConfig
from dacite import from_dict from dacite import from_dict
from zona import util
from zona.log import get_logger from zona.log import get_logger
logger = get_logger() logger = get_logger()
@ -32,9 +31,17 @@ def find_config(start: Path | None = None) -> Path | None:
SitemapConfig = dict[str, str] SitemapConfig = dict[str, str]
@dataclass
class PostDefaultsConfig:
description: str = "A blog post"
@dataclass @dataclass
class BlogConfig: class BlogConfig:
dir: str = "blog" dir: str = "blog"
defaults: PostDefaultsConfig = field(
default_factory=PostDefaultsConfig
)
@dataclass @dataclass
@ -86,7 +93,7 @@ class AuthorConfig:
class FeedConfig: class FeedConfig:
enabled: bool = True enabled: bool = True
timezone: tzinfo = field(default_factory=lambda: ZoneInfo("UTC")) timezone: tzinfo = field(default_factory=lambda: ZoneInfo("UTC"))
path: str = "feed.xml" path: str = "rss.xml"
link: str = "https://example.com" link: str = "https://example.com"
title: str = "Zona Website" title: str = "Zona Website"
description: str = "My zona website." description: str = "My zona website."

View file

@ -17,7 +17,7 @@ from zona.config import ZonaConfig
class Metadata: class Metadata:
title: str title: str
date: datetime date: datetime
description: str | None description: str
show_title: bool = True show_title: bool = True
show_date: bool = True show_date: bool = True
show_nav: bool = True show_nav: bool = True
@ -70,6 +70,7 @@ def parse_metadata(
defaults = { defaults = {
"title": zona.util.filename_to_title(path), "title": zona.util.filename_to_title(path),
"date": datetime.fromtimestamp(path.stat().st_ctime), "date": datetime.fromtimestamp(path.stat().st_ctime),
"description": config.blog.defaults.description,
} }
meta = {**defaults, **raw_meta} meta = {**defaults, **raw_meta}
meta["date"] = parse_date(meta.get("date"), config.feed.timezone) meta["date"] = parse_date(meta.get("date"), config.feed.timezone)