Unsubscribe
This commit is contained in:
parent
c06f3ef114
commit
02232c9c3e
3 changed files with 112 additions and 35 deletions
42
cry/cli.py
42
cry/cli.py
|
|
@ -13,7 +13,12 @@ LOG = logging.getLogger(__name__)
|
|||
|
||||
@click.group()
|
||||
@click.version_option()
|
||||
@click.option("-v", "--verbose", count=True)
|
||||
@click.option(
|
||||
"-v",
|
||||
"--verbose",
|
||||
count=True,
|
||||
help="Increase the verbosity of the output. This option can be specified multiple times.",
|
||||
)
|
||||
def cli(verbose):
|
||||
"Command line feed reader"
|
||||
if verbose > 1:
|
||||
|
|
@ -153,3 +158,38 @@ def show(pattern, count):
|
|||
else:
|
||||
click.echo(f" <No Entries>")
|
||||
click.echo()
|
||||
|
||||
|
||||
@cli.command("list")
|
||||
@click.argument("pattern", required=False, default="")
|
||||
def list_feeds(pattern):
|
||||
"""List subscribed feeds.
|
||||
|
||||
If a pattern is supplied, then filter the feeds to urls or titles that
|
||||
match the pattern. Otherwise, just show everything.
|
||||
"""
|
||||
db = database.Database.local()
|
||||
feeds = db.load_all(feed_limit=0, pattern=pattern)
|
||||
|
||||
max_title = max(len(f.title) for f in feeds)
|
||||
max_url = max(len(f.meta.url) for f in feeds)
|
||||
|
||||
feeds.sort(key=lambda f: f.title)
|
||||
|
||||
for f in feeds:
|
||||
click.echo(f"{f.title:{max_title}} {f.meta.url:{max_url}}")
|
||||
|
||||
|
||||
@cli.command("unsubscribe")
|
||||
@click.argument("url")
|
||||
def unsubscribe(url):
|
||||
"""Unsubscribe from the specified feed.
|
||||
|
||||
(If you need to find the URL for the feed to unsubscribe from, use the
|
||||
`list` command.)
|
||||
"""
|
||||
db = database.Database.local()
|
||||
count = db.set_feed_status(url, feed.FEED_STATUS_UNSUBSCRIBED)
|
||||
if count == 0:
|
||||
click.echo(f"Not subscribed to feed {url}")
|
||||
return 1
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import random
|
|||
import socket
|
||||
import sqlite3
|
||||
import string
|
||||
import time
|
||||
import typing
|
||||
|
||||
import platformdirs
|
||||
|
|
@ -33,7 +34,17 @@ SCHEMA_STATEMENTS = [
|
|||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
""",
|
||||
# I went and changed the status enum to make ALIVE == 0 when I added the
|
||||
# "unsubscribed" status. I should probably make these strings huh.
|
||||
"""
|
||||
UPDATE feeds
|
||||
SET status=CASE
|
||||
WHEN status = 0 THEN 1
|
||||
WHEN status = 1 THEN 0
|
||||
ELSE status
|
||||
END
|
||||
""",
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -168,8 +179,9 @@ class Database:
|
|||
title,
|
||||
link
|
||||
FROM feeds
|
||||
WHERE title LIKE :sql_pattern ESCAPE '\\'
|
||||
OR link LIKE :sql_pattern ESCAPE '\\'
|
||||
WHERE (title LIKE :sql_pattern ESCAPE '\\'
|
||||
OR link LIKE :sql_pattern ESCAPE '\\')
|
||||
AND status != 2 -- UNSUBSCRIBED
|
||||
""",
|
||||
{"sql_pattern": sql_pattern},
|
||||
)
|
||||
|
|
@ -200,21 +212,25 @@ class Database:
|
|||
|
||||
feeds = []
|
||||
for meta, title, link in almost_feeds:
|
||||
cursor = self.db.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
inserted_at,
|
||||
title,
|
||||
link
|
||||
FROM entries
|
||||
WHERE feed_url=?
|
||||
ORDER BY inserted_at DESC
|
||||
LIMIT ?
|
||||
""",
|
||||
[meta.url, feed_limit],
|
||||
)
|
||||
rows = cursor.fetchall()
|
||||
if feed_limit > 0:
|
||||
cursor = self.db.execute(
|
||||
"""
|
||||
SELECT
|
||||
id,
|
||||
inserted_at,
|
||||
title,
|
||||
link
|
||||
FROM entries
|
||||
WHERE feed_url=?
|
||||
ORDER BY inserted_at DESC
|
||||
LIMIT ?
|
||||
""",
|
||||
[meta.url, feed_limit],
|
||||
)
|
||||
rows = cursor.fetchall()
|
||||
else:
|
||||
rows = []
|
||||
|
||||
entries = [
|
||||
feed.Entry(id=id, inserted_at=inserted_at, title=title, link=link)
|
||||
for id, inserted_at, title, link in rows
|
||||
|
|
@ -278,18 +294,26 @@ class Database:
|
|||
return feed.Feed(meta=meta, title=title, link=link, entries=entries)
|
||||
|
||||
def update_meta(self, f: feed.FeedMeta):
|
||||
self.db.execute(
|
||||
"""
|
||||
UPDATE feeds SET
|
||||
last_fetched_ts=?,
|
||||
retry_after_ts=?,
|
||||
status=?,
|
||||
etag=?,
|
||||
modified=?
|
||||
WHERE url=?
|
||||
""",
|
||||
[f.last_fetched_ts, f.retry_after_ts, f.status, f.etag, f.modified, f.url],
|
||||
)
|
||||
with self.db:
|
||||
self.db.execute(
|
||||
"""
|
||||
UPDATE feeds SET
|
||||
last_fetched_ts=?,
|
||||
retry_after_ts=?,
|
||||
status=?,
|
||||
etag=?,
|
||||
modified=?
|
||||
WHERE url=?
|
||||
""",
|
||||
[
|
||||
f.last_fetched_ts,
|
||||
f.retry_after_ts,
|
||||
f.status,
|
||||
f.etag,
|
||||
f.modified,
|
||||
f.url,
|
||||
],
|
||||
)
|
||||
|
||||
def store_feed(self, f: feed.Feed) -> int:
|
||||
"""Store the given feed in the database.
|
||||
|
|
@ -375,3 +399,16 @@ class Database:
|
|||
)
|
||||
end_count = cursor.fetchone()[0]
|
||||
return end_count - start_count
|
||||
|
||||
def set_feed_status(self, url: str, status: int) -> int:
|
||||
with self.db:
|
||||
cursor = self.db.execute(
|
||||
"""
|
||||
UPDATE feeds
|
||||
SET status = ?,
|
||||
last_fetched_ts = ?
|
||||
WHERE url = ?
|
||||
""",
|
||||
[status, int(time.time()), url],
|
||||
)
|
||||
return cursor.rowcount
|
||||
|
|
|
|||
10
cry/feed.py
10
cry/feed.py
|
|
@ -18,9 +18,9 @@ import requests.structures
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
FEED_STATUS_DEAD = 0
|
||||
FEED_STATUS_ALIVE = 1
|
||||
FEED_STATUS_MISSING = 2
|
||||
FEED_STATUS_ALIVE = 0
|
||||
FEED_STATUS_DEAD = 1
|
||||
FEED_STATUS_UNSUBSCRIBED = 2
|
||||
|
||||
# TODO: Consider configuration here.
|
||||
http = requests.Session()
|
||||
|
|
@ -143,8 +143,8 @@ async def fetch_feed(
|
|||
|
||||
Regardless, the new FeedMeta has the latest state of the feed.
|
||||
"""
|
||||
if feed.status == FEED_STATUS_DEAD:
|
||||
LOG.info(f"{feed.url} is dead")
|
||||
if feed.status != FEED_STATUS_ALIVE:
|
||||
LOG.info(f"{feed.url} is dead or unsubscribed")
|
||||
return (None, feed)
|
||||
|
||||
if time.time() < feed.retry_after_ts:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue