Skip to content

Commit 99ad809

Browse files
committed
Add feed slugs plugin recipe. #358
1 parent 3702de9 commit 99ad809

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

docs/plugins.rst

+17
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,20 @@ For `built-in plugins`_, it is enough to use the plugin name (``reader.XYZ``).
116116
To load web application plugins, set the ``READER_APP_PLUGIN`` environment variable.
117117
To load CLI plugins (that customize the CLI),
118118
set the ``READER_CLI_PLUGIN`` environment variable.
119+
120+
121+
122+
Recipes
123+
-------
124+
125+
I currently don't need this functionality,
126+
but if you'd be interested in maintaining any of these
127+
as an experimental or even built-in plugin,
128+
please :doc:`submit a pull request <contributing>`.
129+
130+
.. include:: ../examples/feed_slugs.py
131+
:start-after: """
132+
:end-before: """
133+
.. literalinclude:: ../examples/feed_slugs.py
134+
:start-at: def init_reader
135+
:end-before: if __name__

examples/feed_slugs.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""
2+
Feed slugs
3+
~~~~~~~~~~
4+
5+
This is a recipe of what a "get feed by slug" plugin may look like
6+
(e.g. for user-defined short URLs).
7+
8+
Usage::
9+
10+
>>> from reader import make_reader
11+
>>> import feed_slugs
12+
>>> reader = make_reader('db.sqlite', plugins=[feed_slugs.init_reader])
13+
>>> reader.set_feed_slug('https://death.andgravity.com/_feed/index.xml', 'andgravity')
14+
>>> reader.get_feed_by_slug('andgravity')
15+
Feed(url='https://death.andgravity.com/_feed/index.xml', ...)
16+
>>> reader.get_feed_slug(_.url)
17+
'andgravity'
18+
19+
..
20+
Originally implemented for https://github.com/lemon24/reader/issues/358.
21+
22+
"""
23+
24+
# fmt: off
25+
# flake8: noqa
26+
27+
def init_reader(reader):
28+
# __get__() allows help(reader.get_feed_by_slug) to work
29+
reader.get_feed_by_slug = get_feed_by_slug.__get__(reader)
30+
reader.get_feed_slug = get_feed_slug.__get__(reader)
31+
reader.set_feed_slug = set_feed_slug.__get__(reader)
32+
33+
def get_feed_by_slug(reader, slug):
34+
tag = _make_tag(reader, slug)
35+
return next(reader.get_feeds(tags=[tag], limit=1), None)
36+
37+
def get_feed_slug(reader, feed):
38+
if tag := next(_get_tags(reader, feed), None):
39+
return tag.removeprefix(_make_tag(reader, ''))
40+
return None
41+
42+
def set_feed_slug(reader, feed, slug: str | None):
43+
feed = reader.get_feed(feed)
44+
tag = _make_tag(reader, slug)
45+
46+
if not slug:
47+
reader.delete_tag(feed, tag, missing_ok=True)
48+
return
49+
50+
reader.set_tag(feed, tag)
51+
52+
# ensure only one feed has the slug; technically a race condition,
53+
# when it happens no feed will have the tag
54+
for other_feed in reader.get_feeds(tags=[tag]):
55+
if feed.url != other_feed.url:
56+
reader.delete_tag(other_feed, tag, missing_ok=True)
57+
58+
# ensure feed has only one slug; technically a race condition,
59+
# when it happens the feed will have no slug
60+
for other_tag in _get_tags(reader, feed):
61+
if tag != other_tag:
62+
reader.delete_tag(feed, other_tag, missing_ok=True)
63+
64+
def _make_tag(reader, slug):
65+
return reader.make_plugin_reserved_name('slug', slug)
66+
67+
def _get_tags(reader, resource):
68+
prefix = _make_tag(reader, '')
69+
# filter tags by prefix would make this faster,
70+
# https://github.com/lemon24/reader/issues/309
71+
return (t for t in reader.get_tag_keys(resource) if t.startswith(prefix))
72+
73+
if __name__ == '__main__':
74+
from reader import make_reader
75+
76+
reader = make_reader('db.sqlite', plugins=[init_reader])
77+
url = 'https://death.andgravity.com/_feed/index.xml'
78+
79+
reader.set_feed_slug(url, 'one')
80+
print(
81+
reader.get_feed_slug(url),
82+
getattr(reader.get_feed_by_slug('one'), 'url', None),
83+
)
84+
85+
reader.set_feed_slug(url, 'two')
86+
print(
87+
reader.get_feed_slug(url),
88+
getattr(reader.get_feed_by_slug('two'), 'url', None),
89+
)
90+
91+
reader.set_feed_slug('https://xkcd.com/atom.xml', 'two')
92+
print(
93+
reader.get_feed_slug(url),
94+
getattr(reader.get_feed_by_slug('two'), 'url', None),
95+
)

0 commit comments

Comments
 (0)