1
0
Fork 0
mirror of https://codeberg.org/Reuh/feather.git synced 2025-10-27 18:19:32 +00:00

fix: handle negative timestamps

This commit is contained in:
Étienne Fildadut 2025-10-17 13:57:08 +02:00
parent 54fa01d4e5
commit 48c2c0f850
2 changed files with 24 additions and 12 deletions

View file

@ -4,7 +4,7 @@ from __future__ import annotations
import re import re
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from ttrss.client import TTRClient from ttrss.client import TTRClient, Headline
import google_reader import google_reader
from feather.config import Config from feather.config import Config
@ -146,11 +146,19 @@ class GReaderArticle(Article):
# several API references I've seen didn't mention canonical, but alternate seems to also be the article link (?) and should be an ok fallback # several API references I've seen didn't mention canonical, but alternate seems to also be the article link (?) and should be an ok fallback
self.article_url = item_content.alternate[0].href self.article_url = item_content.alternate[0].href
self._compute_json_path() self.json_path = self._get_json_path()
## Tiny Tiny RSS API ## ## Tiny Tiny RSS API ##
# Monkey patch Headline.__init__ to skip timestamp to datetime conversion
# Articles may have a negative timestamp and Python's datetime.fromtimestamp doesn't like that, so instead we keep the timestamp and deal with the issue in data.py/format_datetime
def Headline_init(self, attr, client):
super(Headline, self).__init__(attr, client)
Headline.__init__ = Headline_init
class TTRSession(ClientSession): class TTRSession(ClientSession):
"""Tiny Tiny RSS API client""" """Tiny Tiny RSS API client"""
@ -234,8 +242,8 @@ class TTRArticle(Article):
self.unread = article.unread self.unread = article.unread
self.title = article.title self.title = article.title
self.published = article.updated.timestamp() self.published = article.updated
self.updated = article.updated.timestamp() self.updated = article.updated
self.author = article.author self.author = article.author
self.summary = article.excerpt self.summary = article.excerpt
self.content = article.content self.content = article.content
@ -248,4 +256,4 @@ class TTRArticle(Article):
self.language = article.lang self.language = article.lang
self.image_url = article.flavor_image self.image_url = article.flavor_image
self._compute_json_path() self.json_path = self._get_json_path()

View file

@ -5,7 +5,7 @@ from __future__ import annotations
import os import os
import json import json
from abc import ABC from abc import ABC
from datetime import datetime from datetime import datetime, timedelta
from pathlib import Path from pathlib import Path
from hashlib import sha256 from hashlib import sha256
from tempfile import NamedTemporaryFile from tempfile import NamedTemporaryFile
@ -40,9 +40,13 @@ def sanitize_filename(
def format_datetime(config: Config, timestamp: int) -> str: def format_datetime(config: Config, timestamp: int) -> str:
"""Format a timestamp according to the configuraiton.""" """Format a timestamp according to the configuraiton."""
return datetime.fromtimestamp(timestamp, config.timezone).strftime( if timestamp < 0:
config.time_format date = datetime(1970, 1, 1, tzinfo=config.timezone) + timedelta(
) seconds=timestamp
)
else:
date = datetime.fromtimestamp(timestamp, config.timezone)
return date.strftime(config.time_format)
def atomic_write(path: Path, content: str): def atomic_write(path: Path, content: str):
@ -168,13 +172,13 @@ class Article(ABC):
d["category"] = self.category.asdict() d["category"] = self.category.asdict()
return d return d
def _compute_json_path(self): def _get_json_path(self) -> Path:
self.json_path = self.config.json_root / f"{self._hash_id()}.json" return self.config.json_root / f"{self._hash_id()}.json"
def _write_json(self, recompute_path=False): def _write_json(self, recompute_path=False):
"""Write the JSON file associated with this article. Error if it already exists.""" """Write the JSON file associated with this article. Error if it already exists."""
if recompute_path: if recompute_path:
self._compute_json_path() self.json_path = self._get_json_path()
stored_fields = ( stored_fields = (
"id", "id",
"unread", "unread",