reader 3.20__tar.gz → 3.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {reader-3.20 → reader-3.22}/CHANGES.rst +91 -4
- {reader-3.20 → reader-3.22}/MANIFEST.in +3 -1
- {reader-3.20/src/reader.egg-info → reader-3.22}/PKG-INFO +9 -13
- {reader-3.20 → reader-3.22}/README.rst +7 -11
- reader-3.22/docs/app.rst +141 -0
- {reader-3.20 → reader-3.22}/docs/cli.rst +4 -10
- {reader-3.20 → reader-3.22}/docs/conf.py +2 -0
- reader-3.22/docs/config.rst +30 -0
- {reader-3.20 → reader-3.22}/docs/dev.rst +30 -37
- {reader-3.20 → reader-3.22}/docs/guide.rst +15 -8
- {reader-3.20 → reader-3.22}/docs/plugins.rst +17 -16
- reader-3.22/docs/screenshots/entries-filters-light.png +0 -0
- reader-3.22/docs/screenshots/entries.png +0 -0
- reader-3.22/docs/screenshots/entry-image-light.png +0 -0
- reader-3.22/docs/screenshots/entry.png +0 -0
- reader-3.22/docs/screenshots/feed.png +0 -0
- reader-3.22/docs/screenshots/feeds.png +0 -0
- reader-3.22/examples/config.toml +26 -0
- {reader-3.20 → reader-3.22}/pyproject.toml +11 -6
- {reader-3.20 → reader-3.22}/run.sh +2 -2
- {reader-3.20 → reader-3.22}/scripts/bench.py +1 -2
- reader-3.22/scripts/vendor_app_stuff.py +41 -0
- {reader-3.20 → reader-3.22}/src/reader/__init__.py +1 -10
- reader-3.22/src/reader/_app/__init__.py +364 -0
- {reader-3.20 → reader-3.22}/src/reader/_app/cli.py +14 -10
- reader-3.22/src/reader/_app/ext.py +52 -0
- {reader-3.20/src/reader/_app/v2 → reader-3.22/src/reader/_app}/forms.py +73 -20
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/__init__.py +27 -59
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/layout.html +4 -5
- reader-3.22/src/reader/_app/legacy/wsgi.py +28 -0
- reader-3.22/src/reader/_app/static/style.css +70 -0
- reader-3.22/src/reader/_app/static/vendor/README +1 -0
- reader-3.22/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css +5 -0
- reader-3.22/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/fonts/bootstrap-icons.woff +0 -0
- reader-3.22/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/fonts/bootstrap-icons.woff2 +0 -0
- reader-3.22/src/reader/_app/static/vendor/bootstrap@5.3.8/dist/css/bootstrap.min.css +6 -0
- reader-3.22/src/reader/_app/static/vendor/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js +7 -0
- reader-3.22/src/reader/_app/static/vendor/htmx-ext-response-targets@2.0.4/dist/response-targets.min.js +1 -0
- reader-3.22/src/reader/_app/static/vendor/htmx.org@2.0.8/dist/htmx.min.js +1 -0
- reader-3.22/src/reader/_app/templates/add_feed.html +46 -0
- reader-3.22/src/reader/_app/templates/change_feed_title.html +56 -0
- reader-3.22/src/reader/_app/templates/delete_feed.html +37 -0
- reader-3.22/src/reader/_app/templates/entries.html +189 -0
- reader-3.22/src/reader/_app/templates/entry.html +135 -0
- reader-3.22/src/reader/_app/templates/feeds.html +81 -0
- reader-3.22/src/reader/_app/templates/layout.html +1 -0
- reader-3.20/src/reader/_app/v2/templates/v2/layout.html → reader-3.22/src/reader/_app/templates/layout_base.html +27 -29
- reader-3.22/src/reader/_app/templates/macros.html +304 -0
- reader-3.22/src/reader/_app/wsgi.py +28 -0
- {reader-3.20 → reader-3.22}/src/reader/_cli.py +107 -133
- reader-3.22/src/reader/_config_utils.py +166 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/__init__.py +68 -14
- {reader-3.20 → reader-3.22}/src/reader/_parser/_http_utils.py +9 -1
- {reader-3.20 → reader-3.22}/src/reader/_parser/requests/__init__.py +0 -1
- reader-3.22/src/reader/_plugins/__init__.py +7 -0
- {reader-3.20 → reader-3.22}/src/reader/_plugins/cli_status.py +8 -4
- reader-3.22/src/reader/_plugins/legacy/__init__.py +3 -0
- {reader-3.20/src/reader/_plugins → reader-3.22/src/reader/_plugins/legacy}/enclosure_tags.py +2 -2
- {reader-3.20/src/reader/_plugins → reader-3.22/src/reader/_plugins/legacy}/preview_feed_list.py +4 -4
- {reader-3.20/src/reader/_plugins → reader-3.22/src/reader/_plugins/legacy}/share.py +2 -2
- {reader-3.20 → reader-3.22}/src/reader/_plugins/sqlite_releases.py +2 -2
- {reader-3.20 → reader-3.22}/src/reader/_plugins/timer.py +1 -1
- {reader-3.20 → reader-3.22}/src/reader/_storage/__init__.py +0 -2
- {reader-3.20 → reader-3.22}/src/reader/_storage/_entries.py +1 -1
- {reader-3.20 → reader-3.22}/src/reader/_storage/_sqlite_utils.py +25 -23
- {reader-3.20 → reader-3.22}/src/reader/_types.py +2 -2
- {reader-3.20 → reader-3.22}/src/reader/_update.py +11 -10
- {reader-3.20 → reader-3.22}/src/reader/_utils.py +8 -0
- {reader-3.20 → reader-3.22}/src/reader/core.py +64 -32
- reader-3.22/src/reader/plugins/__init__.py +53 -0
- reader-3.22/src/reader/plugins/_loader.py +82 -0
- {reader-3.20 → reader-3.22}/src/reader/plugins/enclosure_dedupe.py +4 -2
- {reader-3.20 → reader-3.22}/src/reader/plugins/entry_dedupe.py +9 -8
- {reader-3.20 → reader-3.22}/src/reader/plugins/mark_as_read.py +4 -2
- {reader-3.20 → reader-3.22}/src/reader/plugins/readtime.py +4 -2
- {reader-3.20 → reader-3.22}/src/reader/plugins/ua_fallback.py +4 -2
- {reader-3.20 → reader-3.22/src/reader.egg-info}/PKG-INFO +9 -13
- {reader-3.20 → reader-3.22}/src/reader.egg-info/SOURCES.txt +49 -37
- {reader-3.20 → reader-3.22}/src/reader.egg-info/requires.txt +1 -1
- reader-3.22/tests/_plugins/builtin.py +2 -0
- reader-3.22/tests/_plugins/error_during_import.py +1 -0
- reader-3.22/tests/_plugins/error_import_error.py +1 -0
- {reader-3.20 → reader-3.22}/tests/conftest.py +12 -0
- {reader-3.20 → reader-3.22}/tests/fakeparser.py +27 -36
- {reader-3.20 → reader-3.22}/tests/reader_methods.py +45 -10
- reader-3.20/tests/test_app.py → reader-3.22/tests/test_app_legacy.py +15 -12
- {reader-3.20 → reader-3.22}/tests/test_app_wsgi.py +3 -3
- {reader-3.20 → reader-3.22}/tests/test_changes.py +3 -0
- {reader-3.20 → reader-3.22}/tests/test_cli.py +41 -155
- reader-3.22/tests/test_config_utils.py +107 -0
- {reader-3.20 → reader-3.22}/tests/test_lazy_imports.py +3 -1
- {reader-3.20 → reader-3.22}/tests/test_plugins_cli_status.py +2 -4
- {reader-3.20 → reader-3.22}/tests/test_plugins_enclosure_dedupe.py +1 -1
- {reader-3.20 → reader-3.22}/tests/test_plugins_entry_dedupe.py +22 -4
- reader-3.22/tests/test_plugins_loader.py +103 -0
- {reader-3.20 → reader-3.22}/tests/test_plugins_mark_as_read.py +8 -7
- {reader-3.20 → reader-3.22}/tests/test_plugins_preview_feed_list.py +6 -6
- {reader-3.20 → reader-3.22}/tests/test_plugins_readtime.py +7 -4
- {reader-3.20 → reader-3.22}/tests/test_plugins_sqlite_releases.py +2 -2
- {reader-3.20 → reader-3.22}/tests/test_plugins_ua_fallback.py +2 -2
- {reader-3.20 → reader-3.22}/tests/test_reader.py +38 -1304
- {reader-3.20 → reader-3.22}/tests/test_reader_counts.py +1 -1
- {reader-3.20 → reader-3.22}/tests/test_reader_filter.py +107 -111
- {reader-3.20 → reader-3.22}/tests/test_reader_hooks.py +3 -0
- reader-3.22/tests/test_reader_integration.py +207 -0
- {reader-3.20 → reader-3.22}/tests/test_reader_lifecycle.py +6 -8
- {reader-3.20 → reader-3.22}/tests/test_reader_private.py +3 -0
- {reader-3.20 → reader-3.22}/tests/test_reader_search.py +25 -25
- {reader-3.20 → reader-3.22}/tests/test_reader_sort.py +14 -0
- reader-3.22/tests/test_reader_update.py +1255 -0
- {reader-3.20 → reader-3.22}/tests/test_reader_utils.py +3 -0
- {reader-3.20 → reader-3.22}/tests/utils.py +20 -0
- {reader-3.20 → reader-3.22}/tox.ini +1 -1
- reader-3.20/docs/app.rst +0 -155
- reader-3.20/docs/config.rst +0 -37
- reader-3.20/docs/dev-app.rst +0 -138
- reader-3.20/docs/images/redesign-01.png +0 -0
- reader-3.20/docs/screenshots/dillo.png +0 -0
- reader-3.20/docs/screenshots/entries-feed.png +0 -0
- reader-3.20/docs/screenshots/entries-v2-dark.png +0 -0
- reader-3.20/docs/screenshots/entries-v2-filters-light.png +0 -0
- reader-3.20/docs/screenshots/entries.png +0 -0
- reader-3.20/docs/screenshots/entry-one.png +0 -0
- reader-3.20/docs/screenshots/entry-two.png +0 -0
- reader-3.20/docs/screenshots/feeds.png +0 -0
- reader-3.20/docs/screenshots/lynx.png +0 -0
- reader-3.20/docs/screenshots/search.png +0 -0
- reader-3.20/examples/config.yaml +0 -100
- reader-3.20/src/reader/_app/v2/__init__.py +0 -123
- reader-3.20/src/reader/_app/v2/static/style.css +0 -27
- reader-3.20/src/reader/_app/v2/templates/v2/entries.html +0 -232
- reader-3.20/src/reader/_app/v2/templates/v2/macros.html +0 -47
- reader-3.20/src/reader/_app/wsgi.py +0 -42
- reader-3.20/src/reader/_config.py +0 -161
- reader-3.20/src/reader/_plugins/__init__.py +0 -65
- reader-3.20/src/reader/plugins/__init__.py +0 -64
- reader-3.20/tests/reader_test_plugins/good.py +0 -2
- reader-3.20/tests/reader_test_plugins/init_error.py +0 -2
- reader-3.20/tests/reader_test_plugins/missing_dependency.py +0 -1
- reader-3.20/tests/reader_test_plugins/missing_entry_point.py +0 -1
- reader-3.20/tests/test_config.py +0 -116
- reader-3.20/tests/test_reader_integration.py +0 -209
- reader-3.20/tests/test_reader_plugins.py +0 -87
- reader-3.20/tests/test_reader_update.py +0 -172
- {reader-3.20 → reader-3.22}/LICENSE +0 -0
- {reader-3.20 → reader-3.22}/docs/api.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/changelog.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/contributing.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/index.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/install.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/internal.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/tutorial.rst +0 -0
- {reader-3.20 → reader-3.22}/docs/why.rst +0 -0
- {reader-3.20 → reader-3.22}/examples/custom_headers.py +0 -0
- {reader-3.20 → reader-3.22}/examples/feed_slugs.py +0 -0
- {reader-3.20 → reader-3.22}/examples/parser_only.py +0 -0
- {reader-3.20 → reader-3.22}/examples/podcast.py +0 -0
- {reader-3.20 → reader-3.22}/examples/terminal.py +0 -0
- {reader-3.20 → reader-3.22}/scripts/backup.sh +0 -0
- {reader-3.20 → reader-3.22}/scripts/debug_storage_stats.py +0 -0
- {reader-3.20 → reader-3.22}/scripts/entry_dedupe_backtest.py +0 -0
- {reader-3.20 → reader-3.22}/scripts/jscontrols.html +0 -0
- {reader-3.20 → reader-3.22}/scripts/jscontrols.py +0 -0
- {reader-3.20 → reader-3.22}/scripts/lines.sh +0 -0
- {reader-3.20 → reader-3.22}/scripts/release.py +0 -0
- {reader-3.20 → reader-3.22}/setup.cfg +0 -0
- {reader-3.20 → reader-3.22}/src/reader/__main__.py +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/api_thing.py +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/static/controls.js +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/static/style.css +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/add_entry.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/entries.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/entry.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/feeds.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/macros.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/metadata.html +0 -0
- {reader-3.20/src/reader/_app → reader-3.22/src/reader/_app/legacy}/templates/tags.html +0 -0
- {reader-3.20/src/reader/_app/v2 → reader-3.22/src/reader/_app}/static/theme.js +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_hash_utils.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/_lazy.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/_url_utils.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/feedparser.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/file.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/http.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/jsonfeed.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_parser/requests/_lazy.py +0 -0
- {reader-3.20/src/reader/_plugins → reader-3.22/src/reader/_plugins/legacy}/templates/preview_feed_list.html +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_base.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_changes.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_feeds.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_html_utils.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_schema.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_search.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_sql_utils.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_storage/_tags.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/api.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/encodings.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/exceptions.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/html.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/http.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/mixin.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/py.typed +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/sgml.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/urls.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/_vendor/feedparser/util.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/exceptions.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/py.typed +0 -0
- {reader-3.20 → reader-3.22}/src/reader/types.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader/utils.py +0 -0
- {reader-3.20 → reader-3.22}/src/reader.egg-info/dependency_links.txt +0 -0
- {reader-3.20 → reader-3.22}/src/reader.egg-info/top_level.txt +0 -0
- {reader-3.20/tests/reader_test_plugins → reader-3.22/tests/_plugins}/__init__.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/10.json +0 -0
- {reader-3.20 → reader-3.22}/tests/data/10.json.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/custom +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.atom +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.atom.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.json +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.json.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.rss +0 -0
- {reader-3.20 → reader-3.22}/tests/data/empty.rss.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.atom +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.atom.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.json +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.json.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.rss +0 -0
- {reader-3.20 → reader-3.22}/tests/data/full.rss.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/invalid.json +0 -0
- {reader-3.20 → reader-3.22}/tests/data/invalid.json.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/relative.atom +0 -0
- {reader-3.20 → reader-3.22}/tests/data/relative.atom.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/relative.rss +0 -0
- {reader-3.20 → reader-3.22}/tests/data/relative.rss.py +0 -0
- {reader-3.20 → reader-3.22}/tests/data/sqlite_releases.html +0 -0
- {reader-3.20 → reader-3.22}/tests/data/unknown.json +0 -0
- {reader-3.20 → reader-3.22}/tests/data/unknown.json.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test__types.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test__utils.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_bench.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_exceptions.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_hash_utils.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_html_utils.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_parser.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_reader_deprecations.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_search.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_sql_utils.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_sqlite_utils.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_storage.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_tags.py +0 -0
- {reader-3.20 → reader-3.22}/tests/test_types.py +0 -0
|
@@ -6,6 +6,93 @@ Changelog
|
|
|
6
6
|
:no-index:
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
Version 3.22
|
|
10
|
+
------------
|
|
11
|
+
|
|
12
|
+
Released 2026-04-01
|
|
13
|
+
|
|
14
|
+
* :func:`make_reader` plugin loading improvements. (:issue:`395`)
|
|
15
|
+
|
|
16
|
+
* ``plugins`` now supports arbitrary import paths.
|
|
17
|
+
* :ref:`Built-in plugins <built-in plugins>` now use the
|
|
18
|
+
``.<plugin>`` naming scheme, instead of ``reader.<plugin>``;
|
|
19
|
+
support for the latter is deprecated and will be removed in version 4.0.
|
|
20
|
+
|
|
21
|
+
* :meth:`~Reader.get_feeds`, :meth:`~Reader.get_entries`, and
|
|
22
|
+
:meth:`~Reader.search_entries` now raise exceptions
|
|
23
|
+
for invalid ``query`` and ``starting_after`` eagerly,
|
|
24
|
+
before the iterable is consumed.
|
|
25
|
+
Thanks to `Omprakash Choudhary`_ for the PR.
|
|
26
|
+
(:issue:`388`)
|
|
27
|
+
|
|
28
|
+
* :doc:`app` improvements.
|
|
29
|
+
|
|
30
|
+
* Finish the web app re-design MVP,
|
|
31
|
+
including:
|
|
32
|
+
add / list / filter / delete feeds,
|
|
33
|
+
list / filter articles,
|
|
34
|
+
article view,
|
|
35
|
+
mark articles as read / (un)important,
|
|
36
|
+
article view,
|
|
37
|
+
custom feed titles,
|
|
38
|
+
dark mode,
|
|
39
|
+
CSRF protection,
|
|
40
|
+
vendored CSS / JS dependencies.
|
|
41
|
+
|
|
42
|
+
* Make the new web app the default (entry point ``reader._app.wsgi:app``);
|
|
43
|
+
the :ref:`legacy web app <legacy web app>` remains available
|
|
44
|
+
at ``reader._app.legacy.wsgi:app``.
|
|
45
|
+
|
|
46
|
+
* Update both web apps to use the new configuration infrastructure (see below).
|
|
47
|
+
|
|
48
|
+
* :doc:`CLI <cli>` and :doc:`config file <config>` breaking changes. (:issue:`395`)
|
|
49
|
+
|
|
50
|
+
* The config file format changed from YAML to TOML,
|
|
51
|
+
and follows the shape of the CLI.
|
|
52
|
+
* The ``reader serve`` command was renamed to ``reader web``.
|
|
53
|
+
* Plugin loading environment variables changed:
|
|
54
|
+
``READER_PLUGIN`` -> ``READER_PLUGINS``,
|
|
55
|
+
``READER_CLI_PLUGIN`` -> ``READER_CLI_PLUGINS``,
|
|
56
|
+
``READER_APP_PLUGIN`` -> ``READER_WEB_PLUGINS``.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
.. _Omprakash Choudhary: https://github.com/omseervi098
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
Version 3.21
|
|
63
|
+
------------
|
|
64
|
+
|
|
65
|
+
Released 2026-01-12
|
|
66
|
+
|
|
67
|
+
* :ref:`Scheduled updates <scheduled>` improvements.
|
|
68
|
+
|
|
69
|
+
* Only update scheduled feeds by default
|
|
70
|
+
(:meth:`update_feeds(scheduled=...) <Reader.update_feeds>`
|
|
71
|
+
defaults to :const:`True`);
|
|
72
|
+
previously, all feeds would be updated.
|
|
73
|
+
(:issue:`379`)
|
|
74
|
+
|
|
75
|
+
.. warning::
|
|
76
|
+
|
|
77
|
+
**This is a minor compatibility break**;
|
|
78
|
+
the previous behavior is a bug –
|
|
79
|
+
*reader* should do the right thing
|
|
80
|
+
even if the user doesn't read the documentation.
|
|
81
|
+
|
|
82
|
+
In the CLI, make ``update --scheduled`` the default.
|
|
83
|
+
|
|
84
|
+
* Honor the Cache-Control (max-age) and Expires HTTP headers.
|
|
85
|
+
(:issue:`376`)
|
|
86
|
+
|
|
87
|
+
* Limit the :attr:`~Feed.update_after` derived from HTTP headers
|
|
88
|
+
to a month in the future.
|
|
89
|
+
(:issue:`384`)
|
|
90
|
+
|
|
91
|
+
* If the Retry-After value is a date,
|
|
92
|
+
make the update interval relative to Date.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
9
96
|
Version 3.20
|
|
10
97
|
------------
|
|
11
98
|
|
|
@@ -217,7 +304,7 @@ Released 2024-07-23
|
|
|
217
304
|
* Fix bug in the :mod:`~reader.plugins.entry_dedupe` plugin causing entries
|
|
218
305
|
to flip-flop if there were multiple *new* duplicates of the same issue
|
|
219
306
|
(on the first update, one entry remains, on the second update, the other);
|
|
220
|
-
related to the bug fixed in `version 3.2 <Version 3.2_>`
|
|
307
|
+
related to the bug fixed in `version 3.2 <Version 3.2_>`__.
|
|
221
308
|
(:issue:`340`)
|
|
222
309
|
|
|
223
310
|
* :mod:`~reader._plugins.enclosure_tags` plugin improvements. (:issue:`344`)
|
|
@@ -260,7 +347,7 @@ Released 2024-06-19
|
|
|
260
347
|
* Update an entry whenever its :attr:`~Entry.updated` changes
|
|
261
348
|
(don't require it to be newer).
|
|
262
349
|
|
|
263
|
-
* Fix bug introduced in `version 3.12 <Version 3.12_>`
|
|
350
|
+
* Fix bug introduced in `version 3.12 <Version 3.12_>`__ causing an assertion error
|
|
264
351
|
when there are multiple entries with the same id in the same feed,
|
|
265
352
|
or when parallel :meth:`~Reader.update_feeds` calls add the same entry.
|
|
266
353
|
The fix restores the pre-3.12 first-entry-wins / last-write-wins behavior.
|
|
@@ -411,7 +498,7 @@ Released 2023-08-20
|
|
|
411
498
|
|
|
412
499
|
* Add werkzeug dependency,
|
|
413
500
|
instead of vendoring selected :mod:`werkzeug.http` utilities.
|
|
414
|
-
* Rework lazy imports introduced in `version 3.3 <Version 3.3_>`
|
|
501
|
+
* Rework lazy imports introduced in `version 3.3 <Version 3.3_>`__.
|
|
415
502
|
(:issue:`316`)
|
|
416
503
|
* Make :mod:`reader._parser` a package, and move parsing-related modules into it.
|
|
417
504
|
(:issue:`316`)
|
|
@@ -472,7 +559,7 @@ Released 2023-03-19
|
|
|
472
559
|
so one can express "explicitly unimportant" (*don't care*)
|
|
473
560
|
by setting it to :const:`False`.
|
|
474
561
|
This replaces the semantics for *don't care* introduced
|
|
475
|
-
in `version 2.2 <Version 2.2_>`
|
|
562
|
+
in `version 2.2 <Version 2.2_>`__.
|
|
476
563
|
(:issue:`254`)
|
|
477
564
|
|
|
478
565
|
.. warning::
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
recursive-include src/reader/_app/templates *
|
|
2
2
|
recursive-include src/reader/_app/static *
|
|
3
|
-
recursive-include src/reader/_app/v2 *
|
|
4
3
|
recursive-include src/reader/_plugins/templates *
|
|
4
|
+
recursive-include src/reader/_app/legacy/templates *
|
|
5
|
+
recursive-include src/reader/_app/legacy/static *
|
|
6
|
+
recursive-include src/reader/_plugins/legacy/templates *
|
|
5
7
|
recursive-include src/reader *.pyi
|
|
6
8
|
recursive-include src/reader py.typed
|
|
7
9
|
include run.sh CHANGES.rst LICENSE tox.ini
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reader
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.22
|
|
4
4
|
Summary: A Python feed reader library.
|
|
5
5
|
Author: lemon24
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -45,12 +45,12 @@ Provides-Extra: all
|
|
|
45
45
|
Requires-Dist: reader[app,cli,unstable-plugins]; extra == "all"
|
|
46
46
|
Provides-Extra: cli
|
|
47
47
|
Requires-Dist: click>=7; extra == "cli"
|
|
48
|
-
Requires-Dist: PyYAML; extra == "cli"
|
|
49
48
|
Provides-Extra: app
|
|
50
49
|
Requires-Dist: flask>=0.10; extra == "app"
|
|
51
50
|
Requires-Dist: humanize>=4; extra == "app"
|
|
52
51
|
Requires-Dist: PyYAML; extra == "app"
|
|
53
52
|
Requires-Dist: WTForms; extra == "app"
|
|
53
|
+
Requires-Dist: Flask-WTF; extra == "app"
|
|
54
54
|
Requires-Dist: jinja2-fragments; extra == "app"
|
|
55
55
|
Provides-Extra: unstable-plugins
|
|
56
56
|
Requires-Dist: requests; extra == "unstable-plugins"
|
|
@@ -68,7 +68,9 @@ Dynamic: license-file
|
|
|
68
68
|
|
|
69
69
|
It is designed to allow writing feed reader applications
|
|
70
70
|
without any business code,
|
|
71
|
-
and without depending on a particular framework
|
|
71
|
+
and without depending on a particular framework;
|
|
72
|
+
in MVC terms,
|
|
73
|
+
you'd probably call it a fat model.
|
|
72
74
|
|
|
73
75
|
.. end-intro
|
|
74
76
|
|
|
@@ -122,19 +124,13 @@ and without depending on a particular framework.
|
|
|
122
124
|
|
|
123
125
|
What *reader* doesn't do:
|
|
124
126
|
|
|
125
|
-
* provide an UI
|
|
126
|
-
* provide a REST API (yet)
|
|
127
127
|
* depend on a web framework
|
|
128
|
-
* have an opinion of how
|
|
128
|
+
* have an opinion of how or where you use it
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
In addition, *reader* provides:
|
|
131
131
|
|
|
132
|
-
*
|
|
133
|
-
|
|
134
|
-
* that works even with text-only browsers
|
|
135
|
-
* with automatic tag fixing for podcasts (MP3 enclosures)
|
|
136
|
-
|
|
137
|
-
* a command-line interface
|
|
132
|
+
* an optional web application based on Flask, Bootstrap, and htmx
|
|
133
|
+
* an optional command-line interface
|
|
138
134
|
|
|
139
135
|
.. end-features
|
|
140
136
|
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
It is designed to allow writing feed reader applications
|
|
6
6
|
without any business code,
|
|
7
|
-
and without depending on a particular framework
|
|
7
|
+
and without depending on a particular framework;
|
|
8
|
+
in MVC terms,
|
|
9
|
+
you'd probably call it a fat model.
|
|
8
10
|
|
|
9
11
|
.. end-intro
|
|
10
12
|
|
|
@@ -58,19 +60,13 @@ and without depending on a particular framework.
|
|
|
58
60
|
|
|
59
61
|
What *reader* doesn't do:
|
|
60
62
|
|
|
61
|
-
* provide an UI
|
|
62
|
-
* provide a REST API (yet)
|
|
63
63
|
* depend on a web framework
|
|
64
|
-
* have an opinion of how
|
|
64
|
+
* have an opinion of how or where you use it
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
In addition, *reader* provides:
|
|
67
67
|
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
* that works even with text-only browsers
|
|
71
|
-
* with automatic tag fixing for podcasts (MP3 enclosures)
|
|
72
|
-
|
|
73
|
-
* a command-line interface
|
|
68
|
+
* an optional web application based on Flask, Bootstrap, and htmx
|
|
69
|
+
* an optional command-line interface
|
|
74
70
|
|
|
75
71
|
.. end-features
|
|
76
72
|
|
reader-3.22/docs/app.rst
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
|
|
2
|
+
Web application
|
|
3
|
+
===============
|
|
4
|
+
|
|
5
|
+
*reader* comes with a web application
|
|
6
|
+
based on `Flask`_, `Bootstrap`_, and `htmx`_,
|
|
7
|
+
intended to work across all browsers,
|
|
8
|
+
including mobile and light-weight / text-only ones.
|
|
9
|
+
|
|
10
|
+
.. _Flask: https://flask.palletsprojects.com/
|
|
11
|
+
.. _Bootstrap: https://getbootstrap.com/
|
|
12
|
+
.. _htmx: https://htmx.org/
|
|
13
|
+
|
|
14
|
+
Features, as of *reader* version |version|:
|
|
15
|
+
|
|
16
|
+
* add / list / filter / delete feeds
|
|
17
|
+
* list / filter articles
|
|
18
|
+
* mark articles as read / (un)important
|
|
19
|
+
* article view
|
|
20
|
+
* custom feed titles
|
|
21
|
+
* dark mode
|
|
22
|
+
|
|
23
|
+
More features already implemented in the library
|
|
24
|
+
and the :ref:`legacy web app <legacy web app>`
|
|
25
|
+
should be added in the next releases;
|
|
26
|
+
see the :ref:`roadmap <app roadmap>` for details.
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
.. _app screenshots:
|
|
31
|
+
|
|
32
|
+
Screenshots
|
|
33
|
+
-----------
|
|
34
|
+
|
|
35
|
+
.. figure:: screenshots/entries.png
|
|
36
|
+
:width: 240px
|
|
37
|
+
|
|
38
|
+
main page (dark mode)
|
|
39
|
+
|
|
40
|
+
.. figure:: screenshots/entries-filters-light.png
|
|
41
|
+
:width: 240px
|
|
42
|
+
|
|
43
|
+
main page – more filters (light mode)
|
|
44
|
+
|
|
45
|
+
.. figure:: screenshots/feed.png
|
|
46
|
+
:width: 240px
|
|
47
|
+
|
|
48
|
+
feed page (dark mode)
|
|
49
|
+
|
|
50
|
+
.. figure:: screenshots/feeds.png
|
|
51
|
+
:width: 240px
|
|
52
|
+
|
|
53
|
+
feeds page (dark mode)
|
|
54
|
+
|
|
55
|
+
.. figure:: screenshots/entry.png
|
|
56
|
+
:width: 240px
|
|
57
|
+
|
|
58
|
+
article view (dark mode)
|
|
59
|
+
|
|
60
|
+
.. figure:: screenshots/entry-image-light.png
|
|
61
|
+
:width: 240px
|
|
62
|
+
|
|
63
|
+
article view (light mode)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Serving the web app
|
|
68
|
+
-------------------
|
|
69
|
+
|
|
70
|
+
.. note::
|
|
71
|
+
|
|
72
|
+
The web application is optional, use the ``app`` extra to install
|
|
73
|
+
its :ref:`dependencies <Optional dependencies>`.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
*reader* exposes a standard WSGI application as ``reader._app.wsgi:app``.
|
|
77
|
+
See the `Flask documentation`_ for more details on how to deploy it.
|
|
78
|
+
The path to the reader database can be configured through the
|
|
79
|
+
:doc:`config file <config>`
|
|
80
|
+
or the ``READER_DB`` environment variable.
|
|
81
|
+
|
|
82
|
+
.. warning::
|
|
83
|
+
|
|
84
|
+
The web application has no authentication / authorization whatsoever;
|
|
85
|
+
it is expected a server / middleware will provide that.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
An example uWSGI configuration file (probably not idiomatic, from `here`_)::
|
|
89
|
+
|
|
90
|
+
[uwsgi]
|
|
91
|
+
socket = /apps/reader/uwsgi/sock
|
|
92
|
+
manage-script-name = true
|
|
93
|
+
mount = /reader=reader._app.wsgi:app
|
|
94
|
+
plugin = python3
|
|
95
|
+
virtualenv = /apps/reader/
|
|
96
|
+
env = READER_CONFIG=/apps/reader/reader.toml
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
You can also run the web application with the ``web`` command.
|
|
100
|
+
``web`` uses `Werkzeug's development server`_,
|
|
101
|
+
so it probably won't scale well past a single user.
|
|
102
|
+
|
|
103
|
+
.. note::
|
|
104
|
+
|
|
105
|
+
For privacy reasons,
|
|
106
|
+
you may want to configure your web server to not send a ``Referer`` header
|
|
107
|
+
(by setting ``Referrer-Policy`` header to ``same-origin``
|
|
108
|
+
for all responses; `nginx example`_).
|
|
109
|
+
The ``web`` command does it by default.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
If running on a personal computer, you can use cron to run it at boot::
|
|
113
|
+
|
|
114
|
+
@reboot sleep 60; reader web -p 8080 2>&1 ) >>"/tmp/$LOGNAME.reader.web.run.boot.log"
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
.. _here: https://github.com/lemon24/owncloud/blob/8009f227ef60ebaab621e7bb3363ec9071d8a2e8/reader.yaml#L103-L116
|
|
118
|
+
.. _nginx example: https://github.com/lemon24/owncloud/blob/8009f227ef60ebaab621e7bb3363ec9071d8a2e8/secure.conf#L23
|
|
119
|
+
.. _Flask documentation: https://flask.palletsprojects.com/en/stable/deploying/
|
|
120
|
+
.. _Werkzeug's development server: https://werkzeug.palletsprojects.com/en/stable/serving/#werkzeug.serving.run_simple
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
.. _legacy web app:
|
|
125
|
+
|
|
126
|
+
Legacy web app
|
|
127
|
+
--------------
|
|
128
|
+
|
|
129
|
+
Before the current web application,
|
|
130
|
+
there was another one,
|
|
131
|
+
serving as test bed for new features.
|
|
132
|
+
It is usable, if a bit unpolished,
|
|
133
|
+
but was never meant to be a long-term thing,
|
|
134
|
+
hence the new app;
|
|
135
|
+
you can find screenshots
|
|
136
|
+
`here <https://github.com/lemon24/reader/blob/3.21/docs/app.rst#screenshots-legacy>`_.
|
|
137
|
+
|
|
138
|
+
The WSGI entry point is ``reader._app.legacy.wsgi:app``.
|
|
139
|
+
|
|
140
|
+
The legacy web app should remain available
|
|
141
|
+
until the new app reaches feature parity.
|
|
@@ -2,18 +2,12 @@
|
|
|
2
2
|
Command-line interface
|
|
3
3
|
======================
|
|
4
4
|
|
|
5
|
-
*reader* comes with a
|
|
6
|
-
that exposes
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
.. warning::
|
|
10
|
-
|
|
11
|
-
The CLI is is not fully stable,
|
|
12
|
-
see the :ref:`roadmap <cli roadmap>` for details.
|
|
5
|
+
*reader* comes with a CLI
|
|
6
|
+
that exposes management functionality.
|
|
13
7
|
|
|
14
8
|
.. note::
|
|
15
9
|
|
|
16
|
-
The
|
|
10
|
+
The CLI is optional, use the ``cli`` extra to install
|
|
17
11
|
its :ref:`dependencies <Optional dependencies>`.
|
|
18
12
|
|
|
19
13
|
Most commands need a database to work. The following are equivalent:
|
|
@@ -42,7 +36,7 @@ Serve the web application locally (at http://localhost:8080/):
|
|
|
42
36
|
|
|
43
37
|
.. code-block:: bash
|
|
44
38
|
|
|
45
|
-
python -m reader
|
|
39
|
+
python -m reader web
|
|
46
40
|
|
|
47
41
|
|
|
48
42
|
.. _cli-update:
|
|
@@ -17,6 +17,7 @@ for name in [
|
|
|
17
17
|
'flask.signals',
|
|
18
18
|
'werkzeug',
|
|
19
19
|
'werkzeug.datastructures',
|
|
20
|
+
'werkzeug.exceptions',
|
|
20
21
|
'werkzeug.http',
|
|
21
22
|
'yaml',
|
|
22
23
|
]:
|
|
@@ -45,6 +46,7 @@ autodoc_mock_imports = [
|
|
|
45
46
|
'bs4',
|
|
46
47
|
'mutagen',
|
|
47
48
|
'flask',
|
|
49
|
+
'flask_wtf',
|
|
48
50
|
'werkzeug',
|
|
49
51
|
'humanize',
|
|
50
52
|
'markupsafe',
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
Configuration
|
|
3
|
+
=============
|
|
4
|
+
|
|
5
|
+
Both the :doc:`CLI <cli>` and the :doc:`web application <app>` can
|
|
6
|
+
be configured from a TOML file.
|
|
7
|
+
|
|
8
|
+
.. note::
|
|
9
|
+
|
|
10
|
+
Configuration file loading dependencies get installed automatically when
|
|
11
|
+
installing the CLI or the web application
|
|
12
|
+
:ref:`extras <Optional dependencies>`.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
The configuration file path can be specified either through the ``--config``
|
|
16
|
+
CLI option or through the ``READER_CONFIG`` environment variable
|
|
17
|
+
(also usable with the web application).
|
|
18
|
+
|
|
19
|
+
The configuration file matches the shape of the :doc:`CLI <cli>`
|
|
20
|
+
(the ``reader`` section has options for the ``reader`` command,
|
|
21
|
+
the ``reader.update`` section has options for the ``reader update`` command, etc.).
|
|
22
|
+
In general, option names match those in the CLI
|
|
23
|
+
(``--feed-root`` -> ``feed_root``);
|
|
24
|
+
options that can be passed multiple times in the CLI
|
|
25
|
+
are pluralized in the config
|
|
26
|
+
(``--cli-plugin`` -> ``cli_plugins``).
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
|
|
30
|
+
.. literalinclude:: ../examples/config.toml
|
|
@@ -59,22 +59,22 @@ but I will prioritize supporting :doc:`contributors <contributing>`
|
|
|
59
59
|
* resource tags
|
|
60
60
|
|
|
61
61
|
* :ref:`searchable tag values <searchable tags>`, e.g. for comments
|
|
62
|
-
* :ref:`unification with entry.read/important <entry flag unification>`
|
|
63
62
|
* optimistic locking, :issue:`308`
|
|
64
63
|
* filter tags by prefix, :issue:`309`
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
* HTTP compliance, likely as plugins
|
|
65
|
+
* HTTP behavior / compliance, likely as plugins, :issue:`377`
|
|
68
66
|
|
|
69
67
|
* 301 Moved Permanently, :issue:`246`
|
|
70
68
|
* 410 Gone, :issue:`246`
|
|
71
|
-
*
|
|
69
|
+
* slow down on throttling / max-age, :issue:`378`
|
|
70
|
+
* match the rhythm of the feed, :issue:`382`
|
|
72
71
|
|
|
73
72
|
* add more fields to data objects
|
|
74
73
|
|
|
74
|
+
* .links attribute, :issue:`320`
|
|
75
|
+
* .authors attribute, :issue:`391`
|
|
75
76
|
* extra data, as an escape hatch, :issue:`277`
|
|
76
77
|
|
|
77
|
-
* :ref:`multiple storage implementations <multiple storage implementations>`
|
|
78
78
|
* :ref:`batch get methods <batch get methods>`
|
|
79
79
|
* :doc:`internal` stabilization
|
|
80
80
|
* arbitrary website scraping, :issue:`222`
|
|
@@ -93,15 +93,16 @@ but I will prioritize supporting :doc:`contributors <contributing>`
|
|
|
93
93
|
Command-line interface
|
|
94
94
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
95
95
|
|
|
96
|
-
The :doc:`cli` is more or less stable
|
|
97
|
-
although
|
|
98
|
-
and additional tests.
|
|
96
|
+
The :doc:`cli` is more or less stable,
|
|
97
|
+
although it could use additional tests.
|
|
99
98
|
|
|
100
|
-
A
|
|
99
|
+
A terminal feed reader is *not* in scope,
|
|
101
100
|
since I don't need one,
|
|
102
|
-
but I'm not opposed to the idea
|
|
101
|
+
but I'm not opposed to the idea;
|
|
102
|
+
note that the web app should already
|
|
103
|
+
work with text-based browsers such as `Lynx`_.
|
|
103
104
|
|
|
104
|
-
..
|
|
105
|
+
.. _Lynx: https://en.wikipedia.org/wiki/Lynx_(web_browser)
|
|
105
106
|
|
|
106
107
|
|
|
107
108
|
.. _app roadmap:
|
|
@@ -109,27 +110,23 @@ but I'm not opposed to the idea.
|
|
|
109
110
|
Web application
|
|
110
111
|
~~~~~~~~~~~~~~~
|
|
111
112
|
|
|
112
|
-
The :doc:`app` is
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
and
|
|
117
|
-
|
|
118
|
-
Long term, I'd like to:
|
|
119
|
-
|
|
120
|
-
* re-design it from scratch to improve usability
|
|
121
|
-
(see :issue:`318` for a wishlist)
|
|
122
|
-
* switch to `htmx`_ instead of using a home-grown solution
|
|
123
|
-
* spin it off into a separate package/project
|
|
113
|
+
The new :doc:`app` is under active development.
|
|
114
|
+
I am working on adding features
|
|
115
|
+
already implemented in the library
|
|
116
|
+
and the :ref:`legacy web app <legacy web app>`,
|
|
117
|
+
and possibly on a hosted version.
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
119
|
+
Like with the library,
|
|
120
|
+
the goal is to keep it simple to use
|
|
121
|
+
and sustainable to maintain long-term;
|
|
122
|
+
the decision to use `Flask`_, `Bootstrap`_, and `htmx`_ is part of this
|
|
123
|
+
(if they were around for ~15 years,
|
|
124
|
+
they should be around for 15 more).
|
|
130
125
|
|
|
131
|
-
..
|
|
126
|
+
.. _Flask: https://flask.palletsprojects.com/
|
|
132
127
|
.. _Bootstrap: https://getbootstrap.com/
|
|
128
|
+
.. _htmx: https://htmx.org/
|
|
129
|
+
|
|
133
130
|
|
|
134
131
|
|
|
135
132
|
.. _compat:
|
|
@@ -677,7 +674,10 @@ Why I want to postpone batch update/set methods:
|
|
|
677
674
|
tl:dr: Performance is likely a non-issue with SQLite,
|
|
678
675
|
convenience can be added on top as a plugin.
|
|
679
676
|
|
|
680
|
-
(2025) Why it may be worth adding batch interfaces anyway
|
|
677
|
+
(2025 update) Why it may be worth adding batch interfaces anyway
|
|
678
|
+
(even if underneath the storage implementation doesn't actually batch)
|
|
679
|
+
– it allows for future optimization:
|
|
680
|
+
https://blog.glyph.im/2022/12/potato-programming.html
|
|
681
681
|
|
|
682
682
|
See the 2.12 reader._app.ResourceTags class for an idea of how to
|
|
683
683
|
represent a bunch of tags in a reserved-name-scheme-agnostic way
|
|
@@ -771,10 +771,3 @@ REST API
|
|
|
771
771
|
|
|
772
772
|
Some early thoughts: :issue:`192#issuecomment-700773138`
|
|
773
773
|
(closed with `wontfix`, for now).
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
Web application
|
|
777
|
-
~~~~~~~~~~~~~~~
|
|
778
|
-
|
|
779
|
-
.. toctree::
|
|
780
|
-
dev-app
|
|
@@ -21,7 +21,7 @@ The Reader object
|
|
|
21
21
|
Most *reader* functionality is available through a :class:`Reader` instance,
|
|
22
22
|
which persists feed and entry state
|
|
23
23
|
and provides operations on them;
|
|
24
|
-
in :abbr:`MVC (model–view–controller)`
|
|
24
|
+
in :abbr:`MVC (model–view–controller)` terms,
|
|
25
25
|
you would probably call it a fat model.
|
|
26
26
|
|
|
27
27
|
|
|
@@ -270,11 +270,12 @@ Scheduled updates
|
|
|
270
270
|
~~~~~~~~~~~~~~~~~
|
|
271
271
|
|
|
272
272
|
Because different feeds need to be updated at different rates,
|
|
273
|
-
*reader* also provides a mechanism for scheduling updates
|
|
273
|
+
*reader* also provides a mechanism for scheduling updates
|
|
274
|
+
that is enabled by default.
|
|
274
275
|
|
|
275
276
|
On every update, *reader* determines when a feed should be updated next
|
|
276
277
|
based on a configurable update interval;
|
|
277
|
-
:meth
|
|
278
|
+
:meth:`~Reader.update_feeds`
|
|
278
279
|
updates only the feeds that should be updated at or before the current time.
|
|
279
280
|
|
|
280
281
|
The interval can be **configured by the user**
|
|
@@ -289,9 +290,9 @@ such that updates don't happen exactly at the the same time;
|
|
|
289
290
|
for example, with a one-hour interval, a jitter of 0.25 means
|
|
290
291
|
updates will occur any time in the first 15 minutes of each hour.
|
|
291
292
|
|
|
292
|
-
If the server
|
|
293
|
-
|
|
294
|
-
:meth:`update_feeds(scheduled=True) <Reader.update_feeds>` will honor
|
|
293
|
+
If the server responds with any of the
|
|
294
|
+
Cache-Control max-age, Expires, or Retry-After HTTP headers,
|
|
295
|
+
:meth:`update_feeds(scheduled=True) <Reader.update_feeds>` will honor them.
|
|
295
296
|
|
|
296
297
|
|
|
297
298
|
.. note::
|
|
@@ -308,6 +309,12 @@ If the server sends the Retry-After HTTP header with
|
|
|
308
309
|
.. versionchanged:: 3.15
|
|
309
310
|
Honor the Retry-After HTTP header.
|
|
310
311
|
|
|
312
|
+
.. versionchanged:: 3.21
|
|
313
|
+
Honor the Cache-Control max-age and Expires HTTP headers.
|
|
314
|
+
|
|
315
|
+
.. versionchanged:: 3.21
|
|
316
|
+
Only update scheduled feeds by default.
|
|
317
|
+
|
|
311
318
|
|
|
312
319
|
Update status
|
|
313
320
|
~~~~~~~~~~~~~
|
|
@@ -740,8 +747,8 @@ Plugins
|
|
|
740
747
|
To use a built-in plugin, pass the plugin name to :func:`make_reader`::
|
|
741
748
|
|
|
742
749
|
>>> reader = make_reader("db.sqlite", plugins=[
|
|
743
|
-
... "
|
|
744
|
-
... "
|
|
750
|
+
... ".enclosure_dedupe",
|
|
751
|
+
... ".entry_dedupe",
|
|
745
752
|
... ])
|
|
746
753
|
|
|
747
754
|
|
|
@@ -39,11 +39,19 @@ use the entry point as a :ref:`custom plugin <custom plugins>`::
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
.. automodule:: reader._plugins.cli_status
|
|
42
|
-
.. automodule:: reader._plugins.preview_feed_list
|
|
43
|
-
.. automodule:: reader._plugins.enclosure_tags
|
|
44
42
|
.. automodule:: reader._plugins.sqlite_releases
|
|
45
43
|
.. automodule:: reader._plugins.timer
|
|
46
|
-
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
Legacy web app plugins
|
|
48
|
+
----------------------
|
|
49
|
+
|
|
50
|
+
Following are experimental plugins that work with the legacy web app:
|
|
51
|
+
|
|
52
|
+
.. automodule:: reader._plugins.legacy.preview_feed_list
|
|
53
|
+
.. automodule:: reader._plugins.legacy.enclosure_tags
|
|
54
|
+
.. automodule:: reader._plugins.legacy.share
|
|
47
55
|
|
|
48
56
|
|
|
49
57
|
|
|
@@ -92,30 +100,23 @@ You can still find the code on GitHub:
|
|
|
92
100
|
Loading plugins from the CLI and the web application
|
|
93
101
|
----------------------------------------------------
|
|
94
102
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.. warning::
|
|
98
|
-
|
|
99
|
-
The plugin system/hooks are not stable yet and may change without any notice.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
To load plugins, set the ``READER_PLUGIN`` environment variable to the plugin
|
|
103
|
+
To load plugins, set the ``READER_PLUGINS`` environment variable to the plugin
|
|
103
104
|
entry point (e.g. ``package.module:entry_point``); multiple entry points should
|
|
104
|
-
be separated by
|
|
105
|
+
be separated by space::
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
READER_PLUGINS='first.plugin:entry_point second_plugin' \
|
|
107
108
|
python -m reader some-command
|
|
108
109
|
|
|
109
|
-
For `built-in plugins`_, it is enough to use the plugin name (``
|
|
110
|
+
For `built-in plugins`_, it is enough to use the plugin name (``.plugin``).
|
|
110
111
|
|
|
111
112
|
.. note::
|
|
112
113
|
|
|
113
114
|
:func:`make_reader` ignores the plugin environment variables.
|
|
114
115
|
|
|
115
116
|
|
|
116
|
-
To load web application plugins, set the ``
|
|
117
|
+
To load web application plugins, set the ``READER_WEB_PLUGINS`` environment variable.
|
|
117
118
|
To load CLI plugins (that customize the CLI),
|
|
118
|
-
set the ``
|
|
119
|
+
set the ``READER_CLI_PLUGINS`` environment variable.
|
|
119
120
|
|
|
120
121
|
|
|
121
122
|
|