reader 3.21__tar.gz → 3.23__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.21 → reader-3.23}/CHANGES.rst +73 -4
- {reader-3.21 → reader-3.23}/MANIFEST.in +3 -1
- {reader-3.21/src/reader.egg-info → reader-3.23}/PKG-INFO +10 -13
- {reader-3.21 → reader-3.23}/README.rst +8 -11
- {reader-3.21 → reader-3.23}/docs/api.rst +21 -0
- reader-3.23/docs/app.rst +153 -0
- {reader-3.21 → reader-3.23}/docs/cli.rst +4 -10
- {reader-3.21 → reader-3.23}/docs/conf.py +2 -2
- reader-3.23/docs/config.rst +30 -0
- {reader-3.21 → reader-3.23}/docs/dev.rst +30 -38
- {reader-3.21 → reader-3.23}/docs/guide.rst +55 -26
- {reader-3.21 → reader-3.23}/docs/plugins.rst +17 -16
- reader-3.23/docs/screenshots/entries-filters-light.png +0 -0
- reader-3.23/docs/screenshots/entries.png +0 -0
- reader-3.23/docs/screenshots/entry-image-light.png +0 -0
- reader-3.23/docs/screenshots/entry.png +0 -0
- reader-3.23/docs/screenshots/feed.png +0 -0
- reader-3.23/docs/screenshots/feeds.png +0 -0
- reader-3.23/docs/screenshots/import-result.png +0 -0
- reader-3.23/docs/screenshots/import-select.png +0 -0
- reader-3.23/examples/config.toml +26 -0
- {reader-3.21 → reader-3.23}/examples/podcast.py +0 -1
- {reader-3.21 → reader-3.23}/pyproject.toml +7 -5
- {reader-3.21 → reader-3.23}/run.sh +1 -1
- {reader-3.21 → reader-3.23}/scripts/bench.py +1 -3
- {reader-3.21 → reader-3.23}/scripts/debug_storage_stats.py +0 -1
- {reader-3.21 → reader-3.23}/scripts/entry_dedupe_backtest.py +0 -1
- {reader-3.21 → reader-3.23}/scripts/jscontrols.py +0 -2
- reader-3.23/scripts/vendor_app_stuff.py +40 -0
- {reader-3.21 → reader-3.23}/src/reader/__init__.py +7 -12
- {reader-3.21 → reader-3.23}/src/reader/__main__.py +0 -1
- reader-3.23/src/reader/_app/__init__.py +399 -0
- {reader-3.21 → reader-3.23}/src/reader/_app/cli.py +14 -10
- reader-3.23/src/reader/_app/ext.py +51 -0
- {reader-3.21/src/reader/_app/v2 → reader-3.23/src/reader/_app}/forms.py +73 -21
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/__init__.py +27 -60
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/layout.html +4 -5
- reader-3.23/src/reader/_app/legacy/wsgi.py +27 -0
- reader-3.23/src/reader/_app/static/style.css +70 -0
- reader-3.23/src/reader/_app/static/vendor/README +1 -0
- reader-3.23/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/bootstrap-icons.min.css +5 -0
- reader-3.23/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/fonts/bootstrap-icons.woff +0 -0
- reader-3.23/src/reader/_app/static/vendor/bootstrap-icons@1.13.1/font/fonts/bootstrap-icons.woff2 +0 -0
- reader-3.23/src/reader/_app/static/vendor/bootstrap@5.3.8/dist/css/bootstrap.min.css +6 -0
- reader-3.23/src/reader/_app/static/vendor/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js +7 -0
- reader-3.23/src/reader/_app/static/vendor/htmx-ext-response-targets@2.0.4/dist/response-targets.min.js +1 -0
- reader-3.23/src/reader/_app/static/vendor/htmx.org@2.0.8/dist/htmx.min.js +1 -0
- reader-3.23/src/reader/_app/templates/add_feed.html +54 -0
- reader-3.23/src/reader/_app/templates/change_feed_title.html +56 -0
- reader-3.23/src/reader/_app/templates/delete_feed.html +37 -0
- reader-3.23/src/reader/_app/templates/entries.html +189 -0
- reader-3.23/src/reader/_app/templates/entry.html +135 -0
- reader-3.23/src/reader/_app/templates/feeds.html +88 -0
- reader-3.23/src/reader/_app/templates/import_feeds.html +121 -0
- reader-3.23/src/reader/_app/templates/layout.html +1 -0
- reader-3.21/src/reader/_app/v2/templates/v2/layout.html → reader-3.23/src/reader/_app/templates/layout_base.html +30 -29
- reader-3.23/src/reader/_app/templates/macros.html +319 -0
- reader-3.23/src/reader/_app/wsgi.py +27 -0
- {reader-3.21 → reader-3.23}/src/reader/_cli.py +102 -132
- reader-3.23/src/reader/_config_utils.py +166 -0
- {reader-3.21 → reader-3.23}/src/reader/_hash_utils.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/__init__.py +15 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/_http_utils.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/_lazy.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/feedparser.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/jsonfeed.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_parser/requests/__init__.py +0 -2
- {reader-3.21 → reader-3.23}/src/reader/_parser/requests/_lazy.py +0 -1
- reader-3.23/src/reader/_plugins/__init__.py +7 -0
- {reader-3.21 → reader-3.23}/src/reader/_plugins/cli_status.py +8 -4
- reader-3.23/src/reader/_plugins/legacy/__init__.py +3 -0
- {reader-3.21/src/reader/_plugins → reader-3.23/src/reader/_plugins/legacy}/enclosure_tags.py +2 -3
- {reader-3.21/src/reader/_plugins → reader-3.23/src/reader/_plugins/legacy}/preview_feed_list.py +4 -5
- {reader-3.21/src/reader/_plugins → reader-3.23/src/reader/_plugins/legacy}/share.py +2 -3
- {reader-3.21 → reader-3.23}/src/reader/_plugins/sqlite_releases.py +2 -3
- {reader-3.21 → reader-3.23}/src/reader/_plugins/timer.py +1 -1
- {reader-3.21 → reader-3.23}/src/reader/_storage/__init__.py +0 -3
- {reader-3.21 → reader-3.23}/src/reader/_storage/_base.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_storage/_changes.py +2 -5
- {reader-3.21 → reader-3.23}/src/reader/_storage/_entries.py +8 -13
- {reader-3.21 → reader-3.23}/src/reader/_storage/_feeds.py +1 -2
- {reader-3.21 → reader-3.23}/src/reader/_storage/_html_utils.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_storage/_schema.py +4 -9
- {reader-3.21 → reader-3.23}/src/reader/_storage/_search.py +13 -22
- {reader-3.21 → reader-3.23}/src/reader/_storage/_sql_utils.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_storage/_sqlite_utils.py +1 -2
- {reader-3.21 → reader-3.23}/src/reader/_storage/_tags.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_types.py +2 -3
- {reader-3.21 → reader-3.23}/src/reader/_update.py +0 -1
- {reader-3.21 → reader-3.23}/src/reader/_utils.py +8 -1
- {reader-3.21 → reader-3.23}/src/reader/core.py +120 -26
- {reader-3.21 → reader-3.23}/src/reader/exceptions.py +8 -0
- reader-3.23/src/reader/opml.py +178 -0
- reader-3.23/src/reader/plugins/__init__.py +52 -0
- reader-3.23/src/reader/plugins/_loader.py +81 -0
- {reader-3.21 → reader-3.23}/src/reader/plugins/enclosure_dedupe.py +4 -2
- {reader-3.21 → reader-3.23}/src/reader/plugins/entry_dedupe.py +6 -7
- {reader-3.21 → reader-3.23}/src/reader/plugins/mark_as_read.py +4 -3
- {reader-3.21 → reader-3.23}/src/reader/plugins/readtime.py +4 -3
- {reader-3.21 → reader-3.23}/src/reader/plugins/ua_fallback.py +4 -3
- {reader-3.21 → reader-3.23}/src/reader/types.py +70 -1
- {reader-3.21 → reader-3.23}/src/reader/utils.py +16 -2
- {reader-3.21 → reader-3.23/src/reader.egg-info}/PKG-INFO +10 -13
- {reader-3.21 → reader-3.23}/src/reader.egg-info/SOURCES.txt +54 -37
- {reader-3.21 → reader-3.23}/src/reader.egg-info/requires.txt +1 -1
- reader-3.23/tests/_plugins/builtin.py +2 -0
- reader-3.23/tests/_plugins/error_during_import.py +1 -0
- reader-3.23/tests/_plugins/error_import_error.py +1 -0
- {reader-3.21 → reader-3.23}/tests/data/10.json.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/empty.atom.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/empty.json.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/empty.rss.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/full.atom.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/full.json.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/full.rss.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/invalid.json.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/relative.atom.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/relative.rss.py +0 -1
- {reader-3.21 → reader-3.23}/tests/data/unknown.json.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test__types.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test__utils.py +0 -1
- reader-3.21/tests/test_app.py → reader-3.23/tests/test_app_legacy.py +9 -10
- {reader-3.21 → reader-3.23}/tests/test_app_wsgi.py +3 -3
- {reader-3.21 → reader-3.23}/tests/test_bench.py +0 -2
- {reader-3.21 → reader-3.23}/tests/test_changes.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_cli.py +37 -151
- reader-3.23/tests/test_config_utils.py +105 -0
- {reader-3.21 → reader-3.23}/tests/test_html_utils.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_lazy_imports.py +5 -6
- reader-3.23/tests/test_opml.py +153 -0
- {reader-3.21 → reader-3.23}/tests/test_plugins_cli_status.py +2 -4
- {reader-3.21 → reader-3.23}/tests/test_plugins_enclosure_dedupe.py +1 -1
- {reader-3.21 → reader-3.23}/tests/test_plugins_entry_dedupe.py +1 -2
- reader-3.23/tests/test_plugins_loader.py +103 -0
- {reader-3.21 → reader-3.23}/tests/test_plugins_mark_as_read.py +5 -8
- {reader-3.21 → reader-3.23}/tests/test_plugins_preview_feed_list.py +6 -7
- {reader-3.21 → reader-3.23}/tests/test_plugins_readtime.py +4 -5
- {reader-3.21 → reader-3.23}/tests/test_plugins_sqlite_releases.py +2 -2
- {reader-3.21 → reader-3.23}/tests/test_plugins_ua_fallback.py +2 -2
- {reader-3.21 → reader-3.23}/tests/test_reader.py +2 -6
- {reader-3.21 → reader-3.23}/tests/test_reader_deprecations.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_filter.py +29 -2
- {reader-3.21 → reader-3.23}/tests/test_reader_hooks.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_lifecycle.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_private.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_search.py +12 -9
- {reader-3.21 → reader-3.23}/tests/test_reader_sort.py +7 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_update.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_reader_utils.py +14 -2
- {reader-3.21 → reader-3.23}/tests/test_search.py +0 -1
- {reader-3.21 → reader-3.23}/tests/test_sql_utils.py +12 -22
- {reader-3.21 → reader-3.23}/tests/test_sqlite_utils.py +0 -1
- reader-3.21/docs/app.rst +0 -155
- reader-3.21/docs/config.rst +0 -37
- reader-3.21/docs/dev-app.rst +0 -138
- reader-3.21/docs/images/redesign-01.png +0 -0
- reader-3.21/docs/screenshots/dillo.png +0 -0
- reader-3.21/docs/screenshots/entries-feed.png +0 -0
- reader-3.21/docs/screenshots/entries-v2-dark.png +0 -0
- reader-3.21/docs/screenshots/entries-v2-filters-light.png +0 -0
- reader-3.21/docs/screenshots/entries.png +0 -0
- reader-3.21/docs/screenshots/entry-one.png +0 -0
- reader-3.21/docs/screenshots/entry-two.png +0 -0
- reader-3.21/docs/screenshots/feeds.png +0 -0
- reader-3.21/docs/screenshots/lynx.png +0 -0
- reader-3.21/docs/screenshots/search.png +0 -0
- reader-3.21/examples/config.yaml +0 -100
- reader-3.21/src/reader/_app/v2/__init__.py +0 -123
- reader-3.21/src/reader/_app/v2/static/style.css +0 -27
- reader-3.21/src/reader/_app/v2/templates/v2/entries.html +0 -234
- reader-3.21/src/reader/_app/v2/templates/v2/macros.html +0 -47
- reader-3.21/src/reader/_app/wsgi.py +0 -42
- reader-3.21/src/reader/_config.py +0 -161
- reader-3.21/src/reader/_plugins/__init__.py +0 -65
- reader-3.21/src/reader/plugins/__init__.py +0 -64
- reader-3.21/tests/reader_test_plugins/good.py +0 -2
- reader-3.21/tests/reader_test_plugins/init_error.py +0 -2
- reader-3.21/tests/reader_test_plugins/missing_dependency.py +0 -1
- reader-3.21/tests/reader_test_plugins/missing_entry_point.py +0 -1
- reader-3.21/tests/test_config.py +0 -116
- reader-3.21/tests/test_reader_plugins.py +0 -87
- {reader-3.21 → reader-3.23}/LICENSE +0 -0
- {reader-3.21 → reader-3.23}/docs/changelog.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/contributing.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/index.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/install.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/internal.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/tutorial.rst +0 -0
- {reader-3.21 → reader-3.23}/docs/why.rst +0 -0
- {reader-3.21 → reader-3.23}/examples/custom_headers.py +0 -0
- {reader-3.21 → reader-3.23}/examples/feed_slugs.py +0 -0
- {reader-3.21 → reader-3.23}/examples/parser_only.py +0 -0
- {reader-3.21 → reader-3.23}/examples/terminal.py +0 -0
- {reader-3.21 → reader-3.23}/scripts/backup.sh +0 -0
- {reader-3.21 → reader-3.23}/scripts/jscontrols.html +0 -0
- {reader-3.21 → reader-3.23}/scripts/lines.sh +0 -0
- {reader-3.21 → reader-3.23}/scripts/release.py +0 -0
- {reader-3.21 → reader-3.23}/setup.cfg +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/api_thing.py +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/static/controls.js +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/static/style.css +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/add_entry.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/entries.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/entry.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/feeds.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/macros.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/metadata.html +0 -0
- {reader-3.21/src/reader/_app → reader-3.23/src/reader/_app/legacy}/templates/tags.html +0 -0
- {reader-3.21/src/reader/_app/v2 → reader-3.23/src/reader/_app}/static/theme.js +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_parser/_url_utils.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_parser/file.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_parser/http.py +0 -0
- {reader-3.21/src/reader/_plugins → reader-3.23/src/reader/_plugins/legacy}/templates/preview_feed_list.html +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/api.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/asctime.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/greek.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/hungarian.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/iso8601.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/korean.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/perforce.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/rfc822.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/datetimes/w3dtf.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/encodings.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/exceptions.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/html.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/http.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/mixin.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/_base.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/admin.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/cc.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/dc.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/georss.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/itunes.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/mediarss.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/namespaces/psc.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/parsers/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/parsers/json.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/parsers/loose.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/parsers/strict.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/py.typed +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/sanitizer.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/sgml.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/urls.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/_vendor/feedparser/util.py +0 -0
- {reader-3.21 → reader-3.23}/src/reader/py.typed +0 -0
- {reader-3.21 → reader-3.23}/src/reader.egg-info/dependency_links.txt +0 -0
- {reader-3.21 → reader-3.23}/src/reader.egg-info/top_level.txt +0 -0
- {reader-3.21/tests/reader_test_plugins → reader-3.23/tests/_plugins}/__init__.py +0 -0
- {reader-3.21 → reader-3.23}/tests/conftest.py +0 -0
- {reader-3.21 → reader-3.23}/tests/data/10.json +0 -0
- {reader-3.21 → reader-3.23}/tests/data/custom +0 -0
- {reader-3.21 → reader-3.23}/tests/data/empty.atom +0 -0
- {reader-3.21 → reader-3.23}/tests/data/empty.json +0 -0
- {reader-3.21 → reader-3.23}/tests/data/empty.rss +0 -0
- {reader-3.21 → reader-3.23}/tests/data/full.atom +0 -0
- {reader-3.21 → reader-3.23}/tests/data/full.json +0 -0
- {reader-3.21 → reader-3.23}/tests/data/full.rss +0 -0
- {reader-3.21 → reader-3.23}/tests/data/invalid.json +0 -0
- {reader-3.21 → reader-3.23}/tests/data/relative.atom +0 -0
- {reader-3.21 → reader-3.23}/tests/data/relative.rss +0 -0
- {reader-3.21 → reader-3.23}/tests/data/sqlite_releases.html +0 -0
- {reader-3.21 → reader-3.23}/tests/data/unknown.json +0 -0
- {reader-3.21 → reader-3.23}/tests/fakeparser.py +0 -0
- {reader-3.21 → reader-3.23}/tests/reader_methods.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_exceptions.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_hash_utils.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_parser.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_reader_counts.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_reader_integration.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_storage.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_tags.py +0 -0
- {reader-3.21 → reader-3.23}/tests/test_types.py +0 -0
- {reader-3.21 → reader-3.23}/tests/utils.py +0 -0
- {reader-3.21 → reader-3.23}/tox.ini +0 -0
|
@@ -6,6 +6,75 @@ Changelog
|
|
|
6
6
|
:no-index:
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
Version 3.23
|
|
10
|
+
------------
|
|
11
|
+
|
|
12
|
+
Released 2026-04-24
|
|
13
|
+
|
|
14
|
+
* Add support for :ref:`opml`. (:issue:`165`)
|
|
15
|
+
|
|
16
|
+
* Add support for import / export in the web app; :ref:`screenshots <screenshots-import>`.
|
|
17
|
+
|
|
18
|
+
* Deprecate the :func:`~reader.utils.archive_entries` ``feed_user_title`` argument.
|
|
19
|
+
* Fix :meth:`get_feeds(feed='') <Reader.get_feeds>` and
|
|
20
|
+
:meth:`get_entries(entry=('', '')) <Reader.get_entries>`
|
|
21
|
+
returning wrong entries.
|
|
22
|
+
(:issue:`392`)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
Version 3.22
|
|
26
|
+
------------
|
|
27
|
+
|
|
28
|
+
Released 2026-04-01
|
|
29
|
+
|
|
30
|
+
* :func:`make_reader` plugin loading improvements. (:issue:`395`)
|
|
31
|
+
|
|
32
|
+
* ``plugins`` now supports arbitrary import paths.
|
|
33
|
+
* :ref:`Built-in plugins <built-in plugins>` now use the
|
|
34
|
+
``.<plugin>`` naming scheme, instead of ``reader.<plugin>``;
|
|
35
|
+
support for the latter is deprecated and will be removed in version 4.0.
|
|
36
|
+
|
|
37
|
+
* :meth:`~Reader.get_feeds`, :meth:`~Reader.get_entries`, and
|
|
38
|
+
:meth:`~Reader.search_entries` now raise exceptions
|
|
39
|
+
for invalid ``query`` and ``starting_after`` eagerly,
|
|
40
|
+
before the iterable is consumed.
|
|
41
|
+
Thanks to `Omprakash Choudhary`_ for the PR.
|
|
42
|
+
(:issue:`388`)
|
|
43
|
+
|
|
44
|
+
* :doc:`app` improvements.
|
|
45
|
+
|
|
46
|
+
* Finish the web app re-design MVP,
|
|
47
|
+
including:
|
|
48
|
+
add / list / filter / delete feeds,
|
|
49
|
+
list / filter articles,
|
|
50
|
+
article view,
|
|
51
|
+
mark articles as read / (un)important,
|
|
52
|
+
article view,
|
|
53
|
+
custom feed titles,
|
|
54
|
+
dark mode,
|
|
55
|
+
CSRF protection,
|
|
56
|
+
vendored CSS / JS dependencies.
|
|
57
|
+
|
|
58
|
+
* Make the new web app the default (entry point ``reader._app.wsgi:app``);
|
|
59
|
+
the :ref:`legacy web app <legacy web app>` remains available
|
|
60
|
+
at ``reader._app.legacy.wsgi:app``.
|
|
61
|
+
|
|
62
|
+
* Update both web apps to use the new configuration infrastructure (see below).
|
|
63
|
+
|
|
64
|
+
* :doc:`CLI <cli>` and :doc:`config file <config>` breaking changes. (:issue:`395`)
|
|
65
|
+
|
|
66
|
+
* The config file format changed from YAML to TOML,
|
|
67
|
+
and follows the shape of the CLI.
|
|
68
|
+
* The ``reader serve`` command was renamed to ``reader web``.
|
|
69
|
+
* Plugin loading environment variables changed:
|
|
70
|
+
``READER_PLUGIN`` -> ``READER_PLUGINS``,
|
|
71
|
+
``READER_CLI_PLUGIN`` -> ``READER_CLI_PLUGINS``,
|
|
72
|
+
``READER_APP_PLUGIN`` -> ``READER_WEB_PLUGINS``.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
.. _Omprakash Choudhary: https://github.com/omseervi098
|
|
76
|
+
|
|
77
|
+
|
|
9
78
|
Version 3.21
|
|
10
79
|
------------
|
|
11
80
|
|
|
@@ -251,7 +320,7 @@ Released 2024-07-23
|
|
|
251
320
|
* Fix bug in the :mod:`~reader.plugins.entry_dedupe` plugin causing entries
|
|
252
321
|
to flip-flop if there were multiple *new* duplicates of the same issue
|
|
253
322
|
(on the first update, one entry remains, on the second update, the other);
|
|
254
|
-
related to the bug fixed in `version 3.2 <Version 3.2_>`
|
|
323
|
+
related to the bug fixed in `version 3.2 <Version 3.2_>`__.
|
|
255
324
|
(:issue:`340`)
|
|
256
325
|
|
|
257
326
|
* :mod:`~reader._plugins.enclosure_tags` plugin improvements. (:issue:`344`)
|
|
@@ -294,7 +363,7 @@ Released 2024-06-19
|
|
|
294
363
|
* Update an entry whenever its :attr:`~Entry.updated` changes
|
|
295
364
|
(don't require it to be newer).
|
|
296
365
|
|
|
297
|
-
* Fix bug introduced in `version 3.12 <Version 3.12_>`
|
|
366
|
+
* Fix bug introduced in `version 3.12 <Version 3.12_>`__ causing an assertion error
|
|
298
367
|
when there are multiple entries with the same id in the same feed,
|
|
299
368
|
or when parallel :meth:`~Reader.update_feeds` calls add the same entry.
|
|
300
369
|
The fix restores the pre-3.12 first-entry-wins / last-write-wins behavior.
|
|
@@ -445,7 +514,7 @@ Released 2023-08-20
|
|
|
445
514
|
|
|
446
515
|
* Add werkzeug dependency,
|
|
447
516
|
instead of vendoring selected :mod:`werkzeug.http` utilities.
|
|
448
|
-
* Rework lazy imports introduced in `version 3.3 <Version 3.3_>`
|
|
517
|
+
* Rework lazy imports introduced in `version 3.3 <Version 3.3_>`__.
|
|
449
518
|
(:issue:`316`)
|
|
450
519
|
* Make :mod:`reader._parser` a package, and move parsing-related modules into it.
|
|
451
520
|
(:issue:`316`)
|
|
@@ -506,7 +575,7 @@ Released 2023-03-19
|
|
|
506
575
|
so one can express "explicitly unimportant" (*don't care*)
|
|
507
576
|
by setting it to :const:`False`.
|
|
508
577
|
This replaces the semantics for *don't care* introduced
|
|
509
|
-
in `version 2.2 <Version 2.2_>`
|
|
578
|
+
in `version 2.2 <Version 2.2_>`__.
|
|
510
579
|
(:issue:`254`)
|
|
511
580
|
|
|
512
581
|
.. 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.23
|
|
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
|
|
|
@@ -111,6 +113,7 @@ and without depending on a particular framework.
|
|
|
111
113
|
* filter feeds and articles
|
|
112
114
|
* full-text search articles
|
|
113
115
|
* get statistics on feed and user activity
|
|
116
|
+
* import / export feeds as OPML
|
|
114
117
|
* write plugins to extend its functionality
|
|
115
118
|
* skip all the low level stuff and focus on what makes your feed reader different
|
|
116
119
|
|
|
@@ -122,19 +125,13 @@ and without depending on a particular framework.
|
|
|
122
125
|
|
|
123
126
|
What *reader* doesn't do:
|
|
124
127
|
|
|
125
|
-
* provide an UI
|
|
126
|
-
* provide a REST API (yet)
|
|
127
128
|
* depend on a web framework
|
|
128
|
-
* have an opinion of how
|
|
129
|
+
* have an opinion of how or where you use it
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
In addition, *reader* provides:
|
|
131
132
|
|
|
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
|
|
133
|
+
* an optional web application based on Flask, Bootstrap, and htmx
|
|
134
|
+
* an optional command-line interface
|
|
138
135
|
|
|
139
136
|
.. end-features
|
|
140
137
|
|
|
@@ -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
|
|
|
@@ -47,6 +49,7 @@ and without depending on a particular framework.
|
|
|
47
49
|
* filter feeds and articles
|
|
48
50
|
* full-text search articles
|
|
49
51
|
* get statistics on feed and user activity
|
|
52
|
+
* import / export feeds as OPML
|
|
50
53
|
* write plugins to extend its functionality
|
|
51
54
|
* skip all the low level stuff and focus on what makes your feed reader different
|
|
52
55
|
|
|
@@ -58,19 +61,13 @@ and without depending on a particular framework.
|
|
|
58
61
|
|
|
59
62
|
What *reader* doesn't do:
|
|
60
63
|
|
|
61
|
-
* provide an UI
|
|
62
|
-
* provide a REST API (yet)
|
|
63
64
|
* depend on a web framework
|
|
64
|
-
* have an opinion of how
|
|
65
|
+
* have an opinion of how or where you use it
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
In addition, *reader* provides:
|
|
67
68
|
|
|
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
|
|
69
|
+
* an optional web application based on Flask, Bootstrap, and htmx
|
|
70
|
+
* an optional command-line interface
|
|
74
71
|
|
|
75
72
|
.. end-features
|
|
76
73
|
|
|
@@ -67,6 +67,17 @@ Data objects
|
|
|
67
67
|
.. autoclass:: EntryUpdateStatus
|
|
68
68
|
:members:
|
|
69
69
|
|
|
70
|
+
.. autoclass:: FeedToImport
|
|
71
|
+
:members:
|
|
72
|
+
:undoc-members:
|
|
73
|
+
|
|
74
|
+
.. autoclass:: FeedImportResult
|
|
75
|
+
:members:
|
|
76
|
+
|
|
77
|
+
.. autoclass:: FeedExport
|
|
78
|
+
:members:
|
|
79
|
+
|
|
80
|
+
|
|
70
81
|
|
|
71
82
|
Exceptions
|
|
72
83
|
----------
|
|
@@ -155,6 +166,9 @@ Exceptions
|
|
|
155
166
|
.. autoexception:: PluginInitError
|
|
156
167
|
:show-inheritance:
|
|
157
168
|
|
|
169
|
+
.. autoexception:: FeedImportError
|
|
170
|
+
:show-inheritance:
|
|
171
|
+
|
|
158
172
|
|
|
159
173
|
.. autoexception:: ReaderWarning
|
|
160
174
|
:show-inheritance:
|
|
@@ -214,3 +228,10 @@ Utilities
|
|
|
214
228
|
---------
|
|
215
229
|
|
|
216
230
|
.. autofunction:: reader.utils.archive_entries
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
``reader.opml``
|
|
235
|
+
---------------
|
|
236
|
+
|
|
237
|
+
.. automodule:: reader.opml
|
reader-3.23/docs/app.rst
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
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
|
+
.. _screenshots-import:
|
|
66
|
+
|
|
67
|
+
.. figure:: screenshots/import-select.png
|
|
68
|
+
:width: 240px
|
|
69
|
+
|
|
70
|
+
import feeds (select)
|
|
71
|
+
|
|
72
|
+
.. figure:: screenshots/import-result.png
|
|
73
|
+
:width: 240px
|
|
74
|
+
|
|
75
|
+
import feeds (result)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
Serving the web app
|
|
80
|
+
-------------------
|
|
81
|
+
|
|
82
|
+
.. note::
|
|
83
|
+
|
|
84
|
+
The web application is optional, use the ``app`` extra to install
|
|
85
|
+
its :ref:`dependencies <Optional dependencies>`.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
*reader* exposes a standard WSGI application as ``reader._app.wsgi:app``.
|
|
89
|
+
See the `Flask documentation`_ for more details on how to deploy it.
|
|
90
|
+
The path to the reader database can be configured through the
|
|
91
|
+
:doc:`config file <config>`
|
|
92
|
+
or the ``READER_DB`` environment variable.
|
|
93
|
+
|
|
94
|
+
.. warning::
|
|
95
|
+
|
|
96
|
+
The web application has no authentication / authorization whatsoever;
|
|
97
|
+
it is expected a server / middleware will provide that.
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
An example uWSGI configuration file (probably not idiomatic, from `here`_)::
|
|
101
|
+
|
|
102
|
+
[uwsgi]
|
|
103
|
+
socket = /apps/reader/uwsgi/sock
|
|
104
|
+
manage-script-name = true
|
|
105
|
+
mount = /reader=reader._app.wsgi:app
|
|
106
|
+
plugin = python3
|
|
107
|
+
virtualenv = /apps/reader/
|
|
108
|
+
env = READER_CONFIG=/apps/reader/reader.toml
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
You can also run the web application with the ``web`` command.
|
|
112
|
+
``web`` uses `Werkzeug's development server`_,
|
|
113
|
+
so it probably won't scale well past a single user.
|
|
114
|
+
|
|
115
|
+
.. note::
|
|
116
|
+
|
|
117
|
+
For privacy reasons,
|
|
118
|
+
you may want to configure your web server to not send a ``Referer`` header
|
|
119
|
+
(by setting ``Referrer-Policy`` header to ``same-origin``
|
|
120
|
+
for all responses; `nginx example`_).
|
|
121
|
+
The ``web`` command does it by default.
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
If running on a personal computer, you can use cron to run it at boot::
|
|
125
|
+
|
|
126
|
+
@reboot sleep 60; reader web -p 8080 2>&1 ) >>"/tmp/$LOGNAME.reader.web.run.boot.log"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
.. _here: https://github.com/lemon24/owncloud/blob/8009f227ef60ebaab621e7bb3363ec9071d8a2e8/reader.yaml#L103-L116
|
|
130
|
+
.. _nginx example: https://github.com/lemon24/owncloud/blob/8009f227ef60ebaab621e7bb3363ec9071d8a2e8/secure.conf#L23
|
|
131
|
+
.. _Flask documentation: https://flask.palletsprojects.com/en/stable/deploying/
|
|
132
|
+
.. _Werkzeug's development server: https://werkzeug.palletsprojects.com/en/stable/serving/#werkzeug.serving.run_simple
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
.. _legacy web app:
|
|
137
|
+
|
|
138
|
+
Legacy web app
|
|
139
|
+
--------------
|
|
140
|
+
|
|
141
|
+
Before the current web application,
|
|
142
|
+
there was another one,
|
|
143
|
+
serving as test bed for new features.
|
|
144
|
+
It is usable, if a bit unpolished,
|
|
145
|
+
but was never meant to be a long-term thing,
|
|
146
|
+
hence the new app;
|
|
147
|
+
you can find screenshots
|
|
148
|
+
`here <https://github.com/lemon24/reader/blob/3.21/docs/app.rst#screenshots-legacy>`_.
|
|
149
|
+
|
|
150
|
+
The WSGI entry point is ``reader._app.legacy.wsgi:app``.
|
|
151
|
+
|
|
152
|
+
The legacy web app should remain available
|
|
153
|
+
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:
|
|
@@ -6,7 +6,6 @@ import unittest.mock
|
|
|
6
6
|
import packaging.version
|
|
7
7
|
from setuptools.config.pyprojecttoml import read_configuration
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
sys.path.insert(0, os.path.abspath('../src'))
|
|
11
10
|
|
|
12
11
|
# mock some things "by hand", so we can import reader below without any dependencies
|
|
@@ -17,6 +16,7 @@ for name in [
|
|
|
17
16
|
'flask.signals',
|
|
18
17
|
'werkzeug',
|
|
19
18
|
'werkzeug.datastructures',
|
|
19
|
+
'werkzeug.exceptions',
|
|
20
20
|
'werkzeug.http',
|
|
21
21
|
'yaml',
|
|
22
22
|
]:
|
|
@@ -24,7 +24,6 @@ for name in [
|
|
|
24
24
|
|
|
25
25
|
import reader
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
extensions = [
|
|
29
28
|
'sphinx_rtd_theme',
|
|
30
29
|
'sphinx.ext.autodoc',
|
|
@@ -45,6 +44,7 @@ autodoc_mock_imports = [
|
|
|
45
44
|
'bs4',
|
|
46
45
|
'mutagen',
|
|
47
46
|
'flask',
|
|
47
|
+
'flask_wtf',
|
|
48
48
|
'werkzeug',
|
|
49
49
|
'humanize',
|
|
50
50
|
'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
|
|
@@ -32,7 +32,6 @@ in my spare time,
|
|
|
32
32
|
but I will prioritize supporting :doc:`contributors <contributing>`
|
|
33
33
|
(discussions, reviews and so on).
|
|
34
34
|
|
|
35
|
-
* OPML support, :issue:`165`
|
|
36
35
|
* :ref:`deleting entries <deleting entries>`
|
|
37
36
|
|
|
38
37
|
* archiving important entries of deleted feeds, :issue:`290`
|
|
@@ -59,22 +58,22 @@ but I will prioritize supporting :doc:`contributors <contributing>`
|
|
|
59
58
|
* resource tags
|
|
60
59
|
|
|
61
60
|
* :ref:`searchable tag values <searchable tags>`, e.g. for comments
|
|
62
|
-
* :ref:`unification with entry.read/important <entry flag unification>`
|
|
63
61
|
* optimistic locking, :issue:`308`
|
|
64
62
|
* filter tags by prefix, :issue:`309`
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
* HTTP compliance, likely as plugins
|
|
64
|
+
* HTTP behavior / compliance, likely as plugins, :issue:`377`
|
|
68
65
|
|
|
69
66
|
* 301 Moved Permanently, :issue:`246`
|
|
70
67
|
* 410 Gone, :issue:`246`
|
|
71
|
-
*
|
|
68
|
+
* slow down on throttling / max-age, :issue:`378`
|
|
69
|
+
* match the rhythm of the feed, :issue:`382`
|
|
72
70
|
|
|
73
71
|
* add more fields to data objects
|
|
74
72
|
|
|
73
|
+
* .links attribute, :issue:`320`
|
|
74
|
+
* .authors attribute, :issue:`391`
|
|
75
75
|
* extra data, as an escape hatch, :issue:`277`
|
|
76
76
|
|
|
77
|
-
* :ref:`multiple storage implementations <multiple storage implementations>`
|
|
78
77
|
* :ref:`batch get methods <batch get methods>`
|
|
79
78
|
* :doc:`internal` stabilization
|
|
80
79
|
* arbitrary website scraping, :issue:`222`
|
|
@@ -93,15 +92,16 @@ but I will prioritize supporting :doc:`contributors <contributing>`
|
|
|
93
92
|
Command-line interface
|
|
94
93
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
95
94
|
|
|
96
|
-
The :doc:`cli` is more or less stable
|
|
97
|
-
although
|
|
98
|
-
and additional tests.
|
|
95
|
+
The :doc:`cli` is more or less stable,
|
|
96
|
+
although it could use additional tests.
|
|
99
97
|
|
|
100
|
-
A
|
|
98
|
+
A terminal feed reader is *not* in scope,
|
|
101
99
|
since I don't need one,
|
|
102
|
-
but I'm not opposed to the idea
|
|
100
|
+
but I'm not opposed to the idea;
|
|
101
|
+
note that the web app should already
|
|
102
|
+
work with text-based browsers such as `Lynx`_.
|
|
103
103
|
|
|
104
|
-
..
|
|
104
|
+
.. _Lynx: https://en.wikipedia.org/wiki/Lynx_(web_browser)
|
|
105
105
|
|
|
106
106
|
|
|
107
107
|
.. _app roadmap:
|
|
@@ -109,27 +109,23 @@ but I'm not opposed to the idea.
|
|
|
109
109
|
Web application
|
|
110
110
|
~~~~~~~~~~~~~~~
|
|
111
111
|
|
|
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
|
|
112
|
+
The new :doc:`app` is under active development.
|
|
113
|
+
I am working on adding features
|
|
114
|
+
already implemented in the library
|
|
115
|
+
and the :ref:`legacy web app <legacy web app>`,
|
|
116
|
+
and possibly on a hosted version.
|
|
124
117
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
118
|
+
Like with the library,
|
|
119
|
+
the goal is to keep it simple to use
|
|
120
|
+
and sustainable to maintain long-term;
|
|
121
|
+
the decision to use `Flask`_, `Bootstrap`_, and `htmx`_ is part of this
|
|
122
|
+
(if they were around for ~15 years,
|
|
123
|
+
they should be around for 15 more).
|
|
130
124
|
|
|
131
|
-
..
|
|
125
|
+
.. _Flask: https://flask.palletsprojects.com/
|
|
132
126
|
.. _Bootstrap: https://getbootstrap.com/
|
|
127
|
+
.. _htmx: https://htmx.org/
|
|
128
|
+
|
|
133
129
|
|
|
134
130
|
|
|
135
131
|
.. _compat:
|
|
@@ -677,7 +673,10 @@ Why I want to postpone batch update/set methods:
|
|
|
677
673
|
tl:dr: Performance is likely a non-issue with SQLite,
|
|
678
674
|
convenience can be added on top as a plugin.
|
|
679
675
|
|
|
680
|
-
(2025) Why it may be worth adding batch interfaces anyway
|
|
676
|
+
(2025 update) Why it may be worth adding batch interfaces anyway
|
|
677
|
+
(even if underneath the storage implementation doesn't actually batch)
|
|
678
|
+
– it allows for future optimization:
|
|
679
|
+
https://blog.glyph.im/2022/12/potato-programming.html
|
|
681
680
|
|
|
682
681
|
See the 2.12 reader._app.ResourceTags class for an idea of how to
|
|
683
682
|
represent a bunch of tags in a reserved-name-scheme-agnostic way
|
|
@@ -771,10 +770,3 @@ REST API
|
|
|
771
770
|
|
|
772
771
|
Some early thoughts: :issue:`192#issuecomment-700773138`
|
|
773
772
|
(closed with `wontfix`, for now).
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
Web application
|
|
777
|
-
~~~~~~~~~~~~~~~
|
|
778
|
-
|
|
779
|
-
.. toctree::
|
|
780
|
-
dev-app
|