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'')
+ 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