diff --git a/cry/cli.py b/cry/cli.py index fef040f..5c2f8f5 100644 --- a/cry/cli.py +++ b/cry/cli.py @@ -1,5 +1,8 @@ # https://simonwillison.net/2023/Sep/30/cli-tools-python/ import asyncio +import html +import http.server +import io import logging import click @@ -144,12 +147,7 @@ def show(pattern, count): db = database.Database.local() feeds = db.load_all(feed_limit=count, pattern=pattern or "") - def feed_sort_key(f: feed.Feed) -> int: - if len(f.entries) > 0: - return max(e.inserted_at for e in f.entries) - return -1 - - feeds.sort(key=feed_sort_key, reverse=True) + feeds.sort(key=feed.sort_key, reverse=True) for f in feeds: click.echo(f"{f.title}") if len(f.entries) > 0: @@ -193,3 +191,44 @@ def unsubscribe(url): if count == 0: click.echo(f"Not subscribed to feed {url}") return 1 + + +@cli.command("serve") +def serve(): + class Handler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + db = database.Database.local() + feeds = db.load_all(feed_limit=10) + feeds.sort(key=feed.sort_key, reverse=True) + + buffer = io.StringIO() + buffer.write("") + buffer.write('Subscribed Feeds') + buffer.write("") + buffer.write("

Feeds

") + for f in feeds: + feed_title = html.escape(f.title) + buffer.write(f'

{feed_title}

') + buffer.write(f"
") + if len(f.entries) > 0: + for entry in f.entries: + title = html.escape(entry.title) + buffer.write( + f'{title} ({entry.time_ago()}) ' + ) + else: + buffer.write("No entries...") + buffer.write(f"
") + buffer.flush() + text = buffer.getvalue() + response = text.encode("utf-8") + + self.send_response(200) + self.send_header("content-type", "text/html") + self.send_header("content-length", str(len(response))) + self.end_headers() + self.wfile.write(response) + + with http.server.HTTPServer(("", 8000), Handler) as server: + click.echo("Serving at http://127.0.0.1:8000/") + server.serve_forever() diff --git a/cry/feed.py b/cry/feed.py index 303b363..479857d 100644 --- a/cry/feed.py +++ b/cry/feed.py @@ -294,6 +294,27 @@ class Entry: title = clean_text(str(title)) return Entry(id=id, inserted_at=insert_time, title=title, link=link) + def time_ago(self) -> str: + inserted = self.inserted_at / 1000 + seconds = int(time.time()) - inserted + if seconds <= 90: + return f"{seconds}s" + minutes = int(seconds / 60) + if minutes <= 90: + return f"{minutes}m" + hours = int(minutes / 60) + if hours < 24: + return f"{hours}h" + days = int(hours / 24) + if days <= 7: + return f"{days}d" + weeks = int(days / 7) + if weeks < 52: + return f"{weeks}w" + + years = int(weeks / 52) + return f"{years}y" + @dataclasses.dataclass(frozen=True) class Feed: @@ -402,3 +423,10 @@ def merge_feeds(a: Feed, b: Feed) -> Feed: link=source_feed.link, entries=entries, ) + + +def sort_key(f: Feed) -> int: + """A sort key for sorting feeds by recency.""" + if len(f.entries) > 0: + return max(e.inserted_at for e in f.entries) + return -1