summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsupahgreg <supahgreg@users.noreply.github.com>2025-10-05 19:09:04 +0000
committersupahgreg <supahgreg@users.noreply.github.com>2025-10-05 19:09:04 +0000
commita00ef6440f98b0ff1052e5cf75b89d8dd3a38330 (patch)
tree79d20824e86cafa42075708ab9a76f262f004cb6
parent4591dcb22290576dbf114fff1c3f3b0ca5ffaf8d (diff)
Add initial content (with issues).
-rw-r--r--Android-Client.md58
-rw-r--r--Api-Reference.md456
-rw-r--r--Archived-Feed.md10
-rw-r--r--Content-Filters.md73
-rw-r--r--Email-Digests.md15
-rw-r--r--Encryption.md15
-rw-r--r--FAQ.md138
-rw-r--r--Feed-Handler-Plugins.md30
-rw-r--r--Generated-Feeds.md83
-rw-r--r--Global-Config.md78
-rw-r--r--Home.md67
-rw-r--r--Installation-Notes.md466
-rw-r--r--Making-Plugins.md35
-rw-r--r--Plugins.md128
-rw-r--r--Publish-Articles.md18
-rw-r--r--SSL-Certificate-Authentication.md93
-rw-r--r--Scoring.md28
-rw-r--r--Search-Syntax.md22
-rw-r--r--Securing-Cache-Directories.md40
-rw-r--r--Share-Anything.md14
-rw-r--r--Sorting.md54
-rw-r--r--Themes.md47
-rw-r--r--ZeEpube.md129
-rw-r--r--images/bears_1.pngbin0 -> 1272 bytes
-rw-r--r--images/bears_2.pngbin0 -> 1406 bytes
-rw-r--r--images/bears_3.pngbin0 -> 1527 bytes
-rw-r--r--images/bears_4.pngbin0 -> 1549 bytes
-rw-r--r--images/can your chat client do this.pngbin0 -> 71443 bytes
-rw-r--r--images/candy-cane.pngbin0 -> 3044 bytes
-rw-r--r--images/epube/2019/library1.pngbin0 -> 881394 bytes
-rw-r--r--images/epube/2019/library1.webpbin0 -> 101424 bytes
-rw-r--r--images/epube/2019/library2.pngbin0 -> 174487 bytes
-rw-r--r--images/epube/2019/library2.webpbin0 -> 22464 bytes
-rw-r--r--images/epube/2019/reader1.pngbin0 -> 722298 bytes
-rw-r--r--images/epube/2019/reader1.webpbin0 -> 129838 bytes
-rw-r--r--images/epube/2019/reader2.pngbin0 -> 67847 bytes
-rw-r--r--images/epube/2019/reader2.webpbin0 -> 31940 bytes
-rw-r--r--images/epube/2019/reader3.pngbin0 -> 454315 bytes
-rw-r--r--images/epube/2019/reader3.webpbin0 -> 60816 bytes
-rw-r--r--images/epube/Screenshot_2025-05-16_at_15.50.58.pngbin0 -> 2922928 bytes
-rw-r--r--images/epube/Screenshot_2025-05-16_at_15.50.58.webpbin0 -> 280074 bytes
-rw-r--r--images/epube/Screenshot_2025-05-16_at_15.52.29.pngbin0 -> 684762 bytes
-rw-r--r--images/epube/Screenshot_2025-05-16_at_15.52.29.webpbin0 -> 266322 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_155939.pngbin0 -> 2296763 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_155939.webpbin0 -> 153908 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_160100.pngbin0 -> 265095 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_160100.webpbin0 -> 139520 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_160122.pngbin0 -> 221703 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_160122.webpbin0 -> 94346 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164212.pngbin0 -> 2357144 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164212.webpbin0 -> 164698 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164304.pngbin0 -> 264215 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164304.webpbin0 -> 133552 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164403.pngbin0 -> 240665 bytes
-rw-r--r--images/epube/mobile/Screenshot_20250516_164403.webpbin0 -> 119942 bytes
-rw-r--r--images/feed-icon.svg18
-rw-r--r--images/gen_feed_dialog.pngbin0 -> 24137 bytes
-rw-r--r--images/gen_feed_icon.pngbin0 -> 3990 bytes
-rw-r--r--images/icon_classic_128.pngbin0 -> 10968 bytes
-rw-r--r--images/icon_classic_72.pngbin0 -> 5582 bytes
-rw-r--r--images/publish_articles.pngbin0 -> 12519 bytes
-rwxr-xr-ximages/repo-avatars/11.pngbin0 -> 39093 bytes
-rwxr-xr-ximages/repo-avatars/111.pngbin0 -> 4628 bytes
-rwxr-xr-ximages/repo-avatars/13.pngbin0 -> 18205 bytes
-rwxr-xr-ximages/repo-avatars/166.pngbin0 -> 11458 bytes
-rwxr-xr-ximages/repo-avatars/2.pngbin0 -> 31657 bytes
-rwxr-xr-ximages/repo-avatars/3.pngbin0 -> 10787 bytes
-rwxr-xr-ximages/repo-avatars/4.pngbin0 -> 16508 bytes
-rwxr-xr-ximages/repo-avatars/55.pngbin0 -> 9054 bytes
-rwxr-xr-ximages/repo-avatars/baseline_extension_black_48dp.pngbin0 -> 605 bytes
-rwxr-xr-ximages/repo-avatars/iconfinder_social_media_social_media_logo_docker_1916029.pngbin0 -> 2547 bytes
-rw-r--r--images/score_indicator2.pngbin0 -> 2142 bytes
-rw-r--r--images/share_anything.pngbin0 -> 21907 bytes
-rw-r--r--images/tt-comics-web/index.pngbin0 -> 65556 bytes
-rw-r--r--images/tt-comics-web/reader.pngbin0 -> 24963 bytes
-rw-r--r--images/tt-comics/library.jpgbin0 -> 430621 bytes
-rw-r--r--images/tt-comics/library_small.jpgbin0 -> 150371 bytes
-rw-r--r--images/tt-comics/reader.jpgbin0 -> 174835 bytes
-rw-r--r--images/tt-comics/reader_small.jpgbin0 -> 68057 bytes
-rw-r--r--images/tt-irc/ttirc_screenshot-OLD.pngbin0 -> 169606 bytes
-rw-r--r--images/tt-irc/ttirc_screenshot.pngbin0 -> 1237518 bytes
-rw-r--r--images/tt-irc/ttirc_screenshot_light.pngbin0 -> 334071 bytes
-rw-r--r--images/tt-irc/ttirc_screenshot_light_small.jpgbin0 -> 24716 bytes
-rw-r--r--images/tt-irc/ttirc_screenshot_small.jpgbin0 -> 34988 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135136.pngbin0 -> 194642 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135136.webpbin0 -> 103296 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135154.pngbin0 -> 118027 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135154.webpbin0 -> 39328 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135217.pngbin0 -> 126623 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135217.webpbin0 -> 62868 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135426.pngbin0 -> 193286 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135426.webpbin0 -> 104202 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135438.pngbin0 -> 128848 bytes
-rw-r--r--images/tt-rss-android/Screenshot_20250509_135438.webpbin0 -> 67094 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot1.pngbin0 -> 832947 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot1_small.jpgbin0 -> 17753 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot1_small.pngbin0 -> 86381 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot2.pngbin0 -> 374361 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot2_small.pngbin0 -> 47526 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot3.pngbin0 -> 501405 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot3_small.pngbin0 -> 55222 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot4.pngbin0 -> 229551 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot4_small.pngbin0 -> 30143 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot5.pngbin0 -> 380435 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot5_small.jpgbin0 -> 11319 bytes
-rw-r--r--images/tt-rss/18.12/1812-shot5_small.pngbin0 -> 50089 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152046.pngbin0 -> 1775880 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152046.webpbin0 -> 185302 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152046_350px.webpbin0 -> 11122 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152846.pngbin0 -> 961153 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152846.webpbin0 -> 165446 bytes
-rw-r--r--images/tt-rss/21.03/Screenshot_2021-03-10_152846_350px.webpbin0 -> 8720 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.pngbin0 -> 1365142 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.webpbin0 -> 400894 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.pngbin0 -> 5802705 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webpbin0 -> 639236 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.pngbin0 -> 2675158 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webpbin0 -> 470018 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.pngbin0 -> 1612765 bytes
-rw-r--r--images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webpbin0 -> 492134 bytes
-rw-r--r--images/xmas-tree.pngbin0 -> 9050 bytes
-rw-r--r--images/xmas_hat_128.pngbin0 -> 27017 bytes
-rw-r--r--index.md66
-rw-r--r--stylesheets/extra.css10
124 files changed, 2190 insertions, 1 deletions
diff --git a/Android-Client.md b/Android-Client.md
new file mode 100644
index 0000000..8e19774
--- /dev/null
+++ b/Android-Client.md
@@ -0,0 +1,58 @@
+---
+hide:
+ - navigation
+---
+
+# Android client
+
+## **IMPORTANT**
+
+This content is no longer accurate, given the original tt-rss project has closed.
+
+## Screenshots
+
+![](images/tt-rss-android/Screenshot_20250509_135136.webp){ width="120", align=left }
+
+![](images/tt-rss-android/Screenshot_20250509_135154.webp){ width="120", align=left }
+
+![](images/tt-rss-android/Screenshot_20250509_135217.webp){ width="120", align=left }
+
+![](images/tt-rss-android/Screenshot_20250509_135426.webp){ width="120", align=left }
+
+![](images/tt-rss-android/Screenshot_20250509_135438.webp){ width="120" }
+
+## Download
+
+Releases are built automatically for every commit pushed to master branch and [published on Gitlab](https://gitlab.tt-rss.org/tt-rss/tt-rss-android/-/releases).
+
+!!! warning
+
+ This is the only official and supported way to get the APK. If you see the app on any marketplace or anywhere else, it had been uploaded there without my knowledge or consent.
+
+Release APKs are signed. You can verify the signature using [apksigner](https://developer.android.com/tools/apksigner):
+
+```sh
+$ apksigner verify --print-certs org.fox.ttrss-signed.apk
+Signer #1 certificate DN: CN=Andrew Dolgov, OU=N/A, O=tt-rss.org, L=Saint-Petersburg, ST=N/A, C=RU
+Signer #1 certificate SHA-256 digest: c74664ba0fd8f8c97e2a548926609df1369236dd9d9d14c0e5c20b8c2b08cf06
+Signer #1 certificate SHA-1 digest: ac97a3ced638cd750272dab50c08ca979910dc74
+Signer #1 certificate MD5 digest: e4f38ce99c44714e3c21821a1c13717f
+```
+
+Signature digests must match above values.
+
+## FAQ
+
+### How do I automatically update the APK?
+
+There's no built-in auto updater, I suggest using [Obtainium](https://obtainium.imranr.dev/) instead.
+
+When adding new application in Obtainium, paste [app project page](https://gitlab.tt-rss.org/tt-rss/tt-rss-android) in first field, and select "Gitlab" in the "Override source" dropdown below.
+
+### I want to help test the app! Are there development builds available?
+
+Sometimes. Releases are not created for signed non-master branch builds, you can get the APKs from build pipeline artifacts [here](https://gitlab.tt-rss.org/tt-rss/tt-rss-android/-/jobs) - look for `build-signed-branch-apk`. Non-master builds install as a separate application with a gray icon.
+
+### Why are you not on Google Play?
+
+As a small time FOSS developer, dealing with Google and their marketplace is a tremendous pain in the ass.
diff --git a/Api-Reference.md b/Api-Reference.md
new file mode 100644
index 0000000..2d1da5a
--- /dev/null
+++ b/Api-Reference.md
@@ -0,0 +1,456 @@
+---
+hide:
+ - navigation
+---
+
+# API
+
+API is pluggable, plugins can use host <code>add\_api\_method()</code> to add
+custom API calls (see <code>classes/pluginhost.php</code> for details).
+
+API is stateful. You need to login and maintain a session ID to perform further operations. Session ID should be specified using JSON parameter **sid**. I.e.
+
+```bash
+curl -d '{"sid":"your-session-id","op":"getVersion"}' http://example.com/tt-rss/api/
+```
+
+All API calls output JSON-encoded data. API can be enabled or disabled
+per-user in the preferences. Client parameters should be passed encoded
+using JSON in HTTP POST data (supported since version:1.5.3). Older
+versions allowed passing parameters using HTTP GET and POST, but this is
+no longer supported.
+
+### Numeric values
+
+Numbers can also be passed (and are sometimes returned) as quoted string literals, i.e. ``"0"``.
+
+Some tt-rss versions have issues recognizing ``0`` as a valid number
+(unimplemented strict type checking causes ``0`` to be equivalent to ``false``
+in ``getHeadlines``, etc) so it might be a good idea to pass numerics as quoted
+strings for better backwards compatibility.
+
+### Boolean values
+
+For boolean parameters the expected syntax is:
+
+- empty string, numeric zero, unquoted ``false`` literal (?), string literal ``"f"`` or ``"false"``: <b>FALSE</b>
+- anything else: <b>TRUE</b>
+
+## Testing API calls (using curl)
+
+```bash
+curl -d '{"op":"login","user":"you","password":"xxx"}' http://example.com/tt-rss/api/
+```
+
+```bash
+curl -d '{"sid":"...","op":"getHeadlines","feed_id":"0","is_cat":"1"}' http://example.com/tt-rss/api/
+```
+
+Most of the calls (except login, logout, isLoggedIn) require valid login session
+or will return this error object: <code>{"error":"NOT_LOGGED_IN"}</code>
+
+## Output format
+
+All API methods return JSON data like this:
+
+```json
+{"seq":0,"status":0,"content":{"version":"1.4.3.1"}}
+```
+
+- seq (integer) is the sequence number supplied by client (``"seq":131``)
+- status (integer) indicates whether request has been completed
+ successfully, can be either 0 (API\_STATUS\_OK) or 1
+ (API\_STATUS\_ERR)
+- content is the actual reply content, as documented below in method
+ descriptions.
+
+##### 1.4.3 and below (obsolete)
+
+Methods return the “content” object below, sequence numbers and statuses
+are not supported.
+
+Methods
+-------
+
+### getApiLevel (since version:1.5.8, api level 1)
+
+Return an abstracted integer API version level, increased with each API
+functionality change. This is the proper way to detect host API
+functionality, instead of using getVersion.
+
+```json
+{"level":1}
+```
+
+Whether tt-rss returns error for this method (e.g. version:1.5.7 and
+below) client should assume API level 0.
+
+### getVersion
+
+Returns tt-rss version. As of, version:1.5.8 it is not recommended to
+use this to detect API functionality, please use getApiLevel instead.
+
+```json
+{"version":"1.4.0"}
+```
+
+### login
+
+Parameters:
+
+- ``user`` (string)
+- ``password`` (string)
+
+Returns client session ID.
+
+```json
+{"session_id":"xxx"}
+```
+
+It can also return several error objects:
+
+- If API is disabled for this user:
+ <code>error: "API_DISABLED"</code>
+- If specified username and password are incorrect:
+ <code>error: "LOGIN_ERROR"</code>
+
+In case it isn’t immediately obvious, you have to login and get a
+session ID even if you are using single user mode. You can omit user and
+password parameters.
+
+- On version:1.6.0 and above login also returns current API level as an
+ <code>api\_level</code> integer, you can use that instead of calling `getApiLevel` after login.
+- Since API 17, also returns configuration object (see `getConfig` below).
+
+### logout
+
+Closes your login session. Returns either status-message <code>{"status":"OK"}</code> or an error (e.g. <code>{"error":"NOT_LOGGED_IN"}</code>)
+
+### isLoggedIn
+
+Returns a status message with boolean value showing whether your client (e.g.
+specific session ID) is currently logged in.
+
+```json
+{"status":false}
+```
+
+### getUnread
+
+Returns an integer value of currently unread articles.
+
+```json
+{"unread":"992"}
+```
+
+### getCounters
+
+Returns JSON-encoded counter information. Requires version:1.5.0.
+
+* ``output_mode`` (string, default: flc) - what kind of information to return (f - feeds, l - labels, c - categories, t - tags)
+
+### getFeeds
+
+Returns JSON-encoded list of feeds. The list includes category id,
+title, feed url, etc.
+
+Parameters:
+
+- ``cat_id`` (integer) - return feeds under category cat\_id
+- ``unread_only`` (bool) - only return feeds which have unread articles
+- ``limit`` (integer) - limit amount of feeds returned to this value
+- ``offset`` (integer) - skip this amount of feeds first
+- ``include_nested`` (bool) - include child categories (as Feed objects
+ ``with is_cat set)`` **requires version:1.6.0**
+
+Pagination:
+
+Limit and offset are useful if you need feedlist pagination. If you use
+them, you shouldn’t filter by unread, handle filtering in your app
+instead.
+
+Special category IDs are as follows:
+
+* 0 Uncategorized
+* -1 Special (e.g. Starred, Published, Archived, etc.)
+* -2 Labels
+
+Added in version:1.5.0:
+
+- -3 All feeds, excluding virtual feeds (e.g. Labels and such)
+- -4 All feeds, including virtual feeds
+
+Known bug: Prior to version:1.5.0 passing null or 0 cat\_id to this
+method returns full list of feeds instead of Uncategorized feeds only.
+
+### getCategories
+
+Returns JSON-encoded list of categories with unread counts.
+
+- ``unread_only`` (bool) - only return categories which have unread
+ articles
+- ``enable_nested`` (bool) - switch to nested mode, only returns topmost
+ categories **requires version:1.6.0**
+- ``include_empty`` (bool) - include empty categories **requires
+ version:1.7.6**
+
+Nested mode in this case means that a flat list of **only** topmost
+categories is returned and unread counters include counters for child
+categories.
+
+This should be used as a starting point, to display a root list of all
+(for backwards compatibility) or topmost categories, use getFeeds to
+traverse deeper.
+
+### getHeadlines
+
+Returns JSON-encoded list of headlines.
+
+Parameters:
+
+- ``feed_id`` (integer|string) - only output articles for this feed (supports string values to retrieve tag virtual feeds since API level 18, otherwise integer)
+- ``limit`` (integer) - limits the amount of returned articles (see below)
+- ``skip`` (integer) - skip this amount of feeds first
+- ``filter`` (string) - currently unused (?)
+- ``is_cat`` (bool) - requested feed\_id is a category
+- ``show_excerpt`` (bool) - include article excerpt in the output
+- ``show_content`` (bool) - include full article text in the output
+- ``view_mode`` (string = all\_articles, unread, adaptive, marked,
+ updated)
+- ``include_attachments`` (bool) - include article attachments (e.g.
+ enclosures) **requires version:1.5.3**
+- ``since_id`` (integer) - only return articles with id greater than
+ ``since_id`` **requires version:1.5.6**
+- ``include_nested`` (boolean) - include articles from child categories
+ **requires version:1.6.0**
+- ``order_by`` (string) - override default sort order **requires
+ version:1.7.6**
+- ``sanitize`` (bool) - sanitize content or not **requires version:1.8**
+ (default: true)
+- ``force_update`` (bool) - try to update feed before showing headlines
+ **requires version:1.14 (api 9)** (default: false)
+- ``has_sandbox`` (bool) - indicate support for sandboxing of iframe
+ elements **<span class="10 api"></span>** (default: false)
+- ``include_header`` (bool) - adds status information when returning
+ headlines, instead of array(articles) return value changes to
+ array(header, array(articles)) (api 12)
+
+Limit:
+
+Before **API level 6** maximum amount of returned headlines is capped at
+60, API 6 and above sets it to 200.
+
+This parameters might change in the future (supported since **API level
+2**):
+
+- ``search`` (string) - search query (e.g. a list of keywords)
+- ``search_mode`` (string) - all\_feeds, this\_feed (default), this\_cat
+ (category containing requested feed)
+- ``match_on`` (string) - ignored
+
+Special feed IDs are as follows:
+
+- -1 starred
+- -2 published
+- -3 fresh
+- -4 all articles
+- 0 - archived
+- IDs \< -10 labels
+
+Sort order values:
+
+- ``date_reverse`` - oldest first
+- ``feed_dates`` - newest first, goes by feed date
+- ``(nothing)`` - default
+
+### updateArticle
+
+Update information on specified articles.
+
+Parameters:
+
+- ``article_ids`` (comma-separated list of integers) - article IDs to
+ operate on
+- ``mode`` (integer) - type of operation to perform (0 - set to false, 1 -
+ set to true, 2 - toggle)
+- ``field`` (integer) - field to operate on (0 - starred, 1 - published, 2 - unread, 3 - article note **since api level 1**)
+- ``data`` (string) - optional data parameter when setting note field
+ (since **api level 1**)
+
+E.g. to set unread status of articles X and Y to false use the
+following:
+
+<code>?article\_ids=X,Y&mode=0&field=2</code>
+
+Since version:1.5.0 returns a status message:
+
+```json
+{"status":"OK","updated":1}
+```
+
+“Updated” is number of articles updated by the query.
+
+### getArticle
+
+Requests JSON-encoded article object with specific ID.
+
+- ``article_id`` (integer) - article ID to return **as of 15.10.2010
+ git** or version:1.5.0 supports comma-separated list of IDs
+
+Since version:1.4.3 also returns article attachments.
+
+### getConfig
+
+Returns tt-rss configuration parameters:
+
+```json
+{"icons_dir":"icons","icons_url":"icons","daemon_is_running":true,"num_feeds":71}
+```
+
+- ``icons_dir`` - path to icons on the server filesystem
+- ``icons_url`` - path to icons when requesting them over http
+- ``daemon_is_running`` - whether update daemon is running
+- ``num_feeds`` - amount of subscribed feeds (this can be used to refresh
+ feedlist when this amount changes)
+- ``custom_sort_types`` - map of plugin-provided article sort types (API 17+)
+
+### updateFeed
+
+Tries to update specified feed. This operation is not performed in the
+background, so it might take considerable time and, potentially, be
+aborted by the HTTP server.
+
+- ``feed_id`` (integer) - ID of feed to update
+
+Returns status-message if the operation has been completed.
+
+```json
+{"status":"OK"}
+```
+
+### getPref
+
+Returns preference value of specified key.
+
+- ``pref_name`` (string) - preference key to return value of
+
+```json
+{"value":true}
+```
+
+### catchupFeed
+
+Required version: version:1.4.3
+
+Tries to catchup (e.g. mark as read) specified feed.
+
+Parameters:
+
+- ``feed_id`` (integer) - ID of feed to update
+- ``is_cat`` (boolean) - true if the specified feed\_id is a category
+- ``mode`` (string) - optional: one of `all`, `1day`, `1week`, `2week`. defaults to `all`. **since api level 15**.
+
+Returns status-message if the operation has been completed.
+
+```json
+{"status":"OK"}
+```
+
+### getCounters
+
+Required version: version:1.5.0
+
+Returns a list of unread article counts for specified feed groups.
+
+Parameters:
+
+- ``output_mode`` (string) - Feed groups to return counters for
+
+Output mode is a character string, comprising several letters (defaults
+to “flc”):
+
+- f - actual feeds
+- l - labels
+- c - categories
+- t - tags
+
+Several global counters are returned as well, those can’t be disabled
+with output\_mode.
+
+### getLabels (since API level 1)
+
+Returns list of configured labels, as an array of label objects:
+
+```json
+{"id":2,"caption":"Debian","fg_color":"#e14a00","bg_color":"#ffffff","checked":false},
+```
+
+Before version:1.7.5
+
+Returned id is an internal database id of the label, you can convert it
+to the valid feed id like this:
+
+<code>feed\_id = \-11 - label\_id</code>
+
+After:
+
+No conversion is necessary.
+
+Parameters:
+
+* ``article_id`` (int) - set “checked” to true if specified article id has returned label.
+
+### setArticleLabel (since API level 1)
+
+Assigns article\_ids to specified label.
+
+Parameters:
+
+* ``article_ids`` - comma-separated list of article ids
+* ``label_id`` (int) - label id, as returned in getLabels
+* ``assign`` (boolean) - assign or remove label
+
+Note: Up until version:1.15 setArticleLabel() clears the label cache for
+the specified articles. Make sure to regenerate it (e.g. by calling API
+method getLabels() for the respecting articles) when you’re using
+methods which don’t do that by themselves (e.g. getHeadlines())
+otherwise getHeadlines() will not return labels for modified articles.
+
+### shareToPublished (since API level 4 - version:1.6.0)
+
+Creates an article with specified data in the Published feed.
+
+Parameters:
+
+* ``title`` - Article title (string)
+* ``url`` - Article URL (string)
+* ``content`` - Article content (string)
+* ``sanitize`` (bool) - allows inserting HTML if disabled **requires API level 20** (default: true)
+
+### subscribeToFeed (API level 5 - version:1.7.6)
+
+Subscribes to specified feed, returns a status code. See
+subscribe\_to\_feed() in functions.php for details.
+
+Parameters:
+
+* ``feed_url`` - Feed URL (string)
+* ``category_id`` - Category id to place feed into (defaults to 0, Uncategorized) (int)
+* ``login``, ``password`` - Self explanatory (string)
+
+### unsubscribeFeed (API level 5 - version:1.7.6)
+
+Unsubscribes specified feed.
+
+Parameters:
+
+* ``feed_id`` - Feed id to unsubscribe from
+
+### getFeedTree (API level 5 - version:1.7.6)
+
+* ``include_empty`` (bool) - include empty categories
+
+Returns full tree of categories and feeds.
+
+Note: counters for most feeds are not returned with this call for
+performance reasons.
diff --git a/Archived-Feed.md b/Archived-Feed.md
new file mode 100644
index 0000000..31ec0d1
--- /dev/null
+++ b/Archived-Feed.md
@@ -0,0 +1,10 @@
+# Archived Feed
+
+Archived is the place for articles for which originating feed no longer exists.
+It's either Starred articles from unsubscribed feeds or [externally shared
+data](ShareAnything.md).
+
+!!! notice
+
+ Articles in Archived feed are not expired automatically, you can delete them manually
+ using `Select...` &rarr; `Delete permanently` in the main toolbar.
diff --git a/Content-Filters.md b/Content-Filters.md
new file mode 100644
index 0000000..c9708ce
--- /dev/null
+++ b/Content-Filters.md
@@ -0,0 +1,73 @@
+# Filters
+
+Filters are a very powerful and flexible tool which may significantly ease the
+task of extracting useful information from the sea of data that is RSS feeds.
+Filters are applied to articles based on [regular
+expression](http://en.wikipedia.org/wiki/Regular_expression) matches against
+specified fields. After the match had been found, configured actions are taken.
+Matching is case-insensitive,
+[PCRE](http://php.net/manual/en/reference.pcre.pattern.syntax.php) pattern
+syntax is used.
+
+!!! notice
+
+ Filter test dialog may not give entirely accurate results, especially for
+ complex filters. It is suggested to test filters using ``Feed debugger`` (hotkey `f D`) if you
+ feel that some filter is somehow misfiring on a specific feed.
+
+### Load order
+
+Filters are loaded in user-specified order and applied sequentially. It is
+possible to reorder filters using drag and drop. If no manual sorting is
+specified, filters are sorted alphabetically according to user configured
+caption. If no caption is specified for any filter, loading order is not
+guaranteed.
+
+### Filter objects
+
+Each filter object may contain an arbitrary amount of regular expression rules
+and actions. Each expression may have inverse flag set, which inverts matching
+result. On top of that, filter may also have an inverse flag, which inverts the
+final matching.
+
+- Filter object may be configured to successfully match when either one or
+all rules match.
+- Regular expressions may be matched against several article fields, such
+as, title, content, author, etc.
+- Do not include delimiters (e.g. <code>/</code>) when writing regular
+expressions.
+
+### Matching articles and applying actions
+
+Filter matching is performed during feed processing.
+
+!!! notice
+
+ Some actions may be applied only when the article is initially imported from the
+ feed. Other actions may be applied every time article is seen in the originating
+ feed. It is suggested to only rely on filters applying to articles imported
+ after the filter had been created - they will not retroactively apply to your
+ article database.
+
+Several actions are available:
+
+!!! warning
+
+ Filters may not apply actions conditionally based on previous filters. All actions for an article are applied together, once.
+
+1. ``Delete article`` - do not import article from the feed, does not
+actually delete anything from the database
+2. ``Mark as read`` - imports article automatically marked as read
+3. ``Set starred`` - sets article starred automatically on import
+4. ``Assign tags`` - assigns a comma-separated list of custom tags on import
+5. ``Publish article`` - sets article published automatically on import
+6. ``Modify score`` ([Scoring](Scoring.md)) - modifies article overall score based on
+the parameter, a signed integer number. Final article score is calculated after all filters had been applied and is a sum of all matched scoring actions.
+7. ``Assign label`` - assigns specified label to the article on import
+8. ``Stop / Do nothing`` - stops further filter processing for this article, no following filters will be checked nor rules applied.
+9. ``Invoke plugin`` - runs a plugin action when filter is matched
+10. ``Ignore tags`` - a comma-separated list of tags which will be skipped on article import
+
+After all matching filters had been computed for the article, it is either
+imported with modifications as specified by the rules, or dropped if `Delete
+article` action has been found.
diff --git a/Email-Digests.md b/Email-Digests.md
new file mode 100644
index 0000000..4f7b629
--- /dev/null
+++ b/Email-Digests.md
@@ -0,0 +1,15 @@
+# Email Digests
+
+Users may opt into receiving daily (sent once every 24 hours) digests of unread headlines via email.
+
+Digests are sent out by the update daemon or if running <code>update.php —feeds</code>
+manually. At most 15 messages are sent in one batch.
+
+!!! notice
+
+ [PHPMailer plugin](https://github.com/supahgreg/tt-rss-plugin-mailer-smtp) is required to send mail under Docker.
+
+
+* Digests may be customized by editing ``templates/digest_template*.txt``.
+* You can preview your digest contents in preferences.
+
diff --git a/Encryption.md b/Encryption.md
new file mode 100644
index 0000000..7f77138
--- /dev/null
+++ b/Encryption.md
@@ -0,0 +1,15 @@
+# At rest encryption
+
+Transparent at rest encryption is optionally supported for sensitive data stored in the database, currently limited to stored session data and passwords for feeds with authentication enabled.
+
+To enable, [global configuration](GlobalConfig.md) option `TTRSS_ENCRYPTION_KEY` should be set to a 32-byte hex string of random bytes, which may be generated using CLI like this:
+
+```sh
+php ./update.php --gen-encryption-key
+```
+
+If enabled, existing plaintext login sessions are automatically encrypted when used, plaintext feed passwords are encrypted on feed update.
+
+!!! warning
+
+ Automatic encryption of plaintext data is a one-way process. If you decide to disable `TTRSS_ENCRYPTION_KEY` afterwards, all encrypted sessions would become invalid and you will get logged out. Feed passwords would become unreadable until you either enable encryption back using same key or edit feeds manually.
diff --git a/FAQ.md b/FAQ.md
new file mode 100644
index 0000000..7e29bb4
--- /dev/null
+++ b/FAQ.md
@@ -0,0 +1,138 @@
+---
+hide:
+ - navigation
+---
+
+# FAQ
+
+!!! notice
+
+ [Docker-related stuff has a separate FAQ page](wiki/InstallationNotes.md#faq)
+
+### I want to check how tt-rss renders my feed / the feed I'm trying to use is parsed incorrectly
+
+- tt-rss expects valid XML feed data which is parsed using libxml. Any XML parse errors, should you feel that libxml is misbehaving (which is unlikely), should be reported to libxml developers. We don't add hacks for invalid XML on tt-rss side.
+
+Plugins may affect parsing, consider disabling any plugins before investigating XML-related issues.
+
+### I managed to lock myself out of tt-rss
+
+This assumes you can't simply reset your password via email (login form - forgot my password).
+
+If you have OTP (2FA) enabled and know your password but can't provide an OTP token, you can disable OTP via SQL:
+
+```
+UPDATE ttrss_users SET otp_enabled = false WHERE login = 'you'
+```
+
+If you don't remember your password run the following query:
+
+```
+UPDATE ttrss_users
+ SET pwd_hash = 'SHA1:5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', salt = '', otp_enabled = false
+ WHERE login = 'you'
+```
+
+This sets your password back to default (``password``) and disables OTP.
+
+### I have HTTP authentication enabled and get “Your access level is insufficient to run this script” error on login
+
+The problem is that if you have `auth_remote` enabled in [PLUGINS](wiki/GlobalConfig.md) tt-rss tries to automatically log you in as the user specified by the server using HTTP authentication, which may not have administrative privileges.
+
+The easiest way is simply updating database using CLI (`php ./update.php --update-schema`). Docker setup does this on startup.
+
+Alternatively, you can either temporarily disable `auth_remote` (replace it with `auth_internal`), temporarily disable HTTP authentication, or give yourself administrative permissions using SQL:
+
+```sql
+ update ttrss_users set access_level = 10 where login = 'you';
+```
+
+### UI is missing CSS or is otherwise visibly broken
+
+- Try opening tt-rss using safe mode, clean browser profile, or an incognito
+ window (a different browser would also work)
+- Unless you're using SSL, try a different network connection in case your ISP is MITMing you
+- Some values of ``Content-Security-Policy`` header may break tt-rss, if you
+ have this header set in your httpd config, try disabling it temporarily
+- Check for any files in ``(tt-rss)/themes`` not known to Git (especially
+ ``default.php`` or ``default.css`` - formerly default CSS themes for tt-rss,
+ now removed), try temporarily removing all third party themes from
+ ``themes.local``
+
+### Third party theme or plugin broke after update making the UI unusable
+
+Log in to tt-rss in safe mode (use an incognito window if you can't get to login page).
+
+### I want to limit height of images to something more manageable
+
+For combined mode:
+
+```
+body.ttrss_main .cdm .content img, body.ttrss_main .cdm .content video {
+ max-height : 90vh;
+ height : auto;
+}
+
+```
+
+`90vh` means "90% of viewport height". This works on Chromium and derivatives, you can use `90%` for Firefox.
+
+### Feeds stop updating for users who rarely login
+
+This is controlled by a global configuration setting. You can override (or disable) it through environment or `config.php` by setting `TTRSS_DAEMON_UPDATE_LOGIN_LIMIT` to `0`.
+
+Note that this also effectively disables purging of articles stored for inactive users.
+
+### I have questions about article purging / I don't think purging works.
+
+Purging is performed on successful feed update, no updates = no purging.
+
+Starred articles are never purged, unread articles are purged if relevant preference is enabled.
+
+Purging is done based on import timestamp, internal to tt-rss. It may be different from article date specified by the feed (i.e. article says it was published on 1970/01/01 but it was imported today). You can see import timestamp if you hover over date in tt-rss web UI.
+
+Import date is bumped every time article is encountered in the feed, otherwise it will get purged and reimported again on every feed refresh, creating duplicates.
+
+When in doubt, use Feed debugger (`f D` on a feed) to see additional purging-related information:
+
+```
+[11:08:10/6783] purging feed...
+[11:08:10/6783] purge_feed: interval 60 days for feed XXX, owner: X, purge unread: 1
+[11:08:10/6783] purge_feed: deleted 1 articles.
+[11:08:10/6783] update done.
+```
+
+Related question:
+
+### I archive or delete articles manually and I get duplicates. Why?
+
+Because the articles are still in the feed XML and get pulled in (again) on next feed update.
+
+See also: [ArchivedFeed](wiki/ArchivedFeed.md)
+
+### I have used update daemon before, but switched away from it. However, the UI keeps nagging me about the daemon not running or not updating feeds or whatever.
+
+Find and delete daemon lock file in <code>LOCK_DIRECTORY</code>. Usually, it’s <code>lock/update_daemon.lock</code>. You can also remove <code>update_daemon.stamp</code>.
+
+### I need an URL I can call to subscribe to feed to integrate with some third party browser extension/application.
+
+```
+https://example.com/tt-rss/public.php?op=bookmarklets--subscribe&feed_url=%s
+```
+
+If feed URL is empty (or not given) tt-rss will display feed subscription dialog.
+
+### I need to get the number of unread articles for specific user
+
+There's a simple unauthenticated endpoint to do just that:
+
+```
+$ curl -s "https://example.com/tt-rss/public.php?op=getUnread&login=you&fresh=1" ; echo
+8;1
+$ curl -s "https://example.com/tt-rss/public.php?op=getUnread&login=you" ; echo
+8
+```
+
+In single user mode, use “admin” for login.
+
+If optional parameter `&fresh=1` is passed via query string, return value includes fresh article count as a `;`-separated string.
diff --git a/Feed-Handler-Plugins.md b/Feed-Handler-Plugins.md
new file mode 100644
index 0000000..789a5ef
--- /dev/null
+++ b/Feed-Handler-Plugins.md
@@ -0,0 +1,30 @@
+# Feed handler plugins
+
+!!! warning
+
+ Unless you have a strong need for these plugins, using them is not recommended. If
+ you do use them, at least don't enable them for all feeds.
+
+Some plugins utilize global per-feed content hooks which either modify fetched
+feed XML data (i.e. fixing broken XML) or even generate it entirely, for tt-rss
+to process, for websites that don't actually provide RSS feeds.
+
+While having this ability available for plugins is valuable there are several
+downsides:
+
+1. This entirely bypasses rate-limiting and article duplicate checking done
+ during normal feed update process. A badly written plugin using
+ <code>HOOK_FETCH_FEED</code> may cause your tt-rss feed to keep updating
+ feeds indefinitely, processing all articles every time, causing unnecessary
+ CPU load on your server.
+
+2. If you have full text content plugins enabled, this may cause excessive load
+ on origin server, because your tt-rss instance is going to scrape site
+ content for every provided article on every feed update.
+
+This may result in your tt-rss instance being banned by origin servers for
+causing excessive load and/or your VDS being suspended for suspected bad
+behavior.
+
+Additionally, tt-rss being blacklisted by feed publishers may negatively affect
+other users.
diff --git a/Generated-Feeds.md b/Generated-Feeds.md
new file mode 100644
index 0000000..cd9fac2
--- /dev/null
+++ b/Generated-Feeds.md
@@ -0,0 +1,83 @@
+# Generated Feeds
+
+You can generate a feed (in Atom or JSON format) for almost anything displayed
+in headlines buffer (e.g. actual feeds, Labels, Categories, etc.) by clicking
+this icon:
+
+![](../images/gen_feed_icon.png)
+
+!!! warning
+
+ Subscribing to your own feed of search results is going to produce
+ duplicate articles on each and every feed update.
+
+## Data protection
+
+Feed URLs are protected using random unique keys which are specific to each
+generated feed. Key can be regenerated at any time, invalidating previous URL.
+
+![](../images/gen_feed_dialog.png)
+
+You can clear all generated feeds in Preferences (`Feeds` &rarr; `Published &
+shared articles`).
+
+## Anatomy of a generated feed URL
+
+```
+http://example.com/tt-rss/public.php?op=rss&id=61&is_cat=1&view-mode=adaptive&key=...
+```
+
+- ``id`` (integer) - requested feed ID
+- ``is_cat`` (boolean) - whether the feed is a category
+- ``view-mode`` (string) - see below
+- ``key`` (string) - automatically generated access key, specific to feed id
+
+### Optional parameters:
+
+- ``login``, ``pass`` - see above
+- ``format`` - since version:1.6.0 specifies output format, possible values: ``atom``, ``json``
+- ``limit`` - amount of articles to output, default: 30
+- ``offset`` - start output while skipping this amount of articles, default: 0
+- ``order`` - override default headlines order
+- ``ts`` - output articles newer than timestamp in [strtotime](http://www.php.net/manual/en/function.strtotime.php)
+ accepted format (since version:1.12) i.e. stuff like <code>ts=1%20month%20ago</code>
+
+### Special feed IDs:
+
+- ``-1`` - Starred articles
+- ``-2`` - Published articles
+- ``-3`` - Fresh articles
+- ``-4`` - All articles
+- ``0`` - Archived articles
+
+Feed ID values less than `-10` are considered Labels.
+
+### Special category IDs (is\_cat=1):
+
+- ``0`` - Uncategorized
+- ``-1`` - Special category (includes Starred, Published, etc.)
+- ``-2`` - Labels category (includes your labels)
+
+### View mode values:
+
+Note: It’s probably not a very good idea to use Adaptive view mode for
+generated feeds.
+
+- <code>adaptive</code> - shows unread articles only when they are
+ unread articles, shows everything otherwise
+- <code>marked</code> (this means starred), <code>has\_note</code>,
+ <code>published</code>, <code>unread</code>,
+ <code>unread\_first</code> - should be self explanatory
+
+Actual output may differ between modes for several special feeds for
+usability reasons, e.g. recently read feed ignores <code>unread</code>
+specifier because unread articles are never part of the feed).
+
+### Order values:
+
+- ``default`` - depends on the feed: either import batch date or (for published and starred feeds) ``last_published`` and ``last_marked``
+- ``title`` - sort by title
+- ``date_reverse`` - reverse sort by batch date
+- ``feed_dates`` - sort by feed-provided article dates
+
+See also: [PublishArticles](PublishArticles.md)
diff --git a/Global-Config.md b/Global-Config.md
new file mode 100644
index 0000000..9dfbe4b
--- /dev/null
+++ b/Global-Config.md
@@ -0,0 +1,78 @@
+# Global configuration
+
+All settings (see `_DEFAULTS[]` for default values) are listed here:
+
+- https://github.com/supahgreg/tt-rss/blob/main/classes/Config.php (source code, including default values)
+
+It is preferred to adjust tt-rss global configuration through the environment, i.e. defined in `.env` when using docker-compose setup:
+
+```ini
+# Copy this file to .env before building the container.
+# Put any local modifications here.
+
+TTRSS_SESSION_COOKIE_LIFETIME=2592000
+```
+
+Alternatively, you can **create** `config.php` in tt-rss root directory (copied from `config.php-dist`), using the following syntax:
+
+```js
+putenv('TTRSS_DB_HOST=myserver');
+putenv('TTRSS_SESSION_COOKIE_LIFETIME='.(86400*30));
+```
+
+- Note lack of quotes around values.
+- Options should be always prefixed by `TTRSS_`.
+- Don't modify `classes/config.php`.
+- You don't need to put everything to `config.php`, only the options which you've changed from the defaults.
+
+Legacy plugin-required constants also go to `config.php`, using `define()`:
+
+```js
+define('LEGACY_CONSTANT', 'value');
+```
+
+To set computed values via `putenv()` you have to get them evaluated by PHP, this would work:
+
+```js
+putenv('TTRSS_SESSION_COOKIE_LIFETIME='.(86400*30));
+```
+
+However, these won't give you expected results:
+
+```js
+putenv("TTRSS_SESSION_COOKIE_LIFETIME='2592000'");
+// => 0, because quoted '2592000' is an invalid number
+
+putenv('TTRSS_SESSION_COOKIE_LIFETIME=86400*30');
+// => 86400, right side expression is not evaluated,
+// instead you're casting string literal "86400*30" to an integer
+```
+
+!!! notice
+
+ All values should be precalculated when setting via `.env` because they are not evaluated by PHP and used as-is.
+
+## Minimal config.php for a non-Docker setup
+
+Should have at least these options defined:
+
+```php
+<?php
+
+putenv('TTRSS_DB_HOST=patroni.example.com');
+putenv('TTRSS_DB_USER=mydbuser');
+putenv('TTRSS_DB_PASS=mydbpass');
+putenv('TTRSS_DB_PORT=5432');
+putenv('TTRSS_SELF_URL_PATH=http://example.com/tt-rss/'); # fully-qualified URL of your tt-rss install
+putenv('TTRSS_PHP_EXECUTABLE=/path/to/php-cli-binary'); # normally something like /usr/bin/php
+```
+
+## Migrating from old-style config.php
+
+For any `config.php` settings you have changed from the defaults (normally this
+is the `DB_` group of settings and `SELF_URL_PATH`, replace as follows, using
+the rules above:
+
+`define('DB_PORT', 'xxx')` &rarr; `putenv('TTRSS_DB_PORT=xxx')`.
+
+You can safely omit any settings that were at default values.
diff --git a/Home.md b/Home.md
index 3fc651f..e7dc737 100644
--- a/Home.md
+++ b/Home.md
@@ -1 +1,66 @@
-Welcome to the tt-rss wiki!
+---
+hide:
+ - navigation
+ - toc
+---
+
+<style>
+ .md-typeset h1,
+ .md-content__button {
+ display: none;
+ }
+</style>
+
+Tiny Tiny RSS is a free and open source web-based news feed (RSS/Atom) reader and aggregator.
+
+## Screenshots
+
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webp){ width="350", align=left }
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webp){ width="350", align=left }
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webp){ width="350" }
+
+## Features
+
+- Free software, licensed under [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html);
+- Self-hosted: control your own data and protect your privacy instead of relying on third party services;
+- Supports:
+ - organizing feeds by folders (and subfolders),
+ - [feed aggregation / syndication](wiki/GeneratedFeeds.md),
+ - keyboard shortcuts,
+ - OPML import/export,
+ - multiple ways to share stuff: export RSS feeds, plugins for various social sites, sharing by URL, etc,
+ - [sharing arbitrary content through tt-rss](wiki/ShareAnything.md),
+ - [Plugins](Plugins.md) and [themes](Themes.md),
+ - embedding full article content via readability and site-specific plugins,
+ - deduplication, including [perceptual hashing](https://github.com/supahgreg/tt-rss-plugin-perceptual-image-hash) for images,
+ - podcasts,
+ - [flexible article filtering](wiki/ContentFilters.md),
+ - [JSON API](ApiReference.md),
+ - and much more…
+- [Android client](AndroidClient.md);
+
+## Development
+
+* https://github.com/supahgreg/tt-rss
+
+## Get in touch
+
+Join https://github.com/supahgreg/tt-rss/discussions if you have questions or need to report a bug.
+
+## Contribute
+
+<!-- * Help translate tt-rss into your own language using [Weblate](https://hosted.weblate.org/engage/tt-rss/); -->
+* [Code contribution guidelines](https://github.com/supahgreg/tt-rss/blob/main/CONTRIBUTING.md);
+
+## Installation
+
+You will need the following:
+
+* A modern web browser. This generally means recent Chrome or compatible;
+* A server (VDS or physical) running Docker;
+
+### [Docker installation guide](wiki/InstallationNotes.md)
+
+Tiny Tiny RSS uses continuous development model based on a `main` branch, which is considered stable. If possible, you should always be running latest main branch code.
+
+There’s no warranty. If it breaks you get to keep both parts.
diff --git a/Installation-Notes.md b/Installation-Notes.md
new file mode 100644
index 0000000..65d54f5
--- /dev/null
+++ b/Installation-Notes.md
@@ -0,0 +1,466 @@
+# Installation Guide
+
+The only supported way to run tt-rss is under Docker.
+
+Due to the original tt-rss project and its infrastructure being discontinued, there are not currently
+"official" Docker images utilizing the code from https://github.com/supahgreg/tt-rss .
+
+!!! notice
+
+ Podman is not Docker. Please don't report issues when using Podman or podman-compose.
+
+This setup uses PostgreSQL and runs tt-rss using several containers as outlined below. We recommend using an external [Patroni cluster](https://patroni.readthedocs.io/en/latest/) instead of a single `db` container in production deployments.
+
+## TL;DR
+
+Place both `.env` and `docker-compose.yml` together in a directory, edit `.env` as you see fit, run `docker compose up -d`.
+
+### .env
+
+```ini
+# Put any local modifications here.
+
+# Run FPM under this UID/GID.
+# OWNER_UID=1000
+# OWNER_GID=1000
+
+# FPM settings.
+#PHP_WORKER_MAX_CHILDREN=5
+#PHP_WORKER_MEMORY_LIMIT=256M
+
+# ADMIN_USER_* settings are applied on every startup.
+
+# Set admin user password to this value. If not set, random password
+# will be generated on startup, look for it in the 'app' container logs.
+#ADMIN_USER_PASS=
+
+# Sets admin user access level to this value. Valid values:
+# -2 - forbidden to login
+# -1 - readonly
+# 0 - default user
+# 10 - admin
+#ADMIN_USER_ACCESS_LEVEL=
+
+# Auto create another user (in addition to built-in admin) unless it already exists.
+#AUTO_CREATE_USER=
+#AUTO_CREATE_USER_PASS=
+#AUTO_CREATE_USER_ACCESS_LEVEL=0
+
+# Default database credentials.
+TTRSS_DB_USER=postgres
+TTRSS_DB_NAME=postgres
+TTRSS_DB_PASS=password
+
+# You can customize other config.php defines by setting overrides here.
+# See tt-rss/.docker/app/Dockerfile for a complete list.
+
+# You probably shouldn't disable auth_internal unless you know what you're doing.
+# TTRSS_PLUGINS=auth_internal,auth_remote
+# TTRSS_SINGLE_USER_MODE=true
+# TTRSS_SESSION_COOKIE_LIFETIME=2592000
+# TTRSS_FORCE_ARTICLE_PURGE=30
+# ...
+
+# Bind exposed port to 127.0.0.1 to run behind reverse proxy on the same host.
+# If you plan to expose the container, remove "127.0.0.1:".
+HTTP_PORT=127.0.0.1:8280
+#HTTP_PORT=8280
+```
+
+### docker-compose.yml
+
+```yaml
+version: '3'
+
+services:
+
+ # see FAQ entry below if upgrading from a different PostgreSQL major version (e.g. 12 to 15):
+ # https://github.com/supahgreg/tt-rss-web-static/blob/main/docs/wiki/InstallationNotes.md#i-got-the-updated-compose-file-above-and-now-my-database-keeps-restarting
+ db:
+ image: postgres:15-alpine
+ restart: unless-stopped
+ env_file:
+ - .env
+ environment:
+ - POSTGRES_USER=${TTRSS_DB_USER}
+ - POSTGRES_PASSWORD=${TTRSS_DB_PASS}
+ - POSTGRES_DB=${TTRSS_DB_NAME}
+ volumes:
+ - db:/var/lib/postgresql/data
+
+ app:
+ image: cthulhoo/ttrss-fpm-pgsql-static:latest
+ restart: unless-stopped
+ env_file:
+ - .env
+ volumes:
+ - app:/var/www/html
+ - ./config.d:/opt/tt-rss/config.d:ro
+ depends_on:
+ - db
+
+# optional, makes weekly backups of your install
+# backups:
+# image: cthulhoo/ttrss-fpm-pgsql-static:latest
+# restart: unless-stopped
+# env_file:
+# - .env
+# volumes:
+# - backups:/backups
+# - app:/var/www/html
+# depends_on:
+# - db
+# command: /opt/tt-rss/dcron.sh -f
+
+ updater:
+ image: cthulhoo/ttrss-fpm-pgsql-static:latest
+ restart: unless-stopped
+ env_file:
+ - .env
+ volumes:
+ - app:/var/www/html
+ - ./config.d:/opt/tt-rss/config.d:ro
+ depends_on:
+ - app
+ command: /opt/tt-rss/updater.sh
+
+ web-nginx:
+ image: cthulhoo/ttrss-web-nginx:latest
+ restart: unless-stopped
+ env_file:
+ - .env
+ ports:
+ - ${HTTP_PORT}:80
+ volumes:
+ - app:/var/www/html:ro
+ depends_on:
+ - app
+
+volumes:
+ db:
+ app:
+ backups:
+```
+
+## FAQ
+
+### Your images won't run on Raspberry Pi!
+
+Sorry, I only make and support AMD64 images, dealing with cross-platform buildx is just too much effort. You'll have to make your own images if you use ARM or 32bit platforms by using an override and running `docker-compose build`.
+
+```yaml
+# docker-compose.override.yml
+version: '3'
+
+services:
+ app:
+ image: cthulhoo/ttrss-fpm-pgsql-static:latest
+ build:
+ dockerfile: .docker/app/Dockerfile
+ context: https://github.com/supahgreg/tt-rss.git
+ args:
+ BUILDKIT_CONTEXT_KEEP_GIT_DIR: 1
+
+ web-nginx:
+ image: cthulhoo/ttrss-web-nginx:latest
+ build:
+ dockerfile: .docker/web-nginx/Dockerfile
+ context: https://github.com/supahgreg/tt-rss.git
+```
+
+`BUILDKIT_CONTEXT_KEEP_GIT_DIR` build argument is needed to display tt-rss version properly. If that doesn't work for you (no BuildKit?) you'll have to resort to terrible hacks.
+
+!!! warning
+
+ Self-built images are not supported.
+
+### I got the updated compose file above and now my database keeps restarting
+
+Error message: The data directory was initialized by PostgreSQL version 12, which is not compatible with this version 15.4.
+
+Official PostgreSQL containers have no support for migrating data between major versions. You can do one of the following:
+
+1. Replace `postgres:15-alpine` with `postgres:12-alpine` in the compose file (or use `docker-compose.override.yml`, see below) and keep using PG 12;
+2. Use [this DB container](https://github.com/pgautoupgrade/docker-pgautoupgrade) which would automatically upgrade the database;
+3. Migrate the data manually using pg_dump & restore (somewhat complicated if you haven't done it before);
+
+### I'm using docker-compose.override.yml and now I'm getting schema update (and other) strange issues
+
+Alternatively, you've changed something related to `/var/www/html/tt-rss` in `docker-compose.yml`.
+
+You screwed up your docker setup somehow, so tt-rss can't update itself to the persistent storage location on startup (this is just an example of one issue, there could be many others).
+
+Either undo your changes or figure how to fix the problem you created and everything should work properly.
+
+### How do I make it run without /tt-rss/ in the URL, i.e. at website root?
+
+Set the following variables in `.env`:
+
+```ini
+APP_WEB_ROOT=/var/www/html/tt-rss
+APP_BASE=
+```
+
+Don't forget to remove `/tt-rss/` from `TTRSS_SELF_URL_PATH`.
+
+### How do I apply configuration options?
+
+There are two sets of options you can change through the environment - options specific to tt-rss (those are prefixed with `TTRSS_`) and options affecting container behavior.
+
+#### Options specific to tt-rss
+
+For example, to set tt-rss global option `SELF_URL_PATH`, add the following to `.env`:
+
+```ini
+TTRSS_SELF_URL_PATH=http://example.com/tt-rss
+```
+
+Don't use quotes around values. Note the prefix (`TTRSS_`) before the value.
+
+Look [here](https://github.com/supahgreg/tt-rss-web-static/blob/main/docs/wiki/GlobalConfig.md) for more information.
+
+#### Container options
+
+Some options, but not all, are mentioned in `.env-dist`. You can see all available options in the [Dockerfile](https://github.com/supahgreg/tt-rss/blob/main/.docker/app/Dockerfile).
+
+### How do I customize the YML without commiting my changes to git?
+
+You can use [docker-compose.override.yml](https://docs.docker.com/compose/extends/). For example, customize `db` to use a different postgres image:
+
+```yml
+# docker-compose.override.yml
+version: '3'
+
+services:
+ db:
+ image: postgres:12-alpine
+```
+
+### I'm trying to run CLI tt-rss scripts inside the container and they complain about root
+
+(run in the compose script directory)
+
+```sh
+docker-compose exec --user app app php8 /var/www/html/tt-rss/update.php --help
+
+# ^ ^
+# | |
+# | +- service (container) name
+# +----- run as user
+```
+
+or
+
+```sh
+docker-compose exec app sudo -Eu app php8 /var/www/html/tt-rss/update.php --help
+```
+
+or
+
+```sh
+docker exec -it <container_id> sudo -Eu app php8 /var/www/html/tt-rss/update.php --help
+```
+
+Note: `sudo -E` is needed to keep environment variables.
+
+### How do I add plugins and themes?
+
+!!! notice
+
+ First party plugins can be added using plugin installer in `Preferences` &rarr; `Plugins`.
+
+By default, tt-rss code is stored on a persistent docker volume (``app``). You can find
+its location like this:
+
+```sh
+docker volume inspect ttrss-docker_app | grep Mountpoint
+```
+
+Alternatively, you can mount any host directory as ``/var/www/html`` by updating ``docker-compose.yml``, i.e.:
+
+```yml
+volumes:
+ - app:/var/www/html
+```
+
+Replace with:
+
+```yml
+volumes:
+ - /opt/tt-rss:/var/www/html
+```
+
+Copy and/or git clone any third party plugins into ``plugins.local`` as usual.
+
+### I'm running into 502 errors and/or other connectivity issues
+
+First, check that all containers are running:
+
+```
+$ docker-compose ps
+ Name Command State Ports
+------------------------------------------------------------------------------------------------------------
+ttrss-docker-demo_app_1_f49351cb24ed /bin/sh -c /startup.sh Up 9000/tcp
+ttrss-docker-demo_backups_1_8d2aa404e31a /dcron.sh -f Up 9000/tcp
+ttrss-docker-demo_db_1_fc1a842fe245 docker-entrypoint.sh postgres Up 5432/tcp
+ttrss-docker-demo_updater_1_b7fcc8f20419 /updater.sh Up 9000/tcp
+ttrss-docker-demo_web-nginx_1_fcef07eb5c55 /docker-entrypoint.sh ngin ... Up 127.0.0.1:8280->80/tcp
+```
+
+Then, ensure that frontend (`web-nginx` or `web`) container is up and can contact FPM (`app`) container:
+
+```
+$ docker-compose exec web-nginx ping app
+PING app (172.18.0.3): 56 data bytes
+64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.144 ms
+64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.128 ms
+64 bytes from 172.18.0.3: seq=2 ttl=64 time=0.206 ms
+^C
+--- app ping statistics ---
+3 packets transmitted, 3 packets received, 0% packet loss
+round-trip min/avg/max = 0.128/0.159/0.206 ms
+```
+
+Containers communicate via DNS names assigned by Docker based on service names defined in `docker-compose.yml`. This means that services (specifically, `app`) and Docker DNS service should be functional.
+
+Similar issues may be also caused by Docker `iptables` functionality either being disabled or conflicting with `nftables`.
+
+### I want to rename `app` (FPM) container
+
+You can but you'll need to pass `APP_UPSTREAM` environment variable to the `web-nginx` container with its new name.
+
+### How do I put this container behind a reverse proxy?
+
+- Don't forget to pass `X-Forwarded-Proto` to the container if you're using HTTPS, otherwise tt-rss would generate plain HTTP URLs.
+- Upstream address and port are set using `HTTP_PORT` in `.env`:
+
+```ini
+HTTP_PORT=127.0.0.1:8280
+```
+
+#### Nginx example
+
+```nginx
+location /tt-rss/ {
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://127.0.0.1:8280/tt-rss/;
+ break;
+}
+```
+
+If you run into problems with global PHP-to-FPM handler taking priority over proxied location, define tt-rss location like this so it takes higher priority:
+
+```nginx
+location ^~ /tt-rss/ {
+ ....
+}
+```
+
+If you want to pass an entire nginx virtual host to tt-rss:
+
+```nginx
+server {
+ server_name rss.example.com;
+
+ ...
+
+ location / {
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ proxy_pass http://127.0.0.1:8280/;
+ break;
+ }
+}
+```
+
+Note that `proxy_pass` in this example points to container website root.
+
+#### Apache example
+
+```
+<IfModule mod_proxy.c>
+ <Location /tt-rss>
+ ProxyPreserveHost On
+ ProxyPass http://localhost:8280/tt-rss
+ ProxyPassReverse http://localhost:8280/tt-rss
+ RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
+ </Location>
+ </IfModule>
+```
+
+### I have internal web services tt-rss is complaining about (URL is invalid, loopback address, disallowed ports)
+
+Put your local services on the same docker network with tt-rss, then access them by service (= host) names, i.e. `http://rss-bridge/`.
+
+```yml
+services:
+ rss-bridge:
+....
+networks:
+ default:
+ external:
+ name: ttrss-docker_default
+```
+
+If your service uses a non-standard (i.e. not 80 or 443) port, make an internal reverse proxy sidecar container for it.
+
+### Backup and restore
+
+If you have `backups` container enabled, stock configuration makes automatic backups (database, local plugins, etc.) once a week to a separate storage volume.
+
+Note that this container is included as a safety net for people who wouldn't bother with backups otherwise. If you value your data, you should invest your time into setting up something like [WAL-G](https://github.com/wal-g/wal-g) instead.
+
+#### Restoring backups
+
+A process to restore the database from such backup would look like this:
+
+1. Enter `backups` container shell: `docker-compose exec backups /bin/sh`
+2. Inside the container, locate and choose the backup file: `ls -t /backups/*.sql.gz`
+3. Clear database (**THIS WOULD DELETE EVERYTHING IN THE DB**): `psql -h db -U $TTRSS_DB_USER $TTRSS_DB_NAME -e -c "drop schema public cascade; create schema public"`
+3. Restore the backup: `zcat /backups/ttrss-backup-yyyymmdd.sql.gz | psql -h db -U $TTRSS_DB_USER $TTRSS_DB_NAME`
+
+Alternatively, if you want to initiate backups from the host, you can use something like this:
+
+```sh
+source .env
+docker-compose exec db /bin/bash \
+ -c "export PGPASSWORD=$TTRSS_DB_PASS \
+ && pg_dump -U $TTRSS_DB_USER $TTRSS_DB_NAME" \
+ | gzip -9 > backup.sql.gz
+```
+
+### How do I use custom certificates?
+
+You need to mount custom certificates into the *app* and *updater* containers like this:
+
+```yml
+volumes:
+ ....
+ ./ca1.crt:/usr/local/share/ca-certificates/ca1.crt:ro
+ ./ca2.crt:/usr/local/share/ca-certificates/ca2.crt:ro
+ ....
+```
+
+Don't forget to restart the containers.
+
+### How do I run these images on K8S?
+
+You'll need to set several mandatory environment values to the container running web-nginx image:
+
+1. `APP_UPSTREAM` should point to the fully-qualified DNS service name provided by the app (FPM) container/pod;
+2. `RESOLVER` should be set to `kube-dns.kube-system.svc.cluster.local`
+
+### Where's the helm chart?
+
+I don't provide one. You will have to make your own.
+
+### I'm using Podman, and...
+
+I neither test against nor support Podman. Please don't report any issues when using it.
diff --git a/Making-Plugins.md b/Making-Plugins.md
new file mode 100644
index 0000000..e230191
--- /dev/null
+++ b/Making-Plugins.md
@@ -0,0 +1,35 @@
+# Making Plugins
+
+Plugins may render new preference panes or embed themselves into several
+existing one, store data using simple key -\> value data or directly in
+the database, modify how articles are rendered, alter feed data, and
+much more.
+
+You can use sample plugins bundled with tt-rss and [other
+plugins](../Plugins.md) as a starting point. Ask on the forums if you need help
+with anything specific.
+
+Some useful information may be found here:
+
+- https://github.com/supahgreg/tt-rss/blob/main/classes/PluginHost.php
+- https://github.com/supahgreg/tt-rss/blob/main/classes/Plugin.php
+
+Frontend (JS) uses different hooks, which are defined in [PluginHost.js](https://github.com/supahgreg/tt-rss/blob/main/js/PluginHost.js)
+
+## Localization support
+
+See ``time_to_read`` plugin for a complete example [here](https://github.com/supahgreg/tt-rss-plugin-time-to-read)
+
+### Implementation
+
+- Plugin translations are placed in a separate Gettext domain (name equals lowercase plugin class).
+- Translation (.po) file in ``(plugin dir)/locale/(LANG)/LC_MESSAGES/`` name should correspond to Gettext domain name.
+
+### Using gettext
+
+- On the PHP side, either use helper methods defined in ``classes/plugin.php``
+ (base class for all plugins) or call ``_dgettext`` group of functions
+ directly.
+- On the Javascript side, all translations are merged so you can use the usual
+ ``__()`` shortcut function.
+
diff --git a/Plugins.md b/Plugins.md
new file mode 100644
index 0000000..ed3de78
--- /dev/null
+++ b/Plugins.md
@@ -0,0 +1,128 @@
+---
+hide:
+ - navigation
+---
+
+# Plugins
+
+Tiny Tiny RSS supports many kinds of plugins: social plugins which share
+articles to various sites, article filter plugins which mangle feed-provided
+data on import (for example, inlining images or extracting full article text
+using Readability), hotkey plugins which alter the way keyboard shortcuts work,
+etc.
+
+There are two kinds of plugins: user and system. User plugins are enabled in
+`Preferences` &rarr; `Plugins`. System plugins require adding them to a [global
+configuration](wiki/GlobalConfig.md) directive <code>PLUGINS</code> which is a
+comma-separated list of enabled system plugins, i.e.
+
+```js
+putenv('TTRSS_PLUGINS=auth_internal, other_plugin');
+```
+
+System plugins are always enabled for all users. If multiple search plugins are loaded, only the first one is used
+
+If you are interested in making plugins, see [MakingPlugins](wiki/MakingPlugins.md),
+https://github.com/topics/tt-rss-plugin , https://github.com/topics/ttrss-plugins , etc.
+
+### Installing plugins
+
+!!! notice
+
+ First party plugins can be added via built-in plugin installer in `Preferences` &rarr; `Plugins`.
+
+Copy plugin folder to ```tt-rss/plugins.local``` then activate it in the settings panel.
+Plugin folder name should correspond to plugin class name defined in ``(plugin)/init.php``,
+i.e. ``Af_ExamplePlugin`` should be copied to ``plugins.local/af_exampleplugin``.
+
+## First party plugins (maintained on this site but not bundled with tt-rss)
+
+https://github.com/supahgreg?tab=repositories&q=tt-rss-plugin&sort=name
+
+## Third party plugins
+
+!!! warning
+
+ We’re not responsible for third party plugins. Use at your own risk.
+
+!!! notice
+
+ Third party plugins may be unmaintained and incompatible with newer tt-rss
+ code (especially those from the old forums). Please report plugin-related
+ problems to their developers.
+
+### Sharing plugins
+
+#### A Tiny Tiny RSS plugin to post to a Wallabag v2 instance
+
+https://github.com/joshp23/ttrss-to-wallabag-v2
+
+#### A plugin for Tiny Tiny RSS, to shorten urls via Yourls
+
+https://github.com/joshp23/tt-rss-yourls
+
+#### Adds support for sharing links with Shaarli to tt-rss
+
+https://github.com/joshp23/tt-rss-shaarli
+
+#### Convert DOI and other links to Sci-Hub links in TT-Rss
+
+https://github.com/joshp23/ttrss-to-Sci-Hub
+
+### Feed data manipulation plugins
+
+#### Enable embedded videos in feeds - videoframes
+
+https://github.com/tribut/ttrss-videoframes
+
+#### Configurable plugin to replace article stub with content from the linked URL's page
+
+https://github.com/feediron/ttrss_plugin-feediron
+
+#### A simple plugin to assist in the display of images from NASA's Astronomy Picture of the Day feed in TT-RSS
+
+https://github.com/joshp23/TTRSS-APOD-Fix
+
+### Webcomics plugins
+
+#### Comic plugin GU Comics, Married to the sea & Toothpaste for dinner
+
+https://github.com/tribut/ttrss-comics
+
+#### Lint/tidy plugin to repair invalid feeds
+
+https://github.com/Churten/tt-rss-ff-xmllint
+
+#### Embed content from Tapastic rss streams
+
+https://github.com/ldidry/af_tapastic.git
+
+### API plugins
+
+#### FreshRSS / Google Reader API Support
+
+Use any RSS app or client that supports FreshRSS or the Google Reader API.
+
+https://github.com/eric-pierce/freshapi
+
+#### Fever API emulator
+
+Simulates the Fever API for reading RSS Feeds with your Fever clients.
+
+https://github.com/DigitalDJ/tinytinyrss-fever-plugin
+
+### Other plugins
+
+#### Generate QR codes from article links, with xhr support and no disk cache
+
+https://github.com/GregThib/ttrss-qrcodegen
+
+#### Send XMPP notifications via Prosody mod_post_msg
+
+https://github.com/joshp23/ttrss-notify-xmpp-prosody
+
+#### Plugins for alternative navigation and night mode
+
+Set of plugins to (1) use cursor keys for a tree-style article navigation; (2) change to a minimal set of hotkeys; (3) toggle night mode for custom themes; (4) change the sort order of unread articles to Oldest first.
+
+https://github.com/ltGuillaume/FeedMei/tree/master/plugins.local/
diff --git a/Publish-Articles.md b/Publish-Articles.md
new file mode 100644
index 0000000..120e9a9
--- /dev/null
+++ b/Publish-Articles.md
@@ -0,0 +1,18 @@
+# Published Articles
+
+You can publish selected articles to a special RSS feed, accessible to anyone
+who knows the special randomly-generated URL. This works independently of
+[GeneratedFeeds](GeneratedFeeds.md) which allows you to share entire feeds,
+categories, etc.
+
+You can mark articles as published by clicking [standard feed
+icon](http://feedicons.com/) near headline title:
+
+![](../images/publish_articles.png)
+
+Resulting URL is displayed in Preferences (`Feeds` &rarr; `Published & shared articles`).
+
+
+!!! notice
+
+ You can also publish articles automatically using filters (`Action` &rarr; `Publish article`).
diff --git a/SSL-Certificate-Authentication.md b/SSL-Certificate-Authentication.md
new file mode 100644
index 0000000..1852f81
--- /dev/null
+++ b/SSL-Certificate-Authentication.md
@@ -0,0 +1,93 @@
+# SSL Certificate Authentication
+
+!!! warning
+
+ This guide is considered legacy and is no longer supported as it is not compatible with
+ [stock docker compose](InstallationNotes.md) setup. Please don't report any issues when
+ trying to DIY this.
+
+This article details the steps to enable user authentication with TT-RSS using a client certificate.
+
+## Prerequisites
+
+You **must** have a working TT-RSS installation with SSL. This guide is not intended to walk you through installing TT-RSS, nor is it intended to help you enable HTTPS on your web server.
+
+If you have no idea how certificates work (i.e. the terms x509 and PKI make no sense to you), stop now.
+
+This guide includes steps for Nginx. Of course other web servers (e.g. Apache) support client certificates so you're welcome to use them if you prefer, the steps just aren't included here (but might be added at some point).
+
+This guide was written with Debian 9 in mind, other distros will vary.
+
+## Getting Started
+
+Client certificates are typically created/issued by a private Certificate Authority (i.e. **you** as the administrator would create the certificates for your users). You create a root certificate authority and install the **public** certificate for it on your web server. You then create certificates for each client, signed by the root certificate authority's private key. Each client is issued their certificate and private key (often as a single file with a `.p12` extension).
+
+Note:
+
+1. These certificates are distinct from the ones used for encrypted/HTTPS connections on your server. Those are usually issued by public Certificate Authorities (e.g. Let's Encrypt).
+2. Do **not** do the certificate creation on your public, Internet-facing web server. This should be done on a computer that's offline and the certificate authority's private key should be kept in a safe place.
+
+## Server Setup
+
+Install your certificate authority public certificate on the server. The location doesn't really matter but this is how Debian does it:
+
+```sh
+sudo cp ttrss-ca.crt /usr/local/share/ca-certificates/
+sudo chown root:root /usr/local/share/ca-certificates/ttrss-ca.crt
+sudo chmod 644 /usr/local/share/ca-certificates/ttrss-ca.crt
+```
+
+(In Debian run the command `sudo update-ca-certificates` to rebuild the list of certificate authorities.)
+
+Edit your Nginx conf file for your TT-RSS installation to add the certificate and have Nginx validate clients with it.
+
+Note:
+
+1. The file path and extension to the certificate are different than above because Debian builds a consolidated list of certificate authorities provided by the vendor, user, etc.; this is why we ran the update-ca-certificates command above and your distro may vary its approach so be aware of that.
+2. We use `ssl_verify_client on;` which prevents access to the site unless a valid certificate is provided. If you want **both** password and certificate authentication, use `ssl_verify_client optional;` instead.
+3. In the php location we do not use `$ssl_client_v_start` and `$ssl_client_v_end` Nginx variables by default. These variables were added in Nginx version 1.11.7 and Debian 9 does not ship that version. It's included as a comment for future support.
+
+```nginx
+server {
+
+ ssl_client_certificate /etc/ssl/certs/ttrss-ca.pem
+ ssl_verify_client on;
+ # ssl_verify_client optional;
+
+ location ~ [^/]\.php(/|$) {
+
+ fastcgi_param SSL_CLIENT_M_SERIAL $ssl_client_serial;
+ fastcgi_param SSL_CLIENT_S_DN $ssl_client_s_dn;
+ # fastcgi_param SSL_CLIENT_V_START $ssl_client_v_start;
+ # fastcgi_param SSL_CLIENT_V_END $ssl_client_v_end;
+ fastcgi_param SSL_CLIENT_V_START 0;
+ fastcgi_param SSL_CLIENT_V_END 0;
+
+ }
+
+}
+```
+
+Now restart Nginx:
+
+```sh
+sudo systemctl restart nginx
+```
+
+Update the TT-RSS config file to add `auth_remote` to the `PLUGINS` constant (near the end of the file):
+
+```php
+define('PLUGINS', 'auth_internal, auth_remote, note');
+```
+
+You might be tempted to remove `auth_internal` but we still need it so don't.
+
+Next, make sure your client certificate (the `.p12` file) is installed on your computer. Different operating systems and browsers do this differently, so you're pretty much on your own there, but if you double-click the .p12 file from the desktop the operating system should offer to install it for you. Vendor-provided browsers (e.g. IE/Edge, Safari, etc.) will typically use certificates provided by the operating system. Third-party installed browsers (e.g. Firefox) often need to have the .p12 file added to them independent of the operating system.
+
+After successfully installing the client certificate, open a new browser window/tab and visit your TT-RSS install. You should immediately be asked to confirm or select the client certificate you want to use. Select the appropriate one. You may have to login with your username/password; this is expected.
+
+Go to Preferences and scroll to the bottom. Under *Login with an SSL certificate* the *Register* button should now be available. Click it, then *Save configuration*.
+
+At this point you should be able to test if this all works. Logout of your TT-RSS session, clear your browser cache and cookies, then open a new window/tab and visit your TT-RSS install. You may be asked to verify the client certificate (some browsers ask every session and others remember your choice). Once you select the certificate it should just log you without using the username/password form.
+
+Finally, if you're never going to use password authentication you could remove `auth_internal` plugin in `config.php`, just remember to add it back if you remove certificate support in the future otherwise you'll get the login form but will never be able to login. You'll also need to enable it if you have to change client certificates as there will be no other way of logging in.
diff --git a/Scoring.md b/Scoring.md
new file mode 100644
index 0000000..c058e2b
--- /dev/null
+++ b/Scoring.md
@@ -0,0 +1,28 @@
+# Scoring
+
+Scoring is supported in a way similar to some newsreaders. Score is calculated
+on article import using special filters with a "Modify score" action.
+
+Resulting score is a sum of all score modifiers from all matching filters. For
+example, if the article matches two filters A (score +100) and B (score -50),
+the resulting score will be 50.
+
+Article score affects the position of the article in the headline buffer (which
+is sorted by score) and alters the way article is displayed:
+
+| Score | Display / Action |
+|-------|------------------|
+| `<-500` | Score indicator points down, article is automatically marked as read
+| `<-100` | Score indicator points down
+| `<0` | Score indicator points down, 1.5.0: article is excluded from Fresh feed and (as of 1.5.10 also excluded from email digest) |
+| `0` | Display normally |
+| `>0` | Score indicator points up |
+| `>500` | Score indicator points up |
+| `>1000` | Same as above, article is also marked as starred |
+
+### Adjusting manually
+
+Calculated score for an individual article may be adjusted by clicking on score
+indicator in the headlines list:
+
+![](../images/score_indicator2.png)
diff --git a/Search-Syntax.md b/Search-Syntax.md
new file mode 100644
index 0000000..86a8d4d
--- /dev/null
+++ b/Search-Syntax.md
@@ -0,0 +1,22 @@
+# Search Syntax
+
+!!! notice
+
+ This only applies to built-in search, other search plugins like may override this syntax.
+
+Search query consists of several keywords. Keyword starting with "-" is considered a negative match. Several special keywords are available:
+
+* ``@{date}`` - match by date. For example, @yesterday or @2011-11-03. Please note that due to incomplete implementation, special date keywords like yesterday might not match all articles if user timezone is different from tt-rss internal timezone (UTC).
+* ``pub:{true,false}`` - match only published or unpublished articles
+* ``star:{true, false}`` - same, starred articles
+* ``unread:{true, false}`` - self explanatory (requires trunk as of 05.03.2015)
+* ``note:{true, false, sometext}`` - same, for articles having an attached note or matching the specified text
+* ``label:Somelabel`` - articles that belong to a specified label
+* ``tag:mytag`` - articles which have specified tag
+* ``title:``, ``author:`` - self explanatory
+
+When searching by keyword with spaces, use quotes like this: `"title:string with spaces"` or `tag:"multiple words"`
+
+If no special keywords are specified, search is done using PostgreSQL [Full Text Search](https://www.postgresql.org/docs/current/textsearch-intro.html) engine.
+
+Pointless as it may be, you can combine negative prefix with the special keywords: -star:true would essentially mean star:false.
diff --git a/Securing-Cache-Directories.md b/Securing-Cache-Directories.md
new file mode 100644
index 0000000..b78cafc
--- /dev/null
+++ b/Securing-Cache-Directories.md
@@ -0,0 +1,40 @@
+# Securing Cache Directories
+
+!!! notice
+
+ Official container images restrict `/cache` access by default. This page applies only to
+ legacy host installations.
+
+While nothing critical is stored in cache directories by tt-rss nor do files
+have easily guessable names, you may consider forbidding external access over
+HTTP to these directories anyway. This is not required, however.
+
+You may also consider restricting access to <code>config.php</code>, just in case.
+
+## Using nginx
+
+```nginx
+location /tt-rss/cache {
+ deny all;
+}
+
+location = /tt-rss/config.php {
+ deny all;
+}
+```
+
+Note: official docker setup has this out of the box.
+
+## Using apache (2.4 syntax)
+
+```apache
+<Directory /var/www/html/tt-rss/cache>
+ Require all denied
+</Directory>
+
+<Directory /var/www/html/tt-rss>
+ <Files "config.php">
+ Require all denied
+ </Files>
+</Directory>
+```
diff --git a/Share-Anything.md b/Share-Anything.md
new file mode 100644
index 0000000..23d4c18
--- /dev/null
+++ b/Share-Anything.md
@@ -0,0 +1,14 @@
+# Share Anything
+
+You can share arbitrary webpages to appear as articles in your ``Published``
+feed. Combined with Readability this makes tt-rss function like a read-it-later
+kind of website.
+
+Sharing is available via bookmarklet in Preferences: (`Feeds` &rarr;
+`Bookmarklets`) (if you have ``bookmarklets`` plugin enabled) or through Android
+application.
+
+![](../images/share_anything.png)
+
+Since they have no actual originating feed, shared articles are placed into
+[Archived articles](ArchivedFeed.md) feed and then set published.
diff --git a/Sorting.md b/Sorting.md
new file mode 100644
index 0000000..67d34d4
--- /dev/null
+++ b/Sorting.md
@@ -0,0 +1,54 @@
+# Sorting
+
+Tiny Tiny RSS provides four options for how articles appear within a
+selected feed: `Default`, `Newest`, `Oldest`, `Title`.
+
+!!! notice
+
+ Special feeds (e.g. *Starred articles*) have unique sorting when *Default* is selected, otherwise they behave as described below.
+
+- *Descending score* means **higher numbers** are shown before lower numbers.
+- *Descending date/time* means **more recent** is shown before less recent.
+- *Ascending date/time* means **less recent** is shown before more recent.
+
+### Default
+
+This is the default (surprise!) and is recommended.
+
+1. Descending [score](Scoring.md).
+2. Descending date/time the article was added into the Tiny Tiny RSS database.
+3. Descending date/time the feed's site states the article was published or changed.
+
+### Newest
+
+1. Descending date/time the feed's site states the article was published or changed.
+
+### Oldest
+
+1. Ascending date/time the feed's site states the article was published or changed.
+
+### Title
+
+1. Alphabetically by the title of the article.
+2. Ascending date/time the article was added into the Tiny Tiny RSS database
+3. Ascending date/time the feed's site states the article was published or changed.
+
+## Special Feeds
+
+When *Default* is selected these special feeds behave as described below.
+
+### Starred articles
+
+1. Descending date/time when the article was starred.
+2. Descending date/time the article was added into the Tiny Tiny RSS database.
+3. Descending date/time the feed's site states the article was published or changed.
+
+### Published articles
+
+1. Descending date/time when the article was published.
+2. Descending date/time the article was added into the Tiny Tiny RSS database.
+3. Descending date/time the feed's site states the article was published or changed.
+
+### Recently read
+
+1. Descending date/time when the article was marked as read in Tiny Tiny RSS.
diff --git a/Themes.md b/Themes.md
new file mode 100644
index 0000000..42b3d24
--- /dev/null
+++ b/Themes.md
@@ -0,0 +1,47 @@
+---
+hide:
+ - navigation
+---
+
+# Themes
+
+Install by copying theme CSS (and any other content, if needed) into ``themes.local`` directory under tt-rss root, then you'll be able to activate it in preferences.
+
+**Please note that we’re not responsible for third party themes. Use at your own risk.**
+
+### FeedMei Theme + Plugins for Tiny Tiny RSS
+
+<img src="https://codeberg.org/ltguillaume/feedmei/media/branch/main/SCREENSHOT.png" alt="">
+<img src="https://codeberg.org/ltguillaume/feedmei/media/branch/main/SCREENSHOT2.png" alt="">
+
+A clean and minimal theme for Tiny Tiny RSS, loosely inspired by Feedly. Built by making the minimal amount of changes to the default theme. This repo also includes a set of plugins.
+
+**Codeberg** https://codeberg.org/ltguillaume/feedmei
+
+### Clean GReader Theme
+
+<img src="https://raw.github.com/naeramarth7/clean-greader/master/img/preview.png" alt="" style="width: 200px;"/>
+
+A theme built from scratch, independent of default css. Inspired by the
+Google Reader it has a white/greyish look.
+
+**Github** https://github.com/naeramarth7/clean-greader
+
+### Feedly Theme
+
+<img src="https://raw.github.com/levito/tt-rss-feedly-theme/master/feedly-screenshots/feedly-expandable.png" alt="" style="width: 200px;"/>
+
+A theme built from scratch, independent of default css. Emulates the greyish look of Feedly.
+
+**Github** https://github.com/levito/tt-rss-feedly-theme
+
+### Reeder Theme
+
+<img src="https://github.com/tschinz/tt-rss_reeder_theme/blob/master/reeder_screenshot/combined_mode_1.png?raw=true" alt="" style="width: 200px;"/>
+
+Theme emulates the paper/brownish look of the Reeder App from IOS.
+
+**Github**
+
+* tt-rss \>1.11 https://github.com/tschinz/tt-rss\_reeder\_theme
+* tt-rss \<1.11 (old version) https://github.com/tschinz/tt-rss\_reeder\_theme/tree/legacy
diff --git a/ZeEpube.md b/ZeEpube.md
new file mode 100644
index 0000000..99d4eeb
--- /dev/null
+++ b/ZeEpube.md
@@ -0,0 +1,129 @@
+---
+title: The Epube
+hide:
+ - navigation
+---
+
+<style>
+ .md-typeset h1,
+ .md-content__button {
+ display: none;
+ }
+</style>
+
+# The Epube
+
+Self-hosted web EPUB reader using [EPUB.js](https://github.com/futurepress/epub.js), Bootstrap, and [Calibre](https://calibre-ebook.com).
+
+## Screenshots
+
+### Desktop
+
+![](images/epube/Screenshot_2025-05-16_at_15.50.58.webp){ width="420", align=left }
+![](images/epube/Screenshot_2025-05-16_at_15.52.29.webp){ width="420" }
+
+### Mobile
+
+![](images/epube/mobile/Screenshot_20250516_155939.webp){ width="120", align=left }
+![](images/epube/mobile/Screenshot_20250516_164212.webp){ width="120", align=left }
+![](images/epube/mobile/Screenshot_20250516_160100.webp){ width="120", align=left }
+![](images/epube/mobile/Screenshot_20250516_164304.webp){ width="120", align=left }
+![](images/epube/mobile/Screenshot_20250516_160122.webp){ width="120", align=left }
+![](images/epube/mobile/Screenshot_20250516_164403.webp){ width="120", align=left }
+
+## Features
+
+* responsive, offline-capable design;
+* integrates with Calibre library;
+* can use either SQLite or PostgreSQL for its own database;
+* multi-device sync of last-read pages (when online);
+* word definition lookups using dictd / Wiktionary;
+* supports Chrome homescreen "app mode";
+* optional hyphenation using [hyphen](https://github.com/ytiurin/hyphen) library;
+* dark mode, themes, etc;
+
+## UI cheat sheet
+
+* Switch pages: Left, Right, space, taps/clicks on left and right sides of the window
+* Show UI if it's hidden: escape or tap somewhere in the middle of reader window
+* Dictionary lookup: double click/select one word
+
+## Installation
+
+Use the following compose setup to either pull or build your own images:
+
+### .env
+
+```ini
+# Put any local modifications here.
+
+OWNER_UID=1000
+OWNER_GID=1000
+
+# Calibre library base directory (mounts to /books)
+BOOKS_DIR=/home/user/calibre/Books
+
+# Default user to create (if it doesn't exist)
+EPUBE_ADMIN_USER=admin
+EPUBE_ADMIN_PASS=password
+
+# APP_WEB_ROOT=/var/www/html/books
+# APP_BASE=
+
+# bind exposed port to 127.0.0.1 by default in case reverse proxy is used.
+# if you plan to run the container standalone and need origin port exposed
+# use next HTTP_PORT definition (or remove "127.0.0.1:").
+HTTP_PORT=127.0.0.1:8280
+#HTTP_PORT=8280
+
+# Optional OAuth
+# EPUBE_OIDC_URL=
+# EPUBE_OIDC_NAME=
+# EPUBE_OIDC_CLIENT_ID=
+# EPUBE_OIDC_CLIENT_SECRET=
+
+# PostgreSQL is optional, default is SQLite
+# EPUBE_DB_TYPE=pgsql
+# EPUBE_DB_USER=postgres
+# EPUBE_DB_PASS=password
+# EPUBE_DB_NAME=postgres
+```
+
+### docker-compose.yml
+
+```yaml
+version: '3'
+
+services:
+ # optional dictionary server (add other dictionaries via Dockerfile)
+ # comment it out if you don't need it
+ dict:
+ restart: unless-stopped
+ image: cthulhoo/the-epube-dict:latest
+
+ app:
+ image: cthulhoo/the-epube-fpm-static:latest
+ restart: unless-stopped
+ volumes:
+ - app:/var/www/html
+ - ${BOOKS_DIR}:/books:ro
+
+ web-nginx:
+ image: cthulhoo/the-epube-web-nginx:latest
+ restart: unless-stopped
+ ports:
+ - ${HTTP_PORT}:8080
+ volumes:
+ - app:/var/www/html:ro
+ depends_on:
+ - app
+
+volumes:
+ app:
+```
+
+## FAQ
+
+### Moving between pages is slow with some books
+
+This happens sometime on slow devices, i.e. phones. The usual reason is Epub chapters are too large. Those can be split into smaller sections with Calibre epub converter: *EPUB Output -> Split files larger than ->* set a smaller value, 100KB should be fine.
diff --git a/images/bears_1.png b/images/bears_1.png
new file mode 100644
index 0000000..bfd4e1f
--- /dev/null
+++ b/images/bears_1.png
Binary files differ
diff --git a/images/bears_2.png b/images/bears_2.png
new file mode 100644
index 0000000..3ecf406
--- /dev/null
+++ b/images/bears_2.png
Binary files differ
diff --git a/images/bears_3.png b/images/bears_3.png
new file mode 100644
index 0000000..cb887a9
--- /dev/null
+++ b/images/bears_3.png
Binary files differ
diff --git a/images/bears_4.png b/images/bears_4.png
new file mode 100644
index 0000000..1e9e4a6
--- /dev/null
+++ b/images/bears_4.png
Binary files differ
diff --git a/images/can your chat client do this.png b/images/can your chat client do this.png
new file mode 100644
index 0000000..3da043c
--- /dev/null
+++ b/images/can your chat client do this.png
Binary files differ
diff --git a/images/candy-cane.png b/images/candy-cane.png
new file mode 100644
index 0000000..4b763d9
--- /dev/null
+++ b/images/candy-cane.png
Binary files differ
diff --git a/images/epube/2019/library1.png b/images/epube/2019/library1.png
new file mode 100644
index 0000000..95bc815
--- /dev/null
+++ b/images/epube/2019/library1.png
Binary files differ
diff --git a/images/epube/2019/library1.webp b/images/epube/2019/library1.webp
new file mode 100644
index 0000000..b1de360
--- /dev/null
+++ b/images/epube/2019/library1.webp
Binary files differ
diff --git a/images/epube/2019/library2.png b/images/epube/2019/library2.png
new file mode 100644
index 0000000..52e9d99
--- /dev/null
+++ b/images/epube/2019/library2.png
Binary files differ
diff --git a/images/epube/2019/library2.webp b/images/epube/2019/library2.webp
new file mode 100644
index 0000000..d04fe49
--- /dev/null
+++ b/images/epube/2019/library2.webp
Binary files differ
diff --git a/images/epube/2019/reader1.png b/images/epube/2019/reader1.png
new file mode 100644
index 0000000..574ca1d
--- /dev/null
+++ b/images/epube/2019/reader1.png
Binary files differ
diff --git a/images/epube/2019/reader1.webp b/images/epube/2019/reader1.webp
new file mode 100644
index 0000000..f6eaf12
--- /dev/null
+++ b/images/epube/2019/reader1.webp
Binary files differ
diff --git a/images/epube/2019/reader2.png b/images/epube/2019/reader2.png
new file mode 100644
index 0000000..8df8e49
--- /dev/null
+++ b/images/epube/2019/reader2.png
Binary files differ
diff --git a/images/epube/2019/reader2.webp b/images/epube/2019/reader2.webp
new file mode 100644
index 0000000..ab50234
--- /dev/null
+++ b/images/epube/2019/reader2.webp
Binary files differ
diff --git a/images/epube/2019/reader3.png b/images/epube/2019/reader3.png
new file mode 100644
index 0000000..d2c665c
--- /dev/null
+++ b/images/epube/2019/reader3.png
Binary files differ
diff --git a/images/epube/2019/reader3.webp b/images/epube/2019/reader3.webp
new file mode 100644
index 0000000..e795db7
--- /dev/null
+++ b/images/epube/2019/reader3.webp
Binary files differ
diff --git a/images/epube/Screenshot_2025-05-16_at_15.50.58.png b/images/epube/Screenshot_2025-05-16_at_15.50.58.png
new file mode 100644
index 0000000..e10ab8a
--- /dev/null
+++ b/images/epube/Screenshot_2025-05-16_at_15.50.58.png
Binary files differ
diff --git a/images/epube/Screenshot_2025-05-16_at_15.50.58.webp b/images/epube/Screenshot_2025-05-16_at_15.50.58.webp
new file mode 100644
index 0000000..0278cf9
--- /dev/null
+++ b/images/epube/Screenshot_2025-05-16_at_15.50.58.webp
Binary files differ
diff --git a/images/epube/Screenshot_2025-05-16_at_15.52.29.png b/images/epube/Screenshot_2025-05-16_at_15.52.29.png
new file mode 100644
index 0000000..021e14a
--- /dev/null
+++ b/images/epube/Screenshot_2025-05-16_at_15.52.29.png
Binary files differ
diff --git a/images/epube/Screenshot_2025-05-16_at_15.52.29.webp b/images/epube/Screenshot_2025-05-16_at_15.52.29.webp
new file mode 100644
index 0000000..263bfd9
--- /dev/null
+++ b/images/epube/Screenshot_2025-05-16_at_15.52.29.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_155939.png b/images/epube/mobile/Screenshot_20250516_155939.png
new file mode 100644
index 0000000..35f68f3
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_155939.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_155939.webp b/images/epube/mobile/Screenshot_20250516_155939.webp
new file mode 100644
index 0000000..b043c40
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_155939.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_160100.png b/images/epube/mobile/Screenshot_20250516_160100.png
new file mode 100644
index 0000000..d3b5520
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_160100.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_160100.webp b/images/epube/mobile/Screenshot_20250516_160100.webp
new file mode 100644
index 0000000..d227116
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_160100.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_160122.png b/images/epube/mobile/Screenshot_20250516_160122.png
new file mode 100644
index 0000000..020586d
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_160122.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_160122.webp b/images/epube/mobile/Screenshot_20250516_160122.webp
new file mode 100644
index 0000000..4843628
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_160122.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164212.png b/images/epube/mobile/Screenshot_20250516_164212.png
new file mode 100644
index 0000000..6d32223
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164212.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164212.webp b/images/epube/mobile/Screenshot_20250516_164212.webp
new file mode 100644
index 0000000..2513ed2
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164212.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164304.png b/images/epube/mobile/Screenshot_20250516_164304.png
new file mode 100644
index 0000000..01003a3
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164304.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164304.webp b/images/epube/mobile/Screenshot_20250516_164304.webp
new file mode 100644
index 0000000..b2e635a
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164304.webp
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164403.png b/images/epube/mobile/Screenshot_20250516_164403.png
new file mode 100644
index 0000000..fba4dc6
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164403.png
Binary files differ
diff --git a/images/epube/mobile/Screenshot_20250516_164403.webp b/images/epube/mobile/Screenshot_20250516_164403.webp
new file mode 100644
index 0000000..bd88faa
--- /dev/null
+++ b/images/epube/mobile/Screenshot_20250516_164403.webp
Binary files differ
diff --git a/images/feed-icon.svg b/images/feed-icon.svg
new file mode 100644
index 0000000..a7f9cf1
--- /dev/null
+++ b/images/feed-icon.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"
+ id="RSSicon"
+ viewBox="0 0 8 8" width="256" height="256">
+
+ <title>RSS feed icon</title>
+
+ <style type="text/css">
+ .button {stroke: none; fill: orange;}
+ .symbol {stroke: none; fill: white;}
+ </style>
+
+ <rect class="button" width="8" height="8" rx="1.5" />
+ <circle class="symbol" cx="2" cy="6" r="1" />
+ <path class="symbol" d="m 1,4 a 3,3 0 0 1 3,3 h 1 a 4,4 0 0 0 -4,-4 z" />
+ <path class="symbol" d="m 1,2 a 5,5 0 0 1 5,5 h 1 a 6,6 0 0 0 -6,-6 z" />
+
+</svg> \ No newline at end of file
diff --git a/images/gen_feed_dialog.png b/images/gen_feed_dialog.png
new file mode 100644
index 0000000..127693a
--- /dev/null
+++ b/images/gen_feed_dialog.png
Binary files differ
diff --git a/images/gen_feed_icon.png b/images/gen_feed_icon.png
new file mode 100644
index 0000000..7fc0a41
--- /dev/null
+++ b/images/gen_feed_icon.png
Binary files differ
diff --git a/images/icon_classic_128.png b/images/icon_classic_128.png
new file mode 100644
index 0000000..e187ff2
--- /dev/null
+++ b/images/icon_classic_128.png
Binary files differ
diff --git a/images/icon_classic_72.png b/images/icon_classic_72.png
new file mode 100644
index 0000000..9756c1b
--- /dev/null
+++ b/images/icon_classic_72.png
Binary files differ
diff --git a/images/publish_articles.png b/images/publish_articles.png
new file mode 100644
index 0000000..645b784
--- /dev/null
+++ b/images/publish_articles.png
Binary files differ
diff --git a/images/repo-avatars/11.png b/images/repo-avatars/11.png
new file mode 100755
index 0000000..7d62c35
--- /dev/null
+++ b/images/repo-avatars/11.png
Binary files differ
diff --git a/images/repo-avatars/111.png b/images/repo-avatars/111.png
new file mode 100755
index 0000000..7f222a2
--- /dev/null
+++ b/images/repo-avatars/111.png
Binary files differ
diff --git a/images/repo-avatars/13.png b/images/repo-avatars/13.png
new file mode 100755
index 0000000..4747810
--- /dev/null
+++ b/images/repo-avatars/13.png
Binary files differ
diff --git a/images/repo-avatars/166.png b/images/repo-avatars/166.png
new file mode 100755
index 0000000..529a133
--- /dev/null
+++ b/images/repo-avatars/166.png
Binary files differ
diff --git a/images/repo-avatars/2.png b/images/repo-avatars/2.png
new file mode 100755
index 0000000..97aa74a
--- /dev/null
+++ b/images/repo-avatars/2.png
Binary files differ
diff --git a/images/repo-avatars/3.png b/images/repo-avatars/3.png
new file mode 100755
index 0000000..682b892
--- /dev/null
+++ b/images/repo-avatars/3.png
Binary files differ
diff --git a/images/repo-avatars/4.png b/images/repo-avatars/4.png
new file mode 100755
index 0000000..6f77045
--- /dev/null
+++ b/images/repo-avatars/4.png
Binary files differ
diff --git a/images/repo-avatars/55.png b/images/repo-avatars/55.png
new file mode 100755
index 0000000..e4f81be
--- /dev/null
+++ b/images/repo-avatars/55.png
Binary files differ
diff --git a/images/repo-avatars/baseline_extension_black_48dp.png b/images/repo-avatars/baseline_extension_black_48dp.png
new file mode 100755
index 0000000..112e77d
--- /dev/null
+++ b/images/repo-avatars/baseline_extension_black_48dp.png
Binary files differ
diff --git a/images/repo-avatars/iconfinder_social_media_social_media_logo_docker_1916029.png b/images/repo-avatars/iconfinder_social_media_social_media_logo_docker_1916029.png
new file mode 100755
index 0000000..2a800fc
--- /dev/null
+++ b/images/repo-avatars/iconfinder_social_media_social_media_logo_docker_1916029.png
Binary files differ
diff --git a/images/score_indicator2.png b/images/score_indicator2.png
new file mode 100644
index 0000000..4b21dd1
--- /dev/null
+++ b/images/score_indicator2.png
Binary files differ
diff --git a/images/share_anything.png b/images/share_anything.png
new file mode 100644
index 0000000..b4ea919
--- /dev/null
+++ b/images/share_anything.png
Binary files differ
diff --git a/images/tt-comics-web/index.png b/images/tt-comics-web/index.png
new file mode 100644
index 0000000..f38d234
--- /dev/null
+++ b/images/tt-comics-web/index.png
Binary files differ
diff --git a/images/tt-comics-web/reader.png b/images/tt-comics-web/reader.png
new file mode 100644
index 0000000..820cb15
--- /dev/null
+++ b/images/tt-comics-web/reader.png
Binary files differ
diff --git a/images/tt-comics/library.jpg b/images/tt-comics/library.jpg
new file mode 100644
index 0000000..99355c6
--- /dev/null
+++ b/images/tt-comics/library.jpg
Binary files differ
diff --git a/images/tt-comics/library_small.jpg b/images/tt-comics/library_small.jpg
new file mode 100644
index 0000000..0b83753
--- /dev/null
+++ b/images/tt-comics/library_small.jpg
Binary files differ
diff --git a/images/tt-comics/reader.jpg b/images/tt-comics/reader.jpg
new file mode 100644
index 0000000..dd8e440
--- /dev/null
+++ b/images/tt-comics/reader.jpg
Binary files differ
diff --git a/images/tt-comics/reader_small.jpg b/images/tt-comics/reader_small.jpg
new file mode 100644
index 0000000..b4796b4
--- /dev/null
+++ b/images/tt-comics/reader_small.jpg
Binary files differ
diff --git a/images/tt-irc/ttirc_screenshot-OLD.png b/images/tt-irc/ttirc_screenshot-OLD.png
new file mode 100644
index 0000000..a68e88a
--- /dev/null
+++ b/images/tt-irc/ttirc_screenshot-OLD.png
Binary files differ
diff --git a/images/tt-irc/ttirc_screenshot.png b/images/tt-irc/ttirc_screenshot.png
new file mode 100644
index 0000000..86ff5d9
--- /dev/null
+++ b/images/tt-irc/ttirc_screenshot.png
Binary files differ
diff --git a/images/tt-irc/ttirc_screenshot_light.png b/images/tt-irc/ttirc_screenshot_light.png
new file mode 100644
index 0000000..c2ea96d
--- /dev/null
+++ b/images/tt-irc/ttirc_screenshot_light.png
Binary files differ
diff --git a/images/tt-irc/ttirc_screenshot_light_small.jpg b/images/tt-irc/ttirc_screenshot_light_small.jpg
new file mode 100644
index 0000000..5110529
--- /dev/null
+++ b/images/tt-irc/ttirc_screenshot_light_small.jpg
Binary files differ
diff --git a/images/tt-irc/ttirc_screenshot_small.jpg b/images/tt-irc/ttirc_screenshot_small.jpg
new file mode 100644
index 0000000..9bc589f
--- /dev/null
+++ b/images/tt-irc/ttirc_screenshot_small.jpg
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135136.png b/images/tt-rss-android/Screenshot_20250509_135136.png
new file mode 100644
index 0000000..9c6a37b
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135136.png
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135136.webp b/images/tt-rss-android/Screenshot_20250509_135136.webp
new file mode 100644
index 0000000..5fcfaf2
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135136.webp
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135154.png b/images/tt-rss-android/Screenshot_20250509_135154.png
new file mode 100644
index 0000000..eae21de
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135154.png
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135154.webp b/images/tt-rss-android/Screenshot_20250509_135154.webp
new file mode 100644
index 0000000..91fc385
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135154.webp
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135217.png b/images/tt-rss-android/Screenshot_20250509_135217.png
new file mode 100644
index 0000000..e5bcc4d
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135217.png
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135217.webp b/images/tt-rss-android/Screenshot_20250509_135217.webp
new file mode 100644
index 0000000..1d833a7
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135217.webp
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135426.png b/images/tt-rss-android/Screenshot_20250509_135426.png
new file mode 100644
index 0000000..5508232
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135426.png
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135426.webp b/images/tt-rss-android/Screenshot_20250509_135426.webp
new file mode 100644
index 0000000..76414fa
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135426.webp
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135438.png b/images/tt-rss-android/Screenshot_20250509_135438.png
new file mode 100644
index 0000000..3d58327
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135438.png
Binary files differ
diff --git a/images/tt-rss-android/Screenshot_20250509_135438.webp b/images/tt-rss-android/Screenshot_20250509_135438.webp
new file mode 100644
index 0000000..ffae586
--- /dev/null
+++ b/images/tt-rss-android/Screenshot_20250509_135438.webp
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot1.png b/images/tt-rss/18.12/1812-shot1.png
new file mode 100644
index 0000000..bc9256f
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot1.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot1_small.jpg b/images/tt-rss/18.12/1812-shot1_small.jpg
new file mode 100644
index 0000000..9c50d89
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot1_small.jpg
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot1_small.png b/images/tt-rss/18.12/1812-shot1_small.png
new file mode 100644
index 0000000..de041af
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot1_small.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot2.png b/images/tt-rss/18.12/1812-shot2.png
new file mode 100644
index 0000000..f5fee24
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot2.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot2_small.png b/images/tt-rss/18.12/1812-shot2_small.png
new file mode 100644
index 0000000..880fed1
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot2_small.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot3.png b/images/tt-rss/18.12/1812-shot3.png
new file mode 100644
index 0000000..b395b99
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot3.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot3_small.png b/images/tt-rss/18.12/1812-shot3_small.png
new file mode 100644
index 0000000..7241ecd
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot3_small.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot4.png b/images/tt-rss/18.12/1812-shot4.png
new file mode 100644
index 0000000..147e2a3
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot4.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot4_small.png b/images/tt-rss/18.12/1812-shot4_small.png
new file mode 100644
index 0000000..42d8697
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot4_small.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot5.png b/images/tt-rss/18.12/1812-shot5.png
new file mode 100644
index 0000000..1a2ac5c
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot5.png
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot5_small.jpg b/images/tt-rss/18.12/1812-shot5_small.jpg
new file mode 100644
index 0000000..75713be
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot5_small.jpg
Binary files differ
diff --git a/images/tt-rss/18.12/1812-shot5_small.png b/images/tt-rss/18.12/1812-shot5_small.png
new file mode 100644
index 0000000..72a8fd3
--- /dev/null
+++ b/images/tt-rss/18.12/1812-shot5_small.png
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152046.png b/images/tt-rss/21.03/Screenshot_2021-03-10_152046.png
new file mode 100644
index 0000000..43820d3
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152046.png
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152046.webp b/images/tt-rss/21.03/Screenshot_2021-03-10_152046.webp
new file mode 100644
index 0000000..88efa65
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152046.webp
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152046_350px.webp b/images/tt-rss/21.03/Screenshot_2021-03-10_152046_350px.webp
new file mode 100644
index 0000000..158923c
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152046_350px.webp
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152846.png b/images/tt-rss/21.03/Screenshot_2021-03-10_152846.png
new file mode 100644
index 0000000..a4d7caf
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152846.png
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152846.webp b/images/tt-rss/21.03/Screenshot_2021-03-10_152846.webp
new file mode 100644
index 0000000..52b56dd
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152846.webp
Binary files differ
diff --git a/images/tt-rss/21.03/Screenshot_2021-03-10_152846_350px.webp b/images/tt-rss/21.03/Screenshot_2021-03-10_152846_350px.webp
new file mode 100644
index 0000000..24e2ebf
--- /dev/null
+++ b/images/tt-rss/21.03/Screenshot_2021-03-10_152846_350px.webp
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.png b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.png
new file mode 100644
index 0000000..c0e6385
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.png
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.webp b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.webp
new file mode 100644
index 0000000..e07d9ed
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.20.55.webp
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.png b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.png
new file mode 100644
index 0000000..82a266f
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.png
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webp b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webp
new file mode 100644
index 0000000..f62b4dc
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webp
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.png b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.png
new file mode 100644
index 0000000..b6b1ae8
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.png
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webp b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webp
new file mode 100644
index 0000000..9ecdd5b
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webp
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.png b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.png
new file mode 100644
index 0000000..dfb2bb1
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.png
Binary files differ
diff --git a/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webp b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webp
new file mode 100644
index 0000000..edd76ca
--- /dev/null
+++ b/images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webp
Binary files differ
diff --git a/images/xmas-tree.png b/images/xmas-tree.png
new file mode 100644
index 0000000..96dcd48
--- /dev/null
+++ b/images/xmas-tree.png
Binary files differ
diff --git a/images/xmas_hat_128.png b/images/xmas_hat_128.png
new file mode 100644
index 0000000..3d88a1e
--- /dev/null
+++ b/images/xmas_hat_128.png
Binary files differ
diff --git a/index.md b/index.md
new file mode 100644
index 0000000..e7dc737
--- /dev/null
+++ b/index.md
@@ -0,0 +1,66 @@
+---
+hide:
+ - navigation
+ - toc
+---
+
+<style>
+ .md-typeset h1,
+ .md-content__button {
+ display: none;
+ }
+</style>
+
+Tiny Tiny RSS is a free and open source web-based news feed (RSS/Atom) reader and aggregator.
+
+## Screenshots
+
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.19.webp){ width="350", align=left }
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.21.21.webp){ width="350", align=left }
+![](images/tt-rss/25.05/Screenshot_2025-05-10_at_09.22.50.webp){ width="350" }
+
+## Features
+
+- Free software, licensed under [GNU GPLv3](http://www.gnu.org/copyleft/gpl.html);
+- Self-hosted: control your own data and protect your privacy instead of relying on third party services;
+- Supports:
+ - organizing feeds by folders (and subfolders),
+ - [feed aggregation / syndication](wiki/GeneratedFeeds.md),
+ - keyboard shortcuts,
+ - OPML import/export,
+ - multiple ways to share stuff: export RSS feeds, plugins for various social sites, sharing by URL, etc,
+ - [sharing arbitrary content through tt-rss](wiki/ShareAnything.md),
+ - [Plugins](Plugins.md) and [themes](Themes.md),
+ - embedding full article content via readability and site-specific plugins,
+ - deduplication, including [perceptual hashing](https://github.com/supahgreg/tt-rss-plugin-perceptual-image-hash) for images,
+ - podcasts,
+ - [flexible article filtering](wiki/ContentFilters.md),
+ - [JSON API](ApiReference.md),
+ - and much more…
+- [Android client](AndroidClient.md);
+
+## Development
+
+* https://github.com/supahgreg/tt-rss
+
+## Get in touch
+
+Join https://github.com/supahgreg/tt-rss/discussions if you have questions or need to report a bug.
+
+## Contribute
+
+<!-- * Help translate tt-rss into your own language using [Weblate](https://hosted.weblate.org/engage/tt-rss/); -->
+* [Code contribution guidelines](https://github.com/supahgreg/tt-rss/blob/main/CONTRIBUTING.md);
+
+## Installation
+
+You will need the following:
+
+* A modern web browser. This generally means recent Chrome or compatible;
+* A server (VDS or physical) running Docker;
+
+### [Docker installation guide](wiki/InstallationNotes.md)
+
+Tiny Tiny RSS uses continuous development model based on a `main` branch, which is considered stable. If possible, you should always be running latest main branch code.
+
+There’s no warranty. If it breaks you get to keep both parts.
diff --git a/stylesheets/extra.css b/stylesheets/extra.css
new file mode 100644
index 0000000..59c662c
--- /dev/null
+++ b/stylesheets/extra.css
@@ -0,0 +1,10 @@
+.md-content img {
+ border: 1px solid var(--md-primary-fg-color);
+ box-shadow: 0 0 .2rem #0000001a,0 .2rem .4rem #0003;
+}
+
+.md-content h1,
+.md-content h2,
+.md-content h3 {
+ clear : both;
+}