Compare commits
798 Commits
409 changed files with 30131 additions and 9982 deletions
@ -0,0 +1,78 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse; |
|||
|
|||
const BASE = __DIR__.DIRECTORY_SEPARATOR; |
|||
|
|||
$paths = [ |
|||
__FILE__, |
|||
BASE."arsse.php", |
|||
BASE."RoboFile.php", |
|||
BASE."lib", |
|||
BASE."tests/cases", |
|||
BASE."tests/lib", |
|||
BASE."tests/bootstrap.php", |
|||
BASE."tests/server.php", |
|||
]; |
|||
$rules = [ |
|||
// house rules where PSR series is silent |
|||
'align_multiline_comment' => ['comment_type' => "phpdocs_only"], |
|||
'array_syntax' => ['syntax' => "short"], |
|||
'binary_operator_spaces' => [ |
|||
'default' => "single_space", |
|||
'operators' => ['=>' => "align_single_space"], |
|||
], |
|||
'cast_spaces' => ['space' => "single"], |
|||
'concat_space' => ['spacing' => "none"], |
|||
'list_syntax' => ['syntax' => "short"], |
|||
'magic_constant_casing' => true, |
|||
'magic_method_casing' => true, |
|||
'modernize_types_casting' => true, |
|||
'native_function_casing' => true, |
|||
'native_function_type_declaration_casing' => true, |
|||
'no_binary_string' => true, |
|||
'no_blank_lines_after_phpdoc' => true, |
|||
'no_empty_comment' => true, |
|||
'no_empty_phpdoc' => true, |
|||
'no_empty_statement' => true, |
|||
'no_extra_blank_lines' => true, // this could probably use more configuration |
|||
'no_mixed_echo_print' => ['use' => "echo"], |
|||
'no_short_bool_cast' => true, |
|||
'no_trailing_comma_in_singleline_array' => true, |
|||
'no_unneeded_control_parentheses' => true, |
|||
'no_unneeded_curly_braces' => true, |
|||
'no_unused_imports' => true, |
|||
'no_whitespace_before_comma_in_array' => true, |
|||
'normalize_index_brace' => true, |
|||
'object_operator_without_whitespace' => true, |
|||
'pow_to_exponentiation' => true, |
|||
'set_type_to_cast' => true, |
|||
'standardize_not_equals' => true, |
|||
'trailing_comma_in_multiline' => ['elements' => ["arrays"]], |
|||
'unary_operator_spaces' => true, |
|||
'yoda_style' => false, |
|||
// PSR standard to apply |
|||
'@PSR12' => true, |
|||
// house exceptions to PSR rules |
|||
'curly_braces_position' => [ |
|||
'functions_opening_brace' => "same_line", |
|||
'classes_opening_brace' => "same_line", |
|||
], |
|||
'function_declaration' => ['closure_function_spacing' => "none"], |
|||
'new_with_braces' => false, // no option to specify absence of braces |
|||
]; |
|||
|
|||
$finder = \PhpCsFixer\Finder::create(); |
|||
foreach ($paths as $path) { |
|||
if (is_file($path)) { |
|||
$finder = $finder->append([$path]); |
|||
} else { |
|||
$finder = $finder->in($path); |
|||
} |
|||
} |
|||
return (new \PhpCsFixer\Config)->setRiskyAllowed(true)->setRules($rules)->setFinder($finder); |
@ -1,31 +0,0 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
namespace JKingWeb\Arsse; |
|||
|
|||
const BASE = __DIR__.DIRECTORY_SEPARATOR; |
|||
|
|||
$paths = [ |
|||
__FILE__, |
|||
BASE."arsse.php", |
|||
BASE."RoboFile.php", |
|||
BASE."lib", |
|||
BASE."tests", |
|||
]; |
|||
$rules = [ |
|||
'@PSR2' => true, |
|||
'braces' => ['position_after_functions_and_oop_constructs' => "same"], |
|||
'function_declaration' => ['closure_function_spacing' => "none"], |
|||
]; |
|||
|
|||
$finder = \PhpCsFixer\Finder::create(); |
|||
foreach ($paths as $path) { |
|||
if (is_file($path)) { |
|||
$finder = $finder->append([$path]); |
|||
} else { |
|||
$finder = $finder->in($path); |
|||
} |
|||
} |
|||
return \PhpCsFixer\Config::create()->setRules($rules)->setFinder($finder); |
@ -1,208 +1,119 @@ |
|||
# The Advanced RSS Environment |
|||
|
|||
The Arsse is a news aggregator server which implements multiple synchronization protocols, including [version 1.2][NCNv1] of [NextCloud News][NCN]' protocol and the [Tiny Tiny RSS][TTRSS] protocol (details below). Unlike most other aggregator servers, The Arsse does not include a Web front-end (though one is planned as a separate project), and it relies on existing protocols to maximize compatibility with existing clients. |
|||
The Arsse is a news aggregator server, written in PHP, which implements multiple synchronization protocols. Unlike most other aggregator servers, The Arsse does not include a Web front-end (though one is planned as a separate project), and it relies on existing protocols to maximize compatibility with existing clients. |
|||
|
|||
At present the software should be considered in an "alpha" state: though its core subsystems are covered by unit tests and should be free of major bugs, not everything has been rigorously tested. Additionally, many features one would expect from other similar software have yet to be implemented. Areas of future work include: |
|||
Information on how to install and use the software can be found in [the manual](https://thearsse.com/manual/), which is available online as well as with every copy of the software. This readme file instead focuses on how to set up a programming environment to modify the source code. |
|||
|
|||
- Providing more sync protocols (Google Reader, Fever, others) |
|||
- Better packaging and configuration samples |
|||
- A user manual |
|||
# Installing from source |
|||
|
|||
## Requirements |
|||
The main repository for The Arsse can be found at [code.mensbeam.com](https://code.mensbeam.com/MensBeam/arsse/), with a mirror also available [at GitHub](https://github.com/mensbeam/arsse/). The GitHub mirror does not accept bug reports, but the two should otherwise be equivalent. |
|||
|
|||
The Arsse has the following requirements: |
|||
[Composer](https://getcomposer.org/) is required to manage PHP dependencies. After cloning the repository or downloading a source code tarball, running `composer install` will download all the required dependencies, and will advise if any PHP extensions need to be installed. If not installing as a programming environment, running `composer install -o --no-dev --no-scripts` is recommended. |
|||
|
|||
- A Linux server utilizing systemd and Nginx (tested on Ubuntu 16.04) |
|||
- PHP 7.0.7 or later with the following extensions: |
|||
- [intl](http://php.net/manual/en/book.intl.php), [json](http://php.net/manual/en/book.json.php), [hash](http://php.net/manual/en/book.hash.php), and [pcre](http://php.net/manual/en/book.pcre.php) |
|||
- [dom](http://php.net/manual/en/book.dom.php), [simplexml](http://php.net/manual/en/book.simplexml.php), and [iconv](http://php.net/manual/en/book.iconv.php) (for picoFeed) |
|||
- One of: |
|||
- [sqlite3](http://php.net/manual/en/book.sqlite3.php) or [pdo_sqlite](http://php.net/manual/en/ref.pdo-sqlite.php) for SQLite databases |
|||
- [pgsql](http://php.net/manual/en/book.pgsql.php) or [pdo_pgsql](http://php.net/manual/en/ref.pdo-pgsql.php) for PostgreSQL 10 or later databases |
|||
- [mysqli](http://php.net/manual/en/book.mysqli.php) or [pdo_mysql](http://php.net/manual/en/ref.pdo-mysql.php) for MySQL 8.0.7 or later databases |
|||
- Privileges to create and run daemon processes on the server |
|||
# Repository structure |
|||
|
|||
## Installation |
|||
## Library code |
|||
|
|||
At present, installation of The Arsse is rather manual. We hope to improve this in the future, but for now the steps below should help get you started. The instructions and configuration samples assume you will be using Ubuntu 16.04 (or equivalent Debian) and Nginx; we hope to expand official support for different configurations in the future as well. |
|||
The code which runs The Arsse, contained in `/arsse.php`, is only a short stub: the application itself is composed of the classes found under `/lib/`, with the main ones being: |
|||
|
|||
### Initial setup |
|||
| Path | Description | |
|||
|----------------|---------------------------------------------------------| |
|||
| `CLI.php` | The command-line interface, including its documentation | |
|||
| `Conf.php` | Configuration handling | |
|||
| `Database.php` | High-level database interface | |
|||
| `Db/` | Low-level database abstraction layer | |
|||
| `REST/` | Protocol implementations | |
|||
| `REST.php` | General protocol handler for CORS, HTTP auth, etc. | |
|||
| `Arsse.php` | Singleton glueing the parts together | |
|||
|
|||
1. Extract the tar archive to `/usr/share` |
|||
2. If desired, create `/usr/share/arsse/config.php` using `config.defaults.php` as a guide. The file you create only needs to contain non-default settings. The `userPreAuth` setting may be of particular interest |
|||
3. Copy `/usr/share/arsse/dist/arsse.service` to `/lib/systemd/system` |
|||
4. In a terminal, execute the following to start the feed fetching service: |
|||
The `/lib/Database.php` file is the heart of the application, performing queries on behalf of protocol implementations or the command-line interface. |
|||
|
|||
``` sh |
|||
sudo systemctl enable arsse |
|||
sudo systemctl start arsse |
|||
``` |
|||
Also necessary to the functioning of the application is the `/vendor/` directory, which contains PHP libraries which The Arsse depends upon. These are managed by Composer. |
|||
|
|||
### Configuring the Web server and PHP |
|||
## Supporting data files |
|||
|
|||
Sample configuration parameters for Nginx can be found in `arsse/dist/nginx.conf` and `arsse/dist/nginx-fcgi.conf`; the samples assume [a server group](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream) has already been defined for PHP. How to configure an Nginx service to use PHP and install the required PHP extensions is beyond the scope of this document, however. |
|||
The `/locale/` and `/sql/` directories contain human-language files and database schemata, both of which are occasionally used by the application in the course of execution. The `/www/` directory serves as a document root for a few static files to be made available to users by a Web server. |
|||
|
|||
### Adding users |
|||
The `/dist/` directory, on the other hand, contains general and system-specific build files, manual pages, and samples of configuration for Web servers and other system integration. These are not used by The Arsse itself, but are used during the process of preparing new releases for supported operating systems. |
|||
|
|||
The Arsse includes a `user add <username> [<password>]` console command to add users to the database; for example running `php arsse.php user add admin password` will add the user `admin` with the password `pasword` to the database. Other commands for managing users are also available. |
|||
## Documentation |
|||
|
|||
Alternatively, if the Web server is configured to handle authentication, you may set the configuration option `userPreAuth` to `true` and The Arsse will defer to the Web server and automatically add any missing users as it encounters them. |
|||
The source text for The Arsse's manual can be found in `/docs/`, with pages written in [Markdown](https://spec.commonmark.org/current/) and converted to HTML [with Daux](#building-the-manual). If a static manual is generated its files will appear under `/manual/`. |
|||
|
|||
## Installation from source |
|||
The Arsse also has a UNIX manual page written in [mdoc](https://man.archlinux.org/man/extra/mandoc/mandoc_mdoc.7.en) format, which can be found under `/dist/man/`. |
|||
|
|||
If installing from the Git repository rather than a download package, you will need to follow extra steps before the instructions in the section above. |
|||
In addition to the manuals the files `/README.md` (this file), `/CHANGELOG`, `/UPGRADING`, `/LICENSE`, and `/AUTHORS` also document various things about the software, rather than the software itself. |
|||
|
|||
First, you must install [Composer] to fetch required PHP libraries. Once Composer is installed, dependencies may be downloaded with the following command: |
|||
## Tests |
|||
|
|||
``` sh |
|||
php composer.phar install -o --no-dev --no-scripts |
|||
``` |
|||
The `/tests/` directory contains everything related to automated testing. It is itself organized as follows: |
|||
|
|||
Second, you may wish to create an example configuration file using the following command: |
|||
| Path | Description | |
|||
|--------------------|------------------------------------------------------------------------------------| |
|||
| `cases/` | The test cases themselves, organized in roughly the same structure as the code | |
|||
| `coverage/` | (optional) Generated code coverage reports | |
|||
| `docroot/` | Sample documents used in some tests, to be returned by PHP's basic HTTP server | |
|||
| `lib/` | Supporting classes which do not contain test cases | |
|||
| `bootstrap.php` | Bootstrap script, equivalent to `/arsse.php`, but for tests | |
|||
| `phpunit.dist.xml` | PHPUnit configuration file | |
|||
| `server.php` | Simple driver for the PHP HTTP server used during testing | |
|||
|
|||
``` sh |
|||
php ./arsse.php conf save-defaults "./config.defaults.php" |
|||
``` |
|||
PHPUnit's configuration can be customized by copying its configuration file to `/tests/phpunit.xml` and modifying the copy accordingly. |
|||
|
|||
## License |
|||
## Tooling |
|||
|
|||
The Arsse is made available under the permissive MIT license. See the `LICENSE` and `AUTHORS` files included with the distribution or source code for exact legal text and copyright holders. Dependencies included in the distribution may be governed by other licenses. |
|||
The `/vendor-bin/` directory houses the files needed for the tools used in The Arsse's programming environment. These are managed by the Composer ["bin" plugin](https://github.com/bamarni/composer-bin-plugin) and are not used by The Arsse itself. The following files are also related to various programming tools: |
|||
|
|||
## Contributing |
|||
| Path | Description | |
|||
|---------------------------|----------------------------------------------------------| |
|||
| `/.gitattributes` | Git settings for handling files | |
|||
| `/.gitignore` | Git file exclusion patterns | |
|||
| `/.php-cs-fixer.dist.php` | Configuration for [php-cs-fixer](https://cs.symfony.com) | |
|||
| `/.php-cs-fixer.cache` | Cache for php-cs-fixer | |
|||
| `/composer.json` | Configuration for Composer | |
|||
| `/composer.lock` | Version synchronization data for Composer | |
|||
| `/RoboFile.php` | Task definitions for [Robo](https://robo.li/) | |
|||
| `/robo` | Simple wrapper for executing Robo on POSIX systems | |
|||
| `/robo.bat` | Simple wrapper for executing Robo on Windows | |
|||
|
|||
Please refer to `CONTRIBUTING.md` for guidelines on contributing code to The Arsse. |
|||
In addition the files `/package.json` and `/postcss.config.js` as well as the `/node_modules/` directory are used by [Yarn](https://yarnpkg.com/) and [PostCSS](https://postcss.org/) when modifying the stylesheet for The Arsse's manual. |
|||
|
|||
## Database compatibility notes |
|||
# Common tasks |
|||
|
|||
Functionally there is no reason to prefer either SQLite or PostgreSQL over the other. SQLite is significantly simpler to set up in most cases, requiring only read and write access to a containing directory in order to function; PostgreSQL may perform better than SQLite when serving hundreds of users or more, though this has not been tested. |
|||
We use a tool called [Robo](https://robo.li/) to simplify the execution of common tasks. It is installed with The Arsse's other dependencies, and its configured tasks can be listed by executing `./robo` without arguments. |
|||
|
|||
MySQL, on the other hand, is **not recommended** due to its relatively constrained index prefix limits which may cause some newsfeeds which would otherwise work to be rejected. If using MySQL, special care should also be taken when performing schema upgrades, as errors during the process can leave the database in a half-upgraded state which The Arsse cannot itself recover from. |
|||
## Running tests |
|||
|
|||
Note that MariaDB is not compatible with The Arsse: its support for common table expressions is, as of this writing, not sufficient for our needs. |
|||
The Arsse has an extensive [PHPUnit](https://phpunit.de/) test suite; tests can be run by executing `./robo test`, which can be supplemented with any arguments understoof by PHPUnit. For example, to test only the Tiny Tiny RSS protocol, one could run `./robo test --testsuite TTRSS`. |
|||
|
|||
## Protocol compatibility notes |
|||
There is also a `test:quick` Robo task which excludes slower tests, and a `test:full` task which includes redundant tests in addition to the standard test suite |
|||
|
|||
### General |
|||
### Test coverage |
|||
|
|||
#### Type casting |
|||
Computing the coverage of tests can be done by running `./robo coverage`, after which an HTML-format coverage report will be written to `/tests/coverage/`. Either [PCOV](https://github.com/krakjoe/pcov) or [Xdebug](https://xdebug.org) is required for this. PCOV is generally recommended as it is faster than Xdebug. Neither extension need be enabled globally; Robo will enable it when needed. |
|||
|
|||
The Arsse does not guarantee it will handle type casting of input in the same way as reference implementations for its supported protocols. As a general rule, clients should endeavour to send only correct input. |
|||
## Enforcing coding style |
|||
|
|||
The Arsse does, however, guarantee _output_ to be of the same type. If it is not, this is [a bug][newIssue] and should be reported. |
|||
The [php-cs-fixer](https://cs.symfony.com) tool, executed via `./robo clean`, can be used to rewrite code to adhere to The Arsse's coding style. The style largely follows [PSR-12](https://www.php-fig.org/psr/psr-12/) with some exceptions: |
|||
|
|||
#### Content sanitization |
|||
- Classes, methods, and functions should have their opening brace on the same line as the signature |
|||
- Anonymous functions should have no space before the parameter list |
|||
|
|||
The Arsse makes use of the [picoFeed] newsfeed parsing library to sanitize article content. The exact sanitization parameters may differ from those of reference implementations for protocols The Arsse supports. |
|||
## Building the manual |
|||
|
|||
### NextCloud News v1.2 |
|||
The Arsse's user manual, made using [Daux](https://daux.io/), can be compiled by running `./robo manual`, which will output files to `/manual/`. It is also possible to serve the manual from a test HTTP server on port 8085 by running `./robo manual:live`. |
|||
|
|||
As a general rule, The Arsse should yield the same output as the reference implementation for all valid inputs (otherwise you've found [a bug][newIssue]), but there are exception, either because the NextCloud News (hereafter "NCN") [protocol description][NCNv1] is at times ambiguous or incomplete, or because implementation details necessitate it differ; this section along with the General section above detail these differences. |
|||
### Rebuilding the manual theme |
|||
|
|||
#### Differences |
|||
The manual employs a custom theme derived from the standard Daux theme. If the standard Daux theme receives improvements, the custom theme can be rebuilt by running `./robo manual:theme`. This requires that [NodeJS](https://nodejs.org) and [Yarn](https://yarnpkg.com/) be installed, but JavaScript tools are not required to modify The Arsse itself, nor the content of the manual. |
|||
|
|||
- Article GUID hashes are not hashes like in NCN; they are integers rendered as strings |
|||
- Article fingerprints are a combination of hashes rather than a single hash |
|||
- When marking articles as starred the feed ID is ignored, as they are not needed to establish uniqueness |
|||
- The feed updater ignores the `userId` parameter: feeds in The Arsse are deduplicated, and have no owner |
|||
- The `/feeds/all` route lists only feeds which should be checked for updates, and it also returns all `userId` attributes as empty strings: feeds in The Arsse are deduplicated, and have no owner |
|||
- The API's "updater" routes do not require administrator priviledges as The Arsse has no concept of user classes |
|||
- The "updater" console commands mentioned in the protocol specification are not implemented, as The Arsse does not implement the required NextCloud subsystems |
|||
- The `lastLoginTimestamp` attribute of the user metadata is always the current time: The Arsse's implementation of the protocol is fully stateless |
|||
- Syntactically invalid JSON input will yield a `400 Bad Request` response instead of falling back to GET parameters |
|||
- Folder names consisting only of whitespace are rejected along with the empty string |
|||
- Feed titles consisting only of whitespace or the empty string are rejected with a `422 Unprocessable Entity` reponse instead of being accepted |
|||
- Bulk-marking operations without a `newestItemId` argument result in a `422 Unprocessable Entity` reponse instead of silently failing |
|||
- Creating a feed in a folder which does not exist places the feed in the root folder rather than suppressing the feed |
|||
- Moving a feed to a folder which does not exist results in a `422 Unprocessable Entity` reponse rather than suppressing the feed |
|||
## Packaging a release |
|||
|
|||
### Tiny Tiny RSS |
|||
Producing release packages is done by running `./robo package`. This performs the following operations: |
|||
|
|||
As a general rule, The Arsse should yield the same output as the reference implementation for all valid inputs (otherwise you've found [a bug][newIssue]), but there are exception, either because the Tiny Tiny RSS (hereafter "TTRSS") [protocol description][TTRSS] is incomplete, erroneous, or out of date, or because TTRSS itself is buggy, or because implementation details necessitate The Arsse differ; this section along with the General section above detail these differences. |
|||
|
|||
#### Extended functionality |
|||
|
|||
The Arsse supports both [the set of extensions][ext-feedreader] to the TTRSS protocol defined by [FeedReader], as well as [the `getCompactHeadlines` operation][ext-newsplus] defined by [News+]. |
|||
|
|||
We are not aware of any other extensions to the TTRSS protocol. If you know of any more, please [let us know][newIssue]. |
|||
|
|||
#### Missing features |
|||
|
|||
- The `getPref` operation is not implemented; it returns `UNKNOWN_METHOD` |
|||
- The `shareToPublished` operation is not implemented; it returns `UNKNOWN_METHOD` |
|||
- Setting an article's "published" flag with the `updateArticle` operation is not implemented and will gracefully fail |
|||
- The `sanitize`, `force_update`, and `has_sandbox` parameters of the `getHeadlines` operation are ignored |
|||
- String `feed_id` values for the `getCompactHeadlines` operation are not supported and will yield an `INCORRECT_USAGE` error |
|||
- Articles are limited to a single attachment rather than multiple attachments |
|||
|
|||
#### Differences |
|||
|
|||
- Input that cannot be parsed as JSON normally returns a `NOT_LOGGED_IN` error; The Arsse returns a non-standard `MALFORMED_INPUT` error instead |
|||
- Feed, category, and label names are normally unrestricted; The Arsse rejects empty strings, as well as strings composed solely of whitespace |
|||
- Discovering multiple feeds during `subscribeToFeed` processing normally produces an error; The Arsse instead chooses the first feed it finds |
|||
- Providing the `setArticleLabel` operation with an invalid label normally silently fails; The Arsse returns an `INVALID_USAGE` error instead |
|||
- Processing of the `search` parameter of the `getHeadlines` operation differs in the following ways: |
|||
- Values other than `"true"` or `"false"` for the `unread`, `star`, and `pub` special keywords treat the entire token as a search term rather than as `"false"` |
|||
- Invalid dates are ignored rather than assumed to be `"1970-01-01"` |
|||
- Only a single negative date is allowed (this is a known bug rather than intentional) |
|||
- Dates are always relative to UTC |
|||
- Full-text search is not yet employed with any database, including PostgreSQL |
|||
- Article hashes are normally SHA1; The Arsse uses SHA256 hashes |
|||
- Article attachments normally have unique IDs; The Arsse always gives attachments an ID of `"0"` |
|||
- The default sort order of the `getHeadlines` operation normally uses custom sorting for "special" feeds; The Arsse's default sort order is equivalent to `feed_dates` for all feeds |
|||
- The `getCounters` operation normally omits members with zero unread; The Arsse includes everything to appease some clients |
|||
|
|||
#### Other notes |
|||
|
|||
- TTRSS accepts base64-encoded passwords, though this is undocumented; The Arsse accepts base64-encoded passwords as well |
|||
- TTRSS sometimes returns an incorrect count from the `setArticleLabel` operation; The Arsse returns a correct count in all cases |
|||
- TTRSS sometimes returns out-of-date cached information; The Arsse does not use caches as TTRSS does, so information is always current |
|||
- TTRSS returns results for _feed_ ID `-3` when providing the `getHeadlines` operation with _category_ ID `-3`; The Arsse retuns the correct results |
|||
- The protocol doucmentation advises not to use `limit` or `skip` together with `unread_only` for the `getFeeds` operation as it produces unpredictable results; The Arsse produces predictable results by first retrieving all unread feeds and then applying `skip` and `limit` |
|||
- The protocol documentation on values for the `view_mode` parameter of the `getHeadlines` operation is out of date; The Arsse matches the actual implementation and supports the undocumented `published` and `has_note` values exposed by the Web user interface |
|||
- The protocol documentation makes mention of a `search_mode` parameter for the `getHeadlines` operation, but this seems to be ignored; The Arsse does not implement it |
|||
- The protocol documentation makes mention of an `output_mode` parameter for the `getCounters` operation, but this seems to be ignored; The Arsse does not implement it |
|||
- The documentation for the `getCompactHeadlines` operation states the default value for `limit` is 20, but the reference implementation defaults to unlimited; The Arsse also defaults to unlimited |
|||
- It is assumed TTRSS exposes other undocumented behaviour; unless otherwise noted The Arsse only implements documented behaviour |
|||
|
|||
#### Interaction with HTTP authentication |
|||
|
|||
Tiny Tiny RSS itself is unaware of HTTP authentication: if HTTP authentication is used in the server configuration, it has no effect on authentication in the API. The Arsse, however, makes use of HTTP authentication for NextCloud News, and can do so for TTRSS as well. In a default configuration The Arsse functions in the same way as TTRSS: HTTP authentication and API authentication are completely separate and independent. Alternative behaviour is summarized below: |
|||
|
|||
- With default settings: |
|||
- Clients may optionally provide HTTP credentials |
|||
- API authentication proceeds as normal |
|||
- All feed icons are visible to unauthenticated clients |
|||
- If the `userHTTPAuthRequired` setting is `true`: |
|||
- Clients must pass HTTP authentication |
|||
- API authentication proceeds as normal |
|||
- Feed icons are visible only to their owners |
|||
- If the `userSessionEnforced` setting is `false`: |
|||
- Clients may optionally provide HTTP credentials |
|||
- If HTTP authentication succeeded API authentication is skipped: tokens are issued upon login, but ignored for HTTP-authenticated requests |
|||
- All feed icons are visible to unauthenticated clients |
|||
- If the `userHTTPAuthRequired` setting is `true` and the `userSessionEnforced` setting is `false`: |
|||
- Clients must pass HTTP authentication |
|||
- API authentication is skipped: tokens are issued upon login, but thereafter ignored |
|||
- Feed icons are visible only to their owners |
|||
- If the `userPreAuth` setting is `true`: |
|||
- The Web server asserts HTTP authentication was successful |
|||
- API authentication only checks that HTTP and API user names match |
|||
- Feed icons are visible only to their owners |
|||
- If the `userPreAuth` setting is `true` and the `userSessionEnforced` setting is `false`: |
|||
- The Web server asserts HTTP authentication was successful |
|||
- API authentication is skipped: tokens are issued upon login, but thereafter ignored |
|||
- Feed icons are visible only to their owners |
|||
|
|||
In all cases, supplying invalid HTTP credentials will result in a 401 response. |
|||
|
|||
[newIssue]: https://code.mensbeam.com/MensBeam/arsse/issues/new |
|||
[Composer]: https://getcomposer.org/ |
|||
[picoFeed]: https://github.com/miniflux/picoFeed/ |
|||
[NCN]: https://github.com/nextcloud/news |
|||
[NCNv1]: https://github.com/nextcloud/news/blob/master/docs/externalapi/Legacy.md |
|||
[CORS]: https://fetch.spec.whatwg.org/#http-cors-protocol |
|||
[TTRSS]: https://git.tt-rss.org/git/tt-rss/wiki/ApiReference |
|||
[FeedReader]: https://jangernert.github.io/FeedReader/ |
|||
[News+]: https://github.com/noinnion/newsplus/ |
|||
[ext-feedreader]: https://github.com/jangernert/FeedReader/tree/master/data/tt-rss-feedreader-plugin |
|||
[ext-newsplus]: https://github.com/hrk/tt-rss-newsplus-plugin |
|||
- Duplicates a [Git](https://git-scm.com/) working tree with the commit (usually a release tag) to package |
|||
- Generates the HTML manual |
|||
- Installs runtime Composer dependencies with an optimized autoloader |
|||
- Deletes numerous unneeded files |
|||
- Exports the default configuration of The Arsse to a file |
|||
- Compresses the remaining files into a tarball |
|||
|
File diff suppressed because it is too large
@ -0,0 +1,5 @@ |
|||
ProxyPreserveHost On |
|||
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/usr/share/arsse/arsse.php" |
|||
ProxyFCGISetEnvIf "-n req('Authorization')" HTTP_AUTHORIZATION "%{req:Authorization}" |
|||
|
|||
ProxyPass "unix:/var/run/php/arsse.sock|fcgi://localhost/usr/share/arsse/" |
@ -0,0 +1,34 @@ |
|||
# Nextcloud News protocol |
|||
<Location "/index.php/apps/news/api"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Tiny Tiny RSS protocol |
|||
<Location "/tt-rss/api"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Tiny Tiny RSS feed icons |
|||
<Location "/tt-rss/feed-icons"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Fever protocol |
|||
<Location "/fever"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Miniflux protocol |
|||
<Location "/v1"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Miniflux version number |
|||
<Location "/version"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
|||
|
|||
# Miniflux "health check" |
|||
<Location "/healthcheck"> |
|||
Include "/etc/arsse/apache/arsse-fcgi.conf" |
|||
</Location> |
@ -0,0 +1,6 @@ |
|||
DocumentRoot "/usr/share/arsse/www" |
|||
<Directory "/usr/share/arsse/www"> |
|||
Require all granted |
|||
</Directory> |
|||
|
|||
Include "/etc/arsse/apache/arsse-loc.conf" |
@ -0,0 +1,9 @@ |
|||
<VirtualHost *:443> |
|||
ServerName "news.example.com" |
|||
SSLEngine On |
|||
|
|||
SSLCertificateFile "/etc/letsencrypt/live/news.example.com/fullchain.pem" |
|||
SSLCertificateKeyFile "/etc/letsencrypt/live/news.example.com/privkey.pem" |
|||
|
|||
Include "/etc/arsse/apache/arsse.conf" |
|||
</VirtualHost> |
@ -0,0 +1,64 @@ |
|||
# Maintainer: J. King <jking@jkingweb.ca> |
|||
pkgname="arsse" |
|||
pkgver=0.10.4 |
|||
pkgrel=1 |
|||
epoch= |
|||
pkgdesc="Multi-protocol RSS/Atom newsfeed synchronization server" |
|||
arch=("any") |
|||
url="https://thearsse.com/" |
|||
license=("MIT") |
|||
conflicts=("arsse-git") |
|||
depends=() |
|||
makedepends=() |
|||
checkdepends=() |
|||
optdepends=("nginx: HTTP server" |
|||
"apache>=2.4: HTTP server" |
|||
"percona-server: Alternate database" |
|||
"postgresql>=10: Alternate database" |
|||
"php-pgsql-interpreter>=7.3: PostgreSQL database support") |
|||
backup=("etc/webapps/arsse/config.php" |
|||
"etc/webapps/arsse/systemd-environment" |
|||
"etc/php/php-fpm.d/arsse.conf" |
|||
"etc/php-legacy/php-fpm.d/arsse.conf" |
|||
"etc/webapps/arsse/nginx/example.conf" |
|||
"etc/webapps/arsse/nginx/arsse.conf" |
|||
"etc/webapps/arsse/nginx/arsse-loc.conf" |
|||
"etc/webapps/arsse/nginx/arsse-fcgi.conf" |
|||
"etc/webapps/arsse/apache/example.conf" |
|||
"etc/webapps/arsse/apache/arsse.conf" |
|||
"etc/webapps/arsse/apache/arsse-fcgi.conf" |
|||
"etc/webapps/arsse/apache/arsse-loc.conf") |
|||
source=("arsse-0.10.4.tar.gz") |
|||
md5sums=("SKIP") |
|||
|
|||
package() { |
|||
# define runtime dependencies |
|||
depends=("php-interpreter>=7.3" "php-sqlite-interpreter>=7.3" "php-fpm-interpreter>=7.3") |
|||
# create most directories necessary for the final package |
|||
cd "$pkgdir" |
|||
mkdir -p "usr/share/webapps/arsse" "usr/share/doc/arsse" "usr/share/licenses/arsse" "usr/lib/systemd/system" "usr/lib/sysusers.d" "usr/lib/tmpfiles.d" "etc/php/php-fpm.d" "etc/php-legacy/php-fpm.d" "etc/webapps/arsse" |
|||
# copy requisite files |
|||
cd "$srcdir/arsse" |
|||
cp -r lib locale sql vendor www CHANGELOG UPGRADING README.md arsse.php "$pkgdir/usr/share/webapps/arsse" |
|||
cp -r manual/* "$pkgdir/usr/share/doc/arsse" |
|||
cp LICENSE AUTHORS "$pkgdir/usr/share/licenses/arsse" |
|||
cp dist/sysuser.conf "$pkgdir/usr/lib/sysusers.d/arsse.conf" |
|||
cp dist/tmpfiles.conf "$pkgdir/usr/lib/tmpfiles.d/arsse.conf" |
|||
cp dist/php-fpm.conf "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
cp -r dist/man "$pkgdir/usr/share" |
|||
cp -r dist/nginx dist/apache config.defaults.php "$pkgdir/etc/webapps/arsse" |
|||
# copy files requiring special permissions |
|||
install -Dm640 dist/config.php "$pkgdir/etc/webapps/arsse" |
|||
# patch generic configuration files to use Arch-specific paths and identifiers |
|||
sed -i -se 's/\/\(etc\|usr\/share\)\/arsse\//\/\1\/webapps\/arsse\//g' "$pkgdir/etc/webapps/arsse/nginx/"* "$pkgdir/etc/webapps/arsse/apache/"* "$pkgdir/usr/lib/tmpfiles.d/arsse.conf" |
|||
sed -i -se 's/\/var\/run\/php\//\/run\/php-fpm\//g' "$pkgdir/etc/webapps/arsse/nginx/"* "$pkgdir/etc/webapps/arsse/apache/"* "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
sed -i -se 's/www-data/http/g' "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
# make a duplicate PHP-FPM pool for php-legacy |
|||
sed -se 's/php-fpm/php-fpm-legacy/' "$pkgdir/etc/php/php-fpm.d/arsse.conf" > "$pkgdir/etc/php-legacy/php-fpm.d/arsse.conf" |
|||
# copy Arch-specific versions of files |
|||
install -Dm755 dist/arch/arsse "$pkgdir/usr/bin/arsse" |
|||
cp dist/arch/nginx-arsse-fcgi.conf "$pkgdir/etc/webapps/arsse/nginx/arsse-fcgi.conf" |
|||
cp dist/arch/apache-arsse-fcgi.conf "$pkgdir/etc/webapps/arsse/apache/arsse-fcgi.conf" |
|||
cp dist/arch/*.service "$pkgdir/usr/lib/systemd/system" |
|||
cp dist/arch/systemd-environment "$pkgdir/etc/webapps/arsse/systemd-environment" |
|||
} |
@ -0,0 +1,79 @@ |
|||
# Maintainer: J. King <jking@jkingweb.ca> |
|||
pkgname="arsse-git" |
|||
pkgver=0.10.4 |
|||
pkgrel=1 |
|||
epoch= |
|||
pkgdesc="Multi-protocol RSS/Atom newsfeed synchronization server, bugfix-testing version" |
|||
arch=("any") |
|||
url="https://thearsse.com/" |
|||
license=("MIT") |
|||
provides=("arsse") |
|||
conflicts=("arsse") |
|||
depends=("php-interpreter>=7.3" "php-intl-interpreter>=7.3" "php-sqlite-interpreter>=7.3") |
|||
makedepends=("composer") |
|||
checkdepends=() |
|||
optdepends=("nginx: HTTP server" |
|||
"apache>=2.4: HTTP server" |
|||
"percona-server: Alternate database" |
|||
"postgresql>=10: Alternate database" |
|||
"php-pgsql-interpreter>=7.3: PostgreSQL database support") |
|||
backup=("etc/webapps/arsse/config.php" |
|||
"etc/webapps/arsse/systemd-environment" |
|||
"etc/php/php-fpm.d/arsse.conf" |
|||
"etc/php-legacy/php-fpm.d/arsse.conf" |
|||
"etc/webapps/arsse/nginx/example.conf" |
|||
"etc/webapps/arsse/nginx/arsse.conf" |
|||
"etc/webapps/arsse/nginx/arsse-loc.conf" |
|||
"etc/webapps/arsse/nginx/arsse-fcgi.conf" |
|||
"etc/webapps/arsse/apache/example.conf" |
|||
"etc/webapps/arsse/apache/arsse.conf" |
|||
"etc/webapps/arsse/apache/arsse-fcgi.conf" |
|||
"etc/webapps/arsse/apache/arsse-loc.conf") |
|||
source=("git+https://code.mensbeam.com/MensBeam/arsse/") |
|||
md5sums=("SKIP") |
|||
|
|||
pkgver() { |
|||
cd "arsse" |
|||
git describe --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g' |
|||
} |
|||
|
|||
build() { |
|||
cd "$srcdir/arsse" |
|||
composer install |
|||
./robo manual |
|||
composer install --no-dev -o --no-scripts |
|||
php arsse.php conf save-defaults config.defaults.php |
|||
rm -r vendor/bin |
|||
} |
|||
|
|||
package() { |
|||
# define runtime dependencies |
|||
depends=("php-interpreter>=7.3" "php-sqlite-interpreter>=7.3" "php-fpm-interpreter>=7.3") |
|||
# create most directories necessary for the final package |
|||
cd "$pkgdir" |
|||
mkdir -p "usr/share/webapps/arsse" "usr/share/doc/arsse" "usr/share/licenses/arsse" "usr/lib/systemd/system" "usr/lib/sysusers.d" "usr/lib/tmpfiles.d" "etc/php/php-fpm.d" "etc/php-legacy/php-fpm.d" "etc/webapps/arsse" |
|||
# copy requisite files |
|||
cd "$srcdir/arsse" |
|||
cp -r lib locale sql vendor www CHANGELOG UPGRADING README.md arsse.php "$pkgdir/usr/share/webapps/arsse" |
|||
cp -r manual/* "$pkgdir/usr/share/doc/arsse" |
|||
cp LICENSE AUTHORS "$pkgdir/usr/share/licenses/arsse" |
|||
cp dist/sysuser.conf "$pkgdir/usr/lib/sysusers.d/arsse.conf" |
|||
cp dist/tmpfiles.conf "$pkgdir/usr/lib/tmpfiles.d/arsse.conf" |
|||
cp dist/php-fpm.conf "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
cp -r dist/man "$pkgdir/usr/share" |
|||
cp -r dist/nginx dist/apache config.defaults.php "$pkgdir/etc/webapps/arsse" |
|||
# copy files requiring special permissions |
|||
install -Dm640 dist/config.php "$pkgdir/etc/webapps/arsse" |
|||
# patch generic configuration files to use Arch-specific paths and identifiers |
|||
sed -i -se 's/\/\(etc\|usr\/share\)\/arsse\//\/\1\/webapps\/arsse\//g' "$pkgdir/etc/webapps/arsse/nginx/"* "$pkgdir/etc/webapps/arsse/apache/"* "$pkgdir/usr/lib/tmpfiles.d/arsse.conf" |
|||
sed -i -se 's/\/var\/run\/php\//\/run\/php-fpm\//g' "$pkgdir/etc/webapps/arsse/nginx/"* "$pkgdir/etc/webapps/arsse/apache/"* "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
sed -i -se 's/www-data/http/g' "$pkgdir/etc/php/php-fpm.d/arsse.conf" |
|||
# make a duplicate PHP-FPM pool for php-legacy |
|||
sed -se 's/php-fpm/php-fpm-legacy/' "$pkgdir/etc/php/php-fpm.d/arsse.conf" > "$pkgdir/etc/php-legacy/php-fpm.d/arsse.conf" |
|||
# copy Arch-specific versions of files |
|||
install -Dm755 dist/arch/arsse "$pkgdir/usr/bin/arsse" |
|||
cp dist/arch/nginx-arsse-fcgi.conf "$pkgdir/etc/webapps/arsse/nginx/arsse-fcgi.conf" |
|||
cp dist/arch/apache-arsse-fcgi.conf "$pkgdir/etc/webapps/arsse/apache/arsse-fcgi.conf" |
|||
cp dist/arch/*.service "$pkgdir/usr/lib/systemd/system" |
|||
cp dist/arch/systemd-environment "$pkgdir/etc/webapps/arsse/systemd-environment" |
|||
} |
@ -0,0 +1,6 @@ |
|||
ProxyPreserveHost On |
|||
ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/usr/share/webapps/arsse/arsse.php" |
|||
ProxyFCGISetEnvIf "-n req('Authorization')" HTTP_AUTHORIZATION "%{req:Authorization}" |
|||
|
|||
# Modify the below line to begin with "unix:/run/php-fpm-legacy/" if using the php-legacy package |
|||
ProxyPass "unix:/run/php-fpm/arsse.sock|fcgi://localhost/usr/share/webapps/arsse/" |
@ -0,0 +1,28 @@ |
|||
#!/usr/bin/env bash |
|||
|
|||
readonly default_php="/usr/bin/php" |
|||
php="" |
|||
|
|||
check_sudo() { |
|||
if ! command -v sudo > /dev/null; then |
|||
printf "The sudo command is not available.\n" |
|||
exit 1 |
|||
fi |
|||
} |
|||
|
|||
# allow overriding the php executable |
|||
if [ -n "${ARSSE_PHP}" ] && command -v "${ARSSE_PHP}" > /dev/null; then |
|||
php="${ARSSE_PHP}" |
|||
else |
|||
php="${default_php}" |
|||
fi |
|||
|
|||
if [ "$(whoami)" = "arsse" ]; then |
|||
"$php" /usr/share/webapps/arsse/arsse "$@" |
|||
elif [ "${UID}" -eq 0 ]; then |
|||
runuser -u "arsse" -- "$php" /usr/share/webapps/arsse/arsse "$@" |
|||
else |
|||
check_sudo |
|||
sudo -u "arsse" "$php" /usr/share/webapps/arsse/arsse "$@" |
|||
fi |
|||
|
@ -0,0 +1,37 @@ |
|||
[Unit] |
|||
Description=The Arsse newsfeed fetching service |
|||
Documentation=https://thearsse.com/manual/ |
|||
PartOf=arsse.service |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
|
|||
[Service] |
|||
User=arsse |
|||
Group=arsse |
|||
Type=simple |
|||
WorkingDirectory=/usr/share/webapps/arsse |
|||
EnvironmentFile=/etc/webapps/arsse/systemd-environment |
|||
ExecStart=/usr/bin/arsse daemon |
|||
|
|||
ProtectProc=invisible |
|||
NoNewPrivileges=true |
|||
ProtectSystem=full |
|||
ProtectHome=true |
|||
StateDirectory=arsse |
|||
ConfigurationDirectory=arsse |
|||
PrivateTmp=true |
|||
PrivateDevices=true |
|||
RestrictSUIDSGID=true |
|||
StandardOutput=journal |
|||
StandardError=journal |
|||
SyslogIdentifier=arsse |
|||
Restart=on-failure |
|||
RestartPreventStatus= |
|||
|
|||
# These directives can be used for extra security, but are disabled for now for compatibility |
|||
|
|||
#ReadOnlyPaths=/ |
|||
#ReadWriePaths=/var/lib/arsse |
|||
#NoExecPaths=/ |
|||
#ExecPaths=/usr/bin/php |
@ -0,0 +1,13 @@ |
|||
[Unit] |
|||
Description=The Arsse newsfeed management service |
|||
Documentation=https://thearsse.com/manual/ |
|||
Requires=arsse-fetch.service |
|||
Wants=php-fpm.service php-legacy-fpm.service |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
|
|||
[Service] |
|||
Type=oneshot |
|||
RemainAfterExit=true |
|||
ExecStart=/usr/bin/true |
@ -0,0 +1,16 @@ |
|||
fastcgi_pass_header Authorization; # required if the Arsse is to perform its own HTTP authentication |
|||
fastcgi_pass_request_body on; |
|||
fastcgi_pass_request_headers on; |
|||
fastcgi_intercept_errors off; |
|||
fastcgi_buffering off; |
|||
fastcgi_param REQUEST_METHOD $request_method; |
|||
fastcgi_param CONTENT_TYPE $content_type; |
|||
fastcgi_param CONTENT_LENGTH $content_length; |
|||
fastcgi_param REQUEST_URI $uri; |
|||
fastcgi_param QUERY_STRING $query_string; |
|||
fastcgi_param HTTPS $https if_not_empty; |
|||
fastcgi_param REMOTE_USER $remote_user; |
|||
fastcgi_param SCRIPT_FILENAME /usr/share/webapps/arsse/arsse.php; |
|||
|
|||
# Modify the below line to begin with "/run/php-fpm-legacy/" if using the php-legacy package |
|||
fastcgi_pass unix:/run/php-fpm/arsse.sock; |
@ -0,0 +1 @@ |
|||
ARSSE_PHP=/usr/bin/php |
@ -0,0 +1,10 @@ |
|||
#! /usr/bin/env php |
|||
<?php |
|||
if (posix_geteuid() == 0) { |
|||
$info = posix_getpwnam("arsse"); |
|||
if ($info) { |
|||
posix_setgid($info['gid']); |
|||
posix_setuid($info['uid']); |
|||
} |
|||
} |
|||
require "/usr/share/arsse/arsse.php"; |
@ -1,15 +0,0 @@ |
|||
[Unit] |
|||
Description=The Arsse feed fetching service |
|||
After=network.target |
|||
|
|||
[Service] |
|||
User=www-data |
|||
Group=www-data |
|||
WorkingDirectory=/usr/share/arsse |
|||
Type=simple |
|||
StandardOutput=null |
|||
StandardError=syslog |
|||
ExecStart=/usr/bin/env php /usr/share/arsse/arsse.php daemon |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
@ -0,0 +1,8 @@ |
|||
<?php |
|||
|
|||
# Please refer to config.defaults.php or the manual at /usr/share/doc/arsse/ |
|||
# for possible configuration parameters |
|||
|
|||
return [ |
|||
'dbSQLite3File' => "/var/lib/arsse/arsse.db", |
|||
]; |
@ -0,0 +1,16 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
. /usr/share/debconf/confmodule |
|||
|
|||
# Set up dbconfig-common |
|||
if test -f /usr/share/dbconfig-common/dpkg/config; then |
|||
. /usr/share/dbconfig-common/dpkg/config |
|||
dbc_dbtypes="sqlite3, pgsql, mysql" |
|||
dbc_authmethod_user="password" |
|||
dbc_go arsse "$@" |
|||
fi |
|||
|
|||
# Prompt for dbconfig-common configuration |
|||
db_go || true |
@ -0,0 +1 @@ |
|||
var/lib/arsse |
@ -0,0 +1,18 @@ |
|||
lib usr/share/arsse/ |
|||
locale usr/share/arsse/ |
|||
sql usr/share/arsse/ |
|||
vendor usr/share/arsse/ |
|||
www usr/share/arsse/ |
|||
CHANGELOG usr/share/arsse/ |
|||
UPGRADING usr/share/arsse/ |
|||
README.md usr/share/arsse/ |
|||
arsse.php usr/share/arsse/ |
|||
|
|||
config.defaults.php etc/arsse/ |
|||
manual usr/share/doc/arsse/ |
|||
dist/man/* usr/share/man/ |
|||
dist/debian/config.php etc/arsse/ |
|||
dist/debian/dbconfig-common.php usr/share/arsse/ |
|||
debian/bin/arsse usr/bin/ |
|||
debian/nginx etc/arsse/ |
|||
debian/apache etc/arsse/ |
@ -0,0 +1 @@ |
|||
etc/arsse/config.php usr/share/arsse/config.php |
@ -0,0 +1,29 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
. /usr/share/debconf/confmodule |
|||
|
|||
if [ "$1" = "configure" ]; then |
|||
# Set permissions on configuration file |
|||
dpkg-statoverride --list "/etc/arsse/config.php" >/dev/null || dpkg-statoverride --update --add root www-data 640 "/etc/arsse/config.php" |
|||
# Set up dbconfig-common |
|||
if test -f /usr/share/dbconfig-common/dpkg/postinst; then |
|||
. /usr/share/dbconfig-common/dpkg/postinst |
|||
dbc_generate_include_owner="root:www-data" |
|||
dbc_generate_include_perms="0640" |
|||
dbc_generate_include="php:/var/lib/arsse/dbconfig.inc" |
|||
dbc_pgsql_createdb_encoding="UTF8' lc_collate='C" |
|||
dbc_mysql_createdb_encoding="UTF8" |
|||
dbc_dbfile_owner="root:www-data" |
|||
dbc_dbfile_perms="0660" |
|||
dbc_go arsse "$@" |
|||
fi |
|||
fi |
|||
|
|||
# dh_installdeb will replace this with shell code automatically |
|||
# generated by other debhelper scripts. |
|||
|
|||
#DEBHELPER# |
|||
|
|||
exit 0 |
@ -0,0 +1,20 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
if test -f /usr/share/debconf/confmodule; then |
|||
. /usr/share/debconf/confmodule |
|||
fi |
|||
|
|||
# Set up dbconfig-common |
|||
if test -f /usr/share/dbconfig-common/dpkg/postrm; then |
|||
. /usr/share/dbconfig-common/dpkg/postrm |
|||
dbc_go arsse "$@" |
|||
fi |
|||
|
|||
# dh_installdeb will replace this with shell code automatically |
|||
# generated by other debhelper scripts. |
|||
|
|||
#DEBHELPER# |
|||
|
|||
exit 0 |
@ -0,0 +1,16 @@ |
|||
#!/bin/sh |
|||
|
|||
set -e |
|||
|
|||
. /usr/share/debconf/confmodule |
|||
|
|||
# Set up dbconfig-common |
|||
. /usr/share/dbconfig-common/dpkg/prerm |
|||
dbc_go arsse "$@" |
|||
|
|||
# dh_installdeb will replace this with shell code automatically |
|||
# generated by other debhelper scripts. |
|||
|
|||
#DEBHELPER# |
|||
|
|||
exit 0 |
@ -0,0 +1 @@ |
|||
10 |
@ -0,0 +1,15 @@ |
|||
<?php |
|||
/*** |
|||
Please refer to config.defaults.php or the manual at /usr/share/doc/arsse/ |
|||
for possible configuration parameters. |
|||
|
|||
The last line includes database auto-configuration information which |
|||
Debian may have created during installation; any database-related |
|||
configuration defined in this file will override anything defined in the |
|||
included file. |
|||
***/ |
|||
|
|||
return [ |
|||
'dbAutoUpdate' => true, |
|||
] |
|||
+ (@include "/usr/share/arsse/dbconfig-common.php"); |
@ -0,0 +1,32 @@ |
|||
Source: arsse |
|||
Maintainer: J. King <jking@jkingweb.ca> |
|||
Section: contrib/net |
|||
Priority: optional |
|||
Standards-Version: 4.5.1 |
|||
Homepage: https://thearsse.com/ |
|||
Vcs-Browser: https://code.mensbeam.com/MensBeam/arsse/ |
|||
Vcs-Git: https://code.mensbeam.com/MensBeam/arsse/ |
|||
Build-Depends: debhelper |
|||
|
|||
Package: arsse |
|||
Architecture: all |
|||
Section: contrib/net |
|||
Priority: optional |
|||
Homepage: https://thearsse.com/ |
|||
Description: Multi-protocol RSS/Atom newsfeed synchronization server |
|||
The Arsse bridges the gap between multiple existing newsfeed aggregator |
|||
client protocols such as Tiny Tiny RSS, Nextcloud News and Miniflux, |
|||
allowing you to use compatible clients for many protocols with a single |
|||
server. |
|||
Depends: ${misc:Depends}, |
|||
dbconfig-sqlite3 | dbconfig-pgsql | dbconfig-mysql | dbconfig-no-thanks, |
|||
php (>= 7.3.0), |
|||
php-cli, |
|||
php-intl, |
|||
php-json, |
|||
php-xml, |
|||
php-sqlite3 | php-pgsql | php-mysql |
|||
Recommends: nginx | apache2, |
|||
php-fpm, |
|||
php-curl, |
|||
ca-certificates |
@ -0,0 +1,34 @@ |
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ |
|||
Upstream-Name: arsse |
|||
Upstream-Contact: J. King <jking@jkingweb.ca> |
|||
Source: https://code.mensbeam.com/MensBeam/arsse/ |
|||
License: Expat |
|||
|
|||
Files: * |
|||
Copyright: 2017 J. King <jking@jkingweb.ca> |
|||
2017 Dustin Wilson <dustin@dustinwilson.com> |
|||
License: Expat |
|||
|
|||
License: Expat |
|||
Copyright (c) 2017 J. King, Dustin Wilson |
|||
. |
|||
Permission is hereby granted, free of charge, to any person |
|||
obtaining a copy of this software and associated documentation |
|||
files (the "Software"), to deal in the Software without |
|||
restriction, including without limitation the rights to use, |
|||
copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the |
|||
Software is furnished to do so, subject to the following |
|||
conditions: |
|||
. |
|||
The above copyright notice and this permission notice shall be |
|||
included in all copies or substantial portions of the Software. |
|||
. |
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
|||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
|||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
|||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
|||
OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,44 @@ |
|||
<?php |
|||
|
|||
# This script transforms Debian's dbconfig-common PHP-format include files |
|||
# into a form usable by The Arsse. This is necessary because The Arsse |
|||
# supports defining configuration parameters for all supported database types |
|||
# at once, using separate keys for the different types |
|||
|
|||
$dbconfpath = "/var/lib/arsse/dbconfig.inc"; // path defined in postinst script |
|||
|
|||
if (file_exists($dbconfpath)) { |
|||
require_once "/var/lib/arsse/dbconfig.inc"; |
|||
$dbtype = $dbtype ?? ""; |
|||
// the returned configuration depends on the $dbtype |
|||
if ($dbtype === "sqlite3") { |
|||
$conf = ['dbDriver' => "sqlite3"]; |
|||
if (strlen((string) $basepath) && strlen((string) $dbname)) { |
|||
$conf['dbSQLite3File'] = "$basepath/$dbname"; |
|||
} |
|||
} elseif ($dbtype === "pgsql") { |
|||
$conf = [ |
|||
'dbDriver' => "postgresql", |
|||
'dbPostgreSQLHost' => $dbserver ?? "", |
|||
'dbPostgreSQLUser' => $dbuser ?? "arsse", |
|||
'dbPostgreSQLPass' => $dbpass ?? "", |
|||
'dbPostgreSQLPort' => (int) $dbport ?: 5432, |
|||
'dbPostgreSQLDb' => $dbname ?? "arsse", |
|||
]; |
|||
} elseif ($dbtype === "mysql") { |
|||
$conf = [ |
|||
'dbDriver' => "mysql", |
|||
'dbMySQLHost' => $dbserver ?? "", |
|||
'dbMySQLUser' => $dbuser ?? "arsse", |
|||
'dbMySQLPass' => $dbpass ?? "", |
|||
'dbMySQLPort' => (int) $dbport ?: 3306, |
|||
'dbMySQLDb' => $dbname ?? "arsse", |
|||
]; |
|||
} else { |
|||
throw new \Exception("Debian dbconfig-common configuration file $dbconfpath is invalid"); |
|||
} |
|||
return $conf; |
|||
} else { |
|||
// if no configuration file exists simply return an empty array |
|||
return []; |
|||
} |
@ -0,0 +1,6 @@ |
|||
# We make reference to "Tiny Tiny RSS" |
|||
spelling-error-in-description Tiny Tiny (duplicate word) Tiny |
|||
# The manual for DrUUID (a dependency) includes a harmless "up" link |
|||
privacy-breach-generic usr/share/arsse/vendor/jkingweb/druuid/documentation/manual.html [<link rel="up" href="http://jkingweb.ca/code/">] (http://jkingweb.ca/code/) |
|||
# We only ask dbconfig-common questions, which don't seem to require templates |
|||
no-debconf-templates |
@ -0,0 +1,40 @@ |
|||
#! /bin/bash -e |
|||
|
|||
### |
|||
# This script is fed to pbuilder to build Debian packages. The base tarball |
|||
# should be created with a command similar to the following: |
|||
# |
|||
# sudo pbuilder create --basetgz pbuilder-arsse.tgz --mirror http://ftp.ca.debian.org/debian/ --extrapackages "debhelper devscripts lintian" |
|||
# |
|||
# Thereafter pbuilder can be used to build packages with this command: |
|||
# |
|||
# sudo pbuilder execute --basetgz pbuilder-arsse.tgz --bindmounts `basedir "/path/to/release/tarball"` -- pbuilder.sh "/path/to/release/tarball" |
|||
# |
|||
# This somewhat roundabout procedure is used because the pbuilder debuild |
|||
# command does not seem to work in Arch Linux, nor does pdebuild. Doing |
|||
# as much as possible within the chroot itself works around these problems. |
|||
### |
|||
|
|||
# create a temporary directory |
|||
tmp=`mktemp -d` |
|||
|
|||
# define various variables |
|||
here=`dirname "$1"` |
|||
tarball=`basename "$1"` |
|||
version=`echo "$tarball" | grep -oP '\d+(?:\.\d+)*' | head -1` |
|||
out="$here/debian" |
|||
in="$tmp/arsse-$version" |
|||
|
|||
# create necessary directories |
|||
mkdir -p "$in" "$out" |
|||
# extract the release tarball |
|||
tar -C "$in" -xf "$1" --strip-components=1 |
|||
# repackage the release tarball into a Debian "orig" tarball |
|||
tar -C "$tmp" -czf "$tmp/arsse_$version.orig.tar.gz" "arsse-$version" |
|||
# copy the "dist/debian" directory down the tree where Debian expects it |
|||
cp -r "$in/dist/debian" "$in/debian" |
|||
# build the package |
|||
cd "$in" |
|||
debuild -us -uc |
|||
# move the resultant files to their final destination |
|||
find "$tmp" -maxdepth 1 -type f -exec mv '{}' "$out" \; |
@ -0,0 +1,26 @@ |
|||
#!/usr/bin/make -f |
|||
|
|||
DH_VERBOSE = 1 |
|||
|
|||
%: |
|||
dh $@ |
|||
|
|||
execute_before_dh_install: |
|||
# Adapt the systemd service for Debian: this involves using only the "arsse-fetch" unit (renamed to "arsse"), removing the "PartOf" directive, and changing the user and group to "www-data" |
|||
cp dist/systemd/arsse-fetch.service debian/arsse.service |
|||
sed -i -se 's/^PartOf=.*//' debian/arsse.service |
|||
sed -i -se 's/^\(User\|Group\)=.*/\1=www-data/' debian/arsse.service |
|||
# Adapt the init script for Debian: this involves changing the user and group to "www-data" |
|||
cp dist/init.sh debian/arsse.init |
|||
sed -i -se 's/^\([ \t]*chown\) arsse:arsse /\1 www-data:www-data /' debian/arsse.init |
|||
# Change the user and group references in tmpfiles |
|||
cp dist/tmpfiles.conf debian/arsse.tmpfiles |
|||
sed -i -se 's/ arsse / www-data /' debian/arsse.tmpfiles |
|||
sed -i -se 's/ arsse / www-data /' debian/arsse.tmpfiles |
|||
# Change the user reference in the executable file |
|||
mkdir -p debian/bin |
|||
cp dist/arsse debian/bin/arsse |
|||
sed -i -se 's/posix_getpwnam("arsse"/posix_getpwnam("www-data"/' debian/bin/arsse |
|||
# Change PHP-FPM socket paths |
|||
cp -r dist/apache dist/nginx debian |
|||
sed -i -se 's/arsse\.sock/php-fpm.sock/' debian/apache/arsse.conf debian/nginx/arsse.conf |
@ -0,0 +1 @@ |
|||
3.0 (quilt) |
@ -0,0 +1,2 @@ |
|||
# Development environment is slightly out of date |
|||
newer-standards-version |
@ -0,0 +1,78 @@ |
|||
#!/bin/sh |
|||
|
|||
### BEGIN INIT INFO |
|||
# Provides: arsse |
|||
# Required-Start: $local_fs $network |
|||
# Required-Stop: $local_fs postgresql mysql |
|||
# Should-Start: postgresql mysql |
|||
# Should-Stop: postgresql mysql |
|||
# Default-Start: 2 3 4 5 |
|||
# Default-Stop: 0 1 6 |
|||
# Short-Description: The Advanced RSS Environment |
|||
# Description: The Arsse is a multi-protocol Web newsfeed synchronization service |
|||
### END INIT INFO |
|||
|
|||
# This script is designed for Debian; some adaptation will be required for other systems |
|||
|
|||
PATH=/usr/sbin/:/usr/bin:/sbin:/bin |
|||
NAME=arsse |
|||
DESC="newsfeed synchronization server" |
|||
PIDFILE=/run/arsse.pid |
|||
DAEMON=/usr/bin/$NAME |
|||
|
|||
. /lib/init/vars.sh |
|||
. /lib/lsb/init-functions |
|||
|
|||
arsse_start() { |
|||
touch "$PIDFILE" |
|||
chown arsse:arsse "$PIDFILE" |
|||
$DAEMON daemon --fork="$PIDFILE" || return 2 |
|||
} |
|||
|
|||
arsse_stop() { |
|||
killproc -p "$PIDFILE" "$DAEMON" |
|||
} |
|||
|
|||
arsse_reload() { |
|||
killproc -p "$PIDFILE" "$DAEMON" HUP |
|||
} |
|||
|
|||
case "$1" in |
|||
start) |
|||
log_daemon_msg "Starting $DESC" "$NAME" |
|||
if pidofproc -p $PIDFILE "$DAEMON" > /dev/null 2>&1 ; then |
|||
return 1 |
|||
fi |
|||
arsse_start |
|||
;; |
|||
stop) |
|||
log_daemon_msg "Stopping $DESC" "$NAME" |
|||
arsse_stop |
|||
;; |
|||
restart) |
|||
log_daemon_msg "Restarting $DESC" "$NAME" |
|||
if pidofproc -p $PIDFILE "$DAEMON" > /dev/null 2>&1 ; then |
|||
arsse_stop |
|||
fi |
|||
arsse_start |
|||
;; |
|||
try-restart) |
|||
if pidofproc -p $PIDFILE "$DAEMON" > /dev/null 2>&1 ; then |
|||
log_daemon_msg "Restarting $DESC" "$NAME" |
|||
arsse_stop |
|||
arsse_start |
|||
fi |
|||
;; |
|||
reload|force-reload) |
|||
log_daemon_msg "Reloading $DESC" "$NAME" |
|||
arsse_reload |
|||
;; |
|||
status) |
|||
status_of_proc -p $PIDFILE $DAEMON $NAME |
|||
exit $? |
|||
;; |
|||
*) |
|||
echo "Usage: $0 {start|stop|restart|try-restart|reload|status}" >&2 |
|||
exit 3 |
|||
;; |
|||
esac |
@ -0,0 +1,342 @@ |
|||
.Dd October 27, 2023 |
|||
.Dt ARSSE 1 |
|||
.Os "The Arsse" 0.10.4 |
|||
. |
|||
. |
|||
.Sh NAME |
|||
.Nm arsse |
|||
.Nd manage an instance of The Advanced RSS Environment (The Arsse) |
|||
. |
|||
. |
|||
.Sh SYNOPSIS |
|||
.Nm "arsse user" |
|||
.Op Nm list |
|||
.Nm "arsse user add" |
|||
.Ar username |
|||
.Op Ar password |
|||
.Op Fl Fl admin |
|||
.Nm "arsse user remove" |
|||
.Ar username |
|||
.Nm "arsse user show" |
|||
.Ar username |
|||
.Nm "arsse user set" |
|||
.Ar username |
|||
.Ar property |
|||
.Ar value |
|||
.Nm "arsse user unset" |
|||
.Ar username |
|||
.Ar property |
|||
.Nm "arsse user set\-pass" |
|||
.Ar username |
|||
.Op Ar password |
|||
.Op Fl Fl fever |
|||
.Nm "arsse user unset\-pass" |
|||
.Ar username |
|||
.Op Fl Fl fever |
|||
.Nm "arsse user auth" |
|||
.Ar username |
|||
.Op Ar password |
|||
.Op Fl Fl fever |
|||
.Nm "arsse token list" |
|||
.Ar username |
|||
.Nm "arsse token create" |
|||
.Ar username |
|||
.Op Ar label |
|||
.Nm "arsse token revoke" |
|||
.Ar username |
|||
.Op Ar token |
|||
.Nm "arsse import" |
|||
.Ar username |
|||
.Op Ar file |
|||
.Op Fl f | Fl Fl flat |
|||
.Op Fl r | Fl Fl replace |
|||
.Nm "arsse export" |
|||
.Ar username |
|||
.Op Ar file |
|||
.Op Fl f | Fl Fl flat |
|||
.Nm "arsse daemon" |
|||
.Op Fl Fl fork Ns = Ns Ar pidfile |
|||
.Nm "arsse feed refresh\-all" |
|||
.Nm "arsse feed refresh" |
|||
.Ar n |
|||
.Nm "arsse conf save\-defaults" |
|||
.Nm "arsse" |
|||
.Fl Fl version | Fl h | Fl Fl help |
|||
. |
|||
. |
|||
.Sh DESCRIPTION |
|||
.Nm |
|||
allows a sufficiently privileged user to perform various administrative operations related to The Arsse, including: |
|||
.Pp |
|||
.Bl -bullet -compact |
|||
.It |
|||
Adding and removing users and managing their metadata |
|||
.It |
|||
Managing passwords and authentication tokens |
|||
.It |
|||
Importing and exporting OPML newsfeed-lists |
|||
.El |
|||
.Pp |
|||
These are documented in the next section |
|||
.Sx COMMANDS Ns No . |
|||
Further, seldom-used commands are documented in the subsequent section |
|||
.Sx ADDITIONAL COMMANDS Ns No . |
|||
. |
|||
. |
|||
.Sh COMMANDS |
|||
. |
|||
.Ss Managing users and metadata |
|||
.Bl -tag |
|||
.It Nm "user" Op Nm list |
|||
Displays a simple list of user names with one entry per line |
|||
.It Nm "user add" Ar username Oo Ar password Oc Oo Fl Fl admin Oc |
|||
Adds a new user to the database with the specified username and password. |
|||
If |
|||
.Ar password |
|||
is omitted a random password will be generated and printed. |
|||
.Pp |
|||
The |
|||
.Fl Fl admin |
|||
flag may be used to mark the user as an administrator. |
|||
This has no meaning within the context of The Arsse as a whole, |
|||
but it is used control access to certain features in the Miniflux and Nextcloud News protocols. |
|||
.It Nm "user remove" Ar username |
|||
Immediately removes a user from the database. |
|||
All associated data (folders, subscriptions, etc.) are also removed. |
|||
.It Nm "user show" Ar username |
|||
Displays a table of metadata properties and their assigned values for |
|||
.Ar username Ns No . |
|||
These properties are primarily used by the Miniflux protocol. |
|||
Consult the section |
|||
.Sx USER METADATA |
|||
for details. |
|||
.It Nm "user set" Ar username Ar property Ar value |
|||
Sets a metadata property for a user. |
|||
These properties are primarily used by the Miniflux protocol. |
|||
Consult the section |
|||
.Sx USER METADATA |
|||
for details. |
|||
.It Nm "user unset" Ar username Ar property |
|||
Clears a metadata property for a user. |
|||
The property is thereafter set to its default value, which is protocol-dependent. |
|||
.El |
|||
. |
|||
.Ss Managing passwords and authentication tokens |
|||
.Bl -tag |
|||
.It Nm "user set\-pass" Ar username Oo Ar password Oc Oo Fl Fl fever Oc |
|||
Changes a user's password to the specified value. |
|||
If no password is specified, a random password will be generated and printed. |
|||
.Pp |
|||
The |
|||
.Fl Fl fever |
|||
option sets a user's Fever protocol password instead of their general password. |
|||
As the Fever protocol requires that passwords be stored insecurely, |
|||
users do not have Fever passwords by default, and logging in to the Fever protocol is disabled until a suitable password is set. |
|||
It is highly recommended that a user's Fever password be different from their general password. |
|||
.It Nm "user unset\-pass" Ar username Oo Fl Fl fever Oc |
|||
Unsets a user's password, effectively disabling their account. |
|||
As with password setting, the |
|||
.Fl Fl fever |
|||
option may be used to operate on a user's Fever password instead of their general password. |
|||
.It Nm "user auth" Ar username Ar password Oo Fl Fl fever Oc |
|||
Tests logging a user in. |
|||
This only checks that the user's password is correctly recognized; |
|||
it has no side effects. |
|||
.Pp |
|||
The |
|||
.Fl Fl fever |
|||
option may be used to test the user's Fever protocol password, if any. |
|||
.It Nm "token list" Ar username |
|||
Displays a user's authentication tokens in a simple tabular format. |
|||
These tokens act as an alternative means of authentication for the Miniflux protocol and may be required by some clients. |
|||
They do not expire. |
|||
.It Nm "token create" Ar username Oo Ar label Oc |
|||
Creates a new random login token and prints it. |
|||
These tokens act as an alternative means of authentication for the Miniflux protocol and may be required by some clients. |
|||
An optional |
|||
.Ar label |
|||
may be specified to give the token a meaningful name. |
|||
.It Nm "token revoke" Ar username Oo Ar token Oc |
|||
Deletes the specified |
|||
.Ar token |
|||
from the database. |
|||
The token itself must be supplied, not its label. |
|||
If it is omitted all tokens for |
|||
.Ar username |
|||
are revoked. |
|||
.El |
|||
. |
|||
.Ss Importing and exporting data |
|||
.Bl -tag |
|||
.It Nm "import" Ar username Oo Ar file Oc Oo Fl r | Fl Fl replace Oc Oo Fl f | Fl Fl flat Oc |
|||
Imports the newsfeeds, folders, and tags found in the OPML formatted |
|||
.Ar file |
|||
into the account of the specified user. |
|||
If no file is specified, data is instead read from standard input. |
|||
Import operations are atomic: |
|||
if any of the newsfeeds listed in the input cannot be retrieved, the entire import operation will fail. |
|||
.Pp |
|||
The |
|||
.Fl Fl replace |
|||
(or |
|||
.Fl r Ns |
|||
) option interprets the OPML file as the list of |
|||
.Em all |
|||
desired newsfeeds, folders and tags, performing any deletion or moving of existing entries which do not appear in the flle. |
|||
If this option is not specified, the file is assumed to list desired |
|||
.Em additions only Ns No . |
|||
.Pp |
|||
The |
|||
.Fl Fl flat |
|||
(or |
|||
.Fl f Ns |
|||
) option can be used to ignore any folder structures in the file, importing any newsfeeds directly into the root folder. |
|||
Combining this with the |
|||
.Fl Fl replace |
|||
option is possible. |
|||
.It Nm "export" Ar username Oo Ar file Oc Oo Fl f | Fl Fl flat Oc |
|||
Exports a user's newsfeeds, folders, and tags to the OPML file specified by |
|||
.Ar file Ns |
|||
, or standard output if no file is specified. |
|||
Note that due to a limitation of the OPML format, any commas present in tag names will not be retained in the export. |
|||
.Pp |
|||
The |
|||
.Fl Fl flat |
|||
(or |
|||
.Fl f Ns |
|||
) option can be used to omit folders from the export. |
|||
Some OPML implementations may not support folders, or arbitrary nesting; |
|||
this option may be used when planning to import into such software. |
|||
.El |
|||
. |
|||
. |
|||
.Sh ADDITIONAL COMMANDS |
|||
.Bl -tag |
|||
.It Nm "daemon" Oo Fl Fl fork Ns = Ns Ar pidfile Oc |
|||
Starts the newsfeed fetching service. |
|||
Normally this command is only invoked by systemd. |
|||
.Pp |
|||
The |
|||
.Fl Fl fork |
|||
option executes an "old-style" fork-then-terminate daemon rather than a "new-style" non-terminating daemon. |
|||
This option should only be employed if using a System V-style init daemon on POSIX systems; |
|||
normally systemd is used. When using this option the daemon will write its process identifier to |
|||
.Ar pidfile |
|||
after forking. |
|||
.It Nm "feed refresh\-all" |
|||
Performs a one-time fetch of all stale feeds. |
|||
This command can be used as the basis of a |
|||
.Nm cron |
|||
job to keep newsfeeds up-to-date. |
|||
.It Nm "feed refresh" Ar n |
|||
Performs a one-time fetch of the feed (not subscription) identified by integer |
|||
.Ar n Ns No . |
|||
This is used internally by the fetching service and should not normally be needed. |
|||
.It Nm "conf save\-defaults" Oo Ar file Oc |
|||
Prints default configuration parameters to standard output, or to |
|||
.Ar file |
|||
if specified. |
|||
Each parameter is annotated with a short description of its purpose and usage. |
|||
.El |
|||
. |
|||
. |
|||
.Sh USER METADATA |
|||
User metadata are primarily used by the Miniflux protocol, |
|||
and most properties have identical or similar names to those used by Miniflux. |
|||
Properties may also affect other protocols, or conversely may have no effect even when using the Miniflux protocol; |
|||
this is noted below when appropriate. |
|||
.Pp |
|||
Booleans accept any of the values |
|||
.Ar true Ns No / Ns Ar false Ns No , |
|||
.Ar 1 Ns No / Ns Ar 0 Ns No , |
|||
.Ar yes Ns No / Ns Ar no Ns No , |
|||
or |
|||
.Ar on Ns No / Ns Ar off Ns No . |
|||
.Pp |
|||
The following metadata properties exist for each user: |
|||
.Pp |
|||
.Bl -tag |
|||
.It Cm num No (integer) |
|||
The numeric identifier of the user. |
|||
This is assigned at user creation and is read-only. |
|||
.It Cm admin No (boolean) |
|||
Boolean. Whether the user is an administrator. |
|||
Administrators may manage other users via the Miniflux protocol, |
|||
and also may trigger feed updates manually via the Nextcloud News protocol. |
|||
.It Cm lang No (string) |
|||
The preferred language of the user as a BCP 47 language tag, for example "en-ca". |
|||
Note that since The Arsse currently only includes English text it is not used by The Arsse itself, |
|||
but clients may use this metadatum in protocols which expose it. |
|||
.It Cm tz No (string) |
|||
The time zone of the user as a Time Zone Database identifier, for example "America/Los_Angeles". |
|||
.It Cm root_folder_name No (string) |
|||
The name of the root folder, in protocols which allow it to be renamed. |
|||
.It Cm sort_asc No (boolean) |
|||
Whether the user prefers ascending sort order for articles. |
|||
Descending order is usually the default, |
|||
but explicitly setting this property false will also make a preference for descending order explicit. |
|||
.It Cm theme No (string) |
|||
The user's preferred user-interface theme. |
|||
This is not used by The Arsse itself, but clients may use this metadatum in protocols which expose it. |
|||
.It Cm page_size No (integer) |
|||
The user's preferred page size when listing articles. |
|||
This is not used by The Arsse itself, but clients may use this metadatum in protocols which expose it. |
|||
.It Cm shortcuts No (boolean) |
|||
Whether to enable keyboard shortcuts. |
|||
This is not used by The Arsse itself, but clients may use this metadatum in protocols which expose it. |
|||
.It Cm gestures No (boolean) |
|||
Whether to enable touch gestures. |
|||
This is not used by The Arsse itself, but clients may use this metadatum in protocols which expose it. |
|||
.It Cm reading_time No (boolean) |
|||
Whether to calculate and display the estimated reading time for articles. |
|||
Currently The Arsse does not calculate reading time, so changing this will likely have no effect. |
|||
.It Cm stylesheet No (string) |
|||
A user stylesheet in CSS format. |
|||
This is not used by The Arsse itself, but clients may use this metadatum in protocols which expose it. |
|||
.El |
|||
. |
|||
. |
|||
.Sh EXAMPLES |
|||
.Bl -tag |
|||
.It Add an administrator to the database with an explicit password: |
|||
.Bd -literal |
|||
$ arsse user add \-\-admin alice "Curiouser and curiouser!" |
|||
.Ed |
|||
.It Add a regular user to the database with a random password: |
|||
.Bd -literal |
|||
$ arsse user add "Bob the Builder" |
|||
bLS!$_UUZ!iN2i_!^IC6 |
|||
.Ed |
|||
.It Make Bob the Builder an administrator: |
|||
.Bd -literal |
|||
$ arsse user set "Bob the Builder" admin true |
|||
.Ed |
|||
.It Disable Alice's account by clearing her password: |
|||
.Bd -literal |
|||
$ arsse user unset\-pass alice |
|||
.Ed |
|||
.It Move all of Foobar's newsfeeds to the root folder: |
|||
.Bd -literal |
|||
$ arsse export foobar \-f | arsse import \-r foobar |
|||
.Ed |
|||
.It Fail to log in as Alice: |
|||
.Bd -literal |
|||
$ arsse user auth alice "Oh, dear!" |
|||
Authentication failed |
|||
$ echo $? |
|||
1 |
|||
.Ed |
|||
.El |
|||
. |
|||
. |
|||
.Sh REPORTING BUGS |
|||
Any bugs found in The Arsse may be reported on the Web via the |
|||
.Lk https://code.mensbeam.com/MensBeam/arsse "MensBeam code repository" |
|||
or may be directed to the principal authors by e-mail: |
|||
.Pp |
|||
.Bl -bullet -compact |
|||
.It |
|||
.Lk https://jkingweb.ca/ "J. King" |
|||
.It |
|||
.Lk https://dustinwilson.com/ "Dustin Wilson" |
|||
.El |
@ -1,51 +0,0 @@ |
|||
server { |
|||
server_name news.example.com; |
|||
listen 80; # adding HTTPS configuration is highly recommended |
|||
# redirect to HTTPS, if desired |
|||
#if ($https != "on") {rewrite ^ https://$host$request_uri;} |
|||
# the userPreAuth setting should be enabled if the Web server is handling authentication |
|||
#auth_basic "Advanced RSS Environment"; |
|||
root /usr/share/arsse/www; |
|||
index index.html; |
|||
|
|||
location / { |
|||
try_files $uri $uri/ =404; |
|||
} |
|||
|
|||
location @arsse_auth { |
|||
# the userPreAuth setting should be enabled if the Web server is handling authentication |
|||
#auth_basic "Advanced RSS Environment"; |
|||
include /usr/share/arsse/dist/nginx-fcgi.conf; |
|||
} |
|||
|
|||
location @arsse_no_auth { |
|||
auth_basic off; |
|||
include /usr/share/arsse/dist/nginx-fcgi.conf; |
|||
} |
|||
|
|||
# NextCloud News protocol |
|||
location /index.php/apps/news/api { |
|||
try_files $uri @arsse_auth; |
|||
|
|||
location ~ ^/index\.php/apps/news/api/?$ { |
|||
try_files $uri @arsse_no_auth; |
|||
} |
|||
} |
|||
|
|||
# Tiny Tiny RSS protocol |
|||
location /tt-rss/api { |
|||
try_files $uri @arsse_no_auth; |
|||
} |
|||
|
|||
# Tiny Tiny RSS feed icons |
|||
location /tt-rss/feed-icons/ { |
|||
try_files $uri @arsse_no_auth; |
|||
} |
|||
|
|||
# Tiny Tiny RSS special-feed icons |
|||
location /tt-rss/images/ { |
|||
auth_basic off; |
|||
root /usr/share/arsse/www; |
|||
try_files $uri =404; |
|||
} |
|||
} |
@ -1,13 +1,15 @@ |
|||
fastcgi_pass php; # PHP is assumed to already be configured for FastCGI operation |
|||
fastcgi_pass_header Authorization; # required if the Arsse is to perform its own HTTP authentication |
|||
fastcgi_pass_request_body on; |
|||
fastcgi_pass_request_headers on; |
|||
fastcgi_intercept_errors off; |
|||
fastcgi_buffering off; |
|||
fastcgi_param SCRIPT_FILENAME /usr/share/arsse/arsse.php; |
|||
fastcgi_param REQUEST_METHOD $request_method; |
|||
fastcgi_param CONTENT_TYPE $content_type; |
|||
fastcgi_param CONTENT_LENGTH $content_length; |
|||
fastcgi_param REQUEST_URI $uri; |
|||
fastcgi_param QUERY_STRING $query_string; |
|||
fastcgi_param HTTPS $https if_not_empty; |
|||
fastcgi_param REMOTE_USER $remote_user; |
|||
|
|||
fastcgi_pass unix:/var/run/php/arsse.sock; |
|||
fastcgi_param SCRIPT_FILENAME /usr/share/arsse/arsse.php; |
@ -0,0 +1,49 @@ |
|||
# Any provided static files |
|||
location / { |
|||
try_files $uri $uri/ =404; |
|||
} |
|||
|
|||
# Nextcloud News protocol |
|||
location /index.php/apps/news/api { |
|||
try_files $uri @arsse; |
|||
|
|||
location ~ ^/index\.php/apps/news/api/?$ { |
|||
try_files $uri @arsse_public; |
|||
} |
|||
} |
|||
|
|||
# Tiny Tiny RSS protocol |
|||
location /tt-rss/api { |
|||
try_files $uri @arsse; |
|||
} |
|||
|
|||
# Tiny Tiny RSS feed icons |
|||
location /tt-rss/feed-icons/ { |
|||
try_files $uri @arsse; |
|||
} |
|||
|
|||
# Tiny Tiny RSS special-feed icons; these are static files |
|||
location /tt-rss/images/ { |
|||
try_files $uri =404; |
|||
} |
|||
|
|||
# Fever protocol |
|||
location /fever/ { |
|||
try_files $uri @arsse; |
|||
} |
|||
|
|||
# Miniflux protocol |
|||
location /v1/ { |
|||
# If put behind HTTP authentication token login will not be possible |
|||
try_files $uri @arsse; |
|||
} |
|||
|
|||
# Miniflux version number |
|||
location /version { |
|||
try_files $uri @arsse_public; |
|||
} |
|||
|
|||
# Miniflux "health check" |
|||
location /healthcheck { |
|||
try_files $uri @arsse_public; |
|||
} |
@ -0,0 +1,13 @@ |
|||
root /usr/share/arsse/www; |
|||
|
|||
location @arsse { |
|||
# HTTP authentication may be enabled for this location, though this may impact some features |
|||
include /etc/arsse/nginx/arsse-fcgi.conf; |
|||
} |
|||
|
|||
location @arsse_public { |
|||
# HTTP authentication should not be enabled for this location |
|||
include /etc/arsse/nginx/arsse-fcgi.conf; |
|||
} |
|||
|
|||
include /etc/arsse/nginx/arsse-loc.conf; |
@ -0,0 +1,13 @@ |
|||
server { |
|||
server_name news.example.com; |
|||
listen 80; |
|||
listen [::]:80; |
|||
listen 443 ssl http2; |
|||
listen [::]:443 ssl http2; |
|||
|
|||
ssl_certificate /etc/letsencrypt/live/news.example.com/fullchain.pem; |
|||
ssl_certificate_key /etc/letsencrypt/live/news.example.com/privkey.pem; |
|||
ssl_trusted_certificate /etc/letsencrypt/live/news.example.com/chain.pem; |
|||
|
|||
include /etc/arsse/nginx/arsse.conf; |
|||
} |
@ -0,0 +1,11 @@ |
|||
[arsse] |
|||
user = arsse |
|||
group = arsse |
|||
listen = /var/run/php/arsse.sock |
|||
listen.owner = arsse |
|||
listen.group = www-data |
|||
pm = dynamic |
|||
pm.max_children = 5 |
|||
pm.start_servers = 2 |
|||
pm.min_spare_servers = 1 |
|||
pm.max_spare_servers = 3 |
@ -0,0 +1,36 @@ |
|||
[Unit] |
|||
Description=The Arsse newsfeed fetching service |
|||
Documentation=https://thearsse.com/manual/ |
|||
PartOf=arsse.service |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
|
|||
[Service] |
|||
User=arsse |
|||
Group=arsse |
|||
Type=simple |
|||
WorkingDirectory=/usr/share/arsse |
|||
ExecStart=/usr/bin/arsse daemon |
|||
|
|||
ProtectProc=invisible |
|||
NoNewPrivileges=true |
|||
ProtectSystem=full |
|||
ProtectHome=true |
|||
StateDirectory=arsse |
|||
ConfigurationDirectory=arsse |
|||
PrivateTmp=true |
|||
PrivateDevices=true |
|||
RestrictSUIDSGID=true |
|||
StandardOutput=journal |
|||
StandardError=journal |
|||
SyslogIdentifier=arsse |
|||
Restart=on-failure |
|||
RestartPreventStatus= |
|||
|
|||
# These directives can be used for extra security, but are disabled for now for compatibility |
|||
|
|||
#ReadOnlyPaths=/ |
|||
#ReadWriePaths=/var/lib/arsse |
|||
#NoExecPaths=/ |
|||
#ExecPaths=/usr/bin/php |
@ -0,0 +1,14 @@ |
|||
[Unit] |
|||
Description=The Arsse newsfeed management service |
|||
Documentation=https://thearsse.com/manual/ |
|||
Requires=arsse-fetch.service |
|||
BindsTo=php-fpm.service |
|||
After=php-fpm.service |
|||
|
|||
[Install] |
|||
WantedBy=multi-user.target |
|||
|
|||
[Service] |
|||
Type=oneshot |
|||
RemainAfterExit=true |
|||
ExecStart=/usr/bin/true |
@ -0,0 +1 @@ |
|||
u arsse - "The Arsse" /var/lib/arsse - |
@ -0,0 +1,5 @@ |
|||
z /usr/bin/arsse 0755 root arsse - - |
|||
z /etc/arsse/config.php 0640 root arsse - - |
|||
L /usr/share/arsse/config.php - root arsse - /etc/arsse/config.php |
|||
d /var/lib/arsse 0750 arsse arsse - - |
|||
L /usr/share/arsse/arsse - root arsse - /usr/share/arsse/arsse.php |
@ -0,0 +1,15 @@ |
|||
{ |
|||
"title": "The Advanced RSS Environment", |
|||
"tagline": "The clean & modern RSS server that doesn't give you any crap.", |
|||
"author": "J. King", |
|||
"languages": { |
|||
"en": "English" |
|||
}, |
|||
"themes_directory": "docs/theme", |
|||
"html": { |
|||
"theme": "arsse", |
|||
"float": false, |
|||
"toggle_code": false, |
|||
"search": false |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
The Advanced RSS Environment (affectionately called "The Arsse") is a news aggregator server which implements multiple synchronization protocols. Unlike most other aggregator servers, The Arsse does not include a Web front-end (though one is planned as a separate project), and it relies on [existing protocols](Supported_Protocols) to maximize compatibility with [existing clients](Compatible_Clients). Supported protocols are: |
|||
|
|||
- Miniflux |
|||
- Nextcloud News |
|||
- Tiny Tiny RSS |
|||
- Fever |
|||
|
|||
The primary goal of The Arsse is to bridge the many isolated ecosystems of client software for the various news synchronization protocols currently in existence. We want people to be able to use the best client software for whatever operating system they use, regardless of the protocols the client supports. |
|||
|
|||
Though The Arsse currently supports only a few protocols, many more are within scope for inclusion, as long as the protocol is not specific to a single service and has clients available. |
|||
|
|||
At present the software should be considered in an "alpha" state: many features one would expect from other similar software have yet to be implemented. Areas of future work include: |
|||
|
|||
- Providing more sync protocols (Google Reader, others) |
|||
- Better packaging and configuration samples |
@ -0,0 +1,71 @@ |
|||
[TOC] |
|||
|
|||
# Downloading The Arsse |
|||
|
|||
Since version 0.9.2 The Arsse is available from the [Arch User Repository](https://aur.archlinux.org/) as packages `arsse` and `arsse-git`. The latter should normally only be used to test bug fixes. |
|||
|
|||
Generic release tarballs may also be downloaded [from our Web site](https://thearsse.com), and the `PKGBUILD` file (found under `arsse/dist/arch/`) can then be extracted alongside the tarball and used to build the `arsse` package. Installing directly from the generic release tarball without producing an Arch package is not recommended as the package-building process performs various adjustments to handle Arch peculiarities. |
|||
|
|||
# Installation |
|||
|
|||
For illustrative purposes, this document assumes the `yay` [AUR helper](https://wiki.archlinux.org/title/AUR_helpers) will be used to download, build, and install The Arsse. This section summarises the steps necessary to configure and use The Arsse after installtion: |
|||
|
|||
```sh |
|||
# Install the package |
|||
sudo yay -S arsse |
|||
# Enable the necessary PHP extensions; curl is optional but recommended; pdo_sqlite may be used instead of sqlite3, but this is not recommended |
|||
sudo sed -i -e 's/^;\(extension=\(curl\|iconv\|intl\|sqlite3\)\)$/\1/' /etc/php/php.ini |
|||
# Enable and start the necessary systemd units |
|||
sudo systemctl enable php-fpm arsse |
|||
sudo systemctl restart php-fpm arsse |
|||
``` |
|||
|
|||
Note that the above is the most concise process, not necessarily the recommended one. In particular [it is recommended](https://wiki.archlinux.org/title/PHP#Extensions) to use `/etc/php/conf.d/` to enable PHP extensions rather than editing `php.ini` as done above. |
|||
|
|||
# Web server configuration |
|||
|
|||
Sample configuration for both Nginx and Apache HTTP Server can be found in `/etc/webapps/arsse/nginx/` and `/etc/webapps/arsse/apache/`, respectively. The `example.conf` files are basic virtual host examples; the other files they include should normally be usable without modification, but may be modified if desired. |
|||
|
|||
If using Apache HTTP Server the `mod_proxy` and `mod_proxy_fcgi` modules must be enabled. This can be achieved by adding the following lines to your virtual host or global configuration: |
|||
|
|||
```apache |
|||
LoadModule proxy_module modules/mod_proxy.so |
|||
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so |
|||
``` |
|||
|
|||
No additional set-up is required for Nginx. |
|||
|
|||
# Using an alternative PHP interpreter |
|||
|
|||
The above instructions assume you will be using the `php` package as your PHP interpreter. If you wish to use `php-legacy` (which is always one feature version behind, for compatibility) a few configuration tweaks are required. The follwoing commands are a short summary: |
|||
|
|||
```sh |
|||
# Enable the necessary PHP extensions; curl is optional but recommended; pdo_sqlite may be used instead of sqlite3, but this is not recommended |
|||
sudo sed -i -e 's/^;\(extension=\(curl\|iconv\|intl\|sqlite3\)\)$/\1/' /etc/php-legacy/php.ini |
|||
# Modify the system service's environment |
|||
sudo sed -i -e 's/^ARSSE_PHP=.*/ARSSE_PHP=\/usr\/bin\/php-legacy/' /etc/webapps/arsse/systemd-environment |
|||
# Modify the PAM environment for the administrative CLI |
|||
echo "export ARSSE_PHP=/usr/bin/php-legacy" | sudo tee -a /etc/profile.d/arsse >/dev/null |
|||
# Modify the Nginx and Apache HTTPD configurations |
|||
sudo sed -i -se 's/\/run\/php-fpm\//\/run\/php-fpm-legacy\//' /etc/webapps/arsse/apache/arsse-fcgi.conf /etc/webapps/arsse/nginx/arsse-fcgi.conf |
|||
``` |
|||
|
|||
The above procedure can also be applied to use another PHP version from AUR if so desired. |
|||
|
|||
# Next steps |
|||
|
|||
If using a database other than SQLite, you will likely want to [set it up](/en/Getting_Started/Database_Setup) before doing anything else. |
|||
|
|||
In order for The Arsse to serve users, those users [must be created](/en/Using_The_Arsse/Managing_Users). |
|||
|
|||
You may also want to review the `config.defaults.php` file included in `/etc/webapps/arsse/` or consult [the documentation for the configuration file](/en/Getting_Started/Configuration), though The Arsse should function with the default configuration. |
|||
|
|||
# Upgrading |
|||
|
|||
Upgrading The Arsse is done like any other package. By default The Arsse will perform any required database schema upgrades when the new version is executed, so the service does need to be restarted: |
|||
|
|||
```sh |
|||
sudo systemctl restart arsse |
|||
``` |
|||
|
|||
Occasionally changes to Web server configuration have been required, such as when new protocols become supported; these changes are always explicit in the `UPGRADING` file. |
@ -0,0 +1,72 @@ |
|||
[TOC] |
|||
|
|||
# Downloading The Arsse |
|||
|
|||
Since version 0.10.0 pre-built Debian packages for The Arsse are available from the [OpenSUSE Build Service](https://build.opensuse.org/) (OBS) under [the author's personal project repository](https://build.opensuse.org/package/show/home:JKingWeb/arsse). This is the preferred method for instaling the software and is the means documented below. |
|||
|
|||
Generic release tarballs may also be downloaded [from our Web site](https://thearsse.com), and a Debian package built manually. Installing directly from the generic release tarball without producing a Debian package is not recommended as the Debian packages make the set-up process on Debian systems significantly simpler. |
|||
|
|||
# Adding the repository |
|||
|
|||
In order to install The Arsse, the OBS repository must first be configured along with its signing key: |
|||
|
|||
```sh |
|||
# Add the key |
|||
wget -q -O - "https://download.opensuse.org/repositories/home:/JKingWeb/Debian_Unstable/Release.key" | gpg --dearmor | sudo tee "/usr/share/keyrings/arsse-obs-keyring.gpg" >/dev/null |
|||
# Add the repository |
|||
echo "deb [signed-by=/usr/share/keyrings/arsse-obs-keyring.gpg] https://download.opensuse.org/repositories/home:/JKingWeb/Debian_Unstable/ ./" | sudo tee "/etc/apt/sources.list.d/arsse-obs.list" >/dev/null |
|||
# Update APT's database |
|||
sudo apt update -qq |
|||
``` |
|||
|
|||
Please note that the "Unstable" qualifier in the repository URL is a reference to Debian's "sid" release and is not a reflection on The Arsse's stability. The repository should be suitable for any Debian version or derivative which includes a sufficiently recent version of PHP. |
|||
|
|||
# Installation |
|||
|
|||
Once the OBS repository is configured, installing The Arsse is achieved with a single command: |
|||
|
|||
```sh |
|||
sudo apt install arsse |
|||
``` |
|||
|
|||
After installation is complete The Arsse will be started automatically. |
|||
|
|||
During the installation process you will be prompted whether to allow `dbconfig-common` to configure The Arsse's database automatically. The default `sqlite3` (SQLite) option is a good choice, but `pgsql` (PostgreSQL) and `mysql` (MySQL) are possible alternatives. If you wish to [use a database other than SQLite](/en/Getting_Started/Database_Setup/index), you should install it before installing The Arsse: |
|||
|
|||
```sh |
|||
# Install PostgreSQL |
|||
sudo apt install postgresql php-pgsql |
|||
# Install MySQL |
|||
sudo apt install mysql-server php-mysql |
|||
# Install SQLite explicitly |
|||
sudo apt install php-sqlite3 |
|||
``` |
|||
|
|||
If you wish to change the database backend after having installed The Arsse, running `dpkg-reconfigure` after installing the database server can be used to achieve this: |
|||
|
|||
```sh |
|||
sudo dpkg-reconfigure arsse |
|||
``` |
|||
|
|||
# Web server configuration |
|||
|
|||
Sample configuration for both Nginx and Apache HTTP Server can be found in `/etc/arsse/nginx/` and `/etc/arsse/apache/`, respectively. The `example.conf` files are basic virtual host examples; the other files they include should normally be usable without modification, but may be modified if needed or desired. In particularly users of systems older than Debian 11 (Bullseye) or Ubuntu 20.04 (Focal Fossa) or derivatives will need to change the PHP-FPM socket path in Nginx or Apache's `arsse.conf`. |
|||
|
|||
In order to use Apache HTTP Server the FastCGI proxy module must be enabled and the server restarted: |
|||
|
|||
```sh |
|||
sudo a2enmod proxy proxy_fcgi |
|||
sudo systemctl restart apache2 |
|||
``` |
|||
|
|||
No additional set-up is required for Nginx. |
|||
|
|||
# Next steps |
|||
|
|||
In order for The Arsse to serve users, those users [must be created](/en/Using_The_Arsse/Managing_Users). |
|||
|
|||
You may also want to review the `config.defaults.php` file included in the download package and create [a configuration file](/en/Getting_Started/Configuration), though The Arsse can function even without using a configuration file. |
|||
|
|||
# Upgrading |
|||
|
|||
Upgrading The Arsse is done like any other package. Occasionally changes to Web server configuration have been required, such as when new protocols become supported; these changes are always explicit in the `UPGRADING` file. |
@ -0,0 +1,53 @@ |
|||
# Downloading The Arsse |
|||
|
|||
The Arsse should run on any operating system for which PHP and a Web server are available, but only the combination of Linux, Systemd, Nginx, and PHP-FPM has been extensively tested. |
|||
|
|||
Below are very generic instructions and suggestions for installing The Arsse on systems for which pre-built packages are not available. |
|||
|
|||
# Requirements |
|||
|
|||
The Arsse has the following requirements: |
|||
|
|||
- A Web server such as: |
|||
- [Nginx](https://nginx.org) |
|||
- [Apache HTTP server](https://httpd.apache.org) 2.4 or later |
|||
- PHP 7.3.0 or later with the following extensions: |
|||
- [intl](https://php.net/manual/en/book.intl.php), [json](https://php.net/manual/en/book.json.php), [hash](https://php.net/manual/en/book.hash.php), [filter](https://php.net/manual/en/book.filter.php), and [dom](https://php.net/manual/en/book.dom.php) |
|||
- [simplexml](https://php.net/manual/en/book.simplexml.php), and [iconv](https://php.net/manual/en/book.iconv.php) |
|||
- One of: |
|||
- [sqlite3](https://php.net/manual/en/book.sqlite3.php) or [pdo_sqlite](https://php.net/manual/en/ref.pdo-sqlite.php) for SQLite databases |
|||
- [pgsql](https://php.net/manual/en/book.pgsql.php) or [pdo_pgsql](https://php.net/manual/en/ref.pdo-pgsql.php) for PostgreSQL 10 or later databases |
|||
- [mysqli](https://php.net/manual/en/book.mysqli.php) or [pdo_mysql](https://php.net/manual/en/ref.pdo-mysql.php) for MySQL/Percona 8.0.11 or later databases |
|||
- [curl](https://php.net/manual/en/book.curl.php) (optional) |
|||
- [posix](https://php.net/manual/en/book.posix.php) and [pcntl](https://php.net/manual/en/book.pcntl.php) (both optional) |
|||
- An interface between PHP and the Web server, such as [PHP-FPM](https://php.net/manual/en/install.fpm.php) |
|||
- Privileges either to create and run system services, or to run cron jobs |
|||
|
|||
# Installation |
|||
|
|||
1. Download [the latest release](https://thearsse.com/releases/current) and extract it somewhere, such as `/usr/share/arsse/` |
|||
2. [Set up your database](/en/Getting_Started/Database_Setup) |
|||
3. Create [a configuration file](/en/Getting_Started/Configuration) if needed |
|||
4. Consult the files under `dist/nginx` and `dist/apache` for sample Web server configuration |
|||
5. Consult `dist/arsse` for a sample executable script which drops privileges on POSIX systems |
|||
6. Start the newsfeed fetching service: |
|||
- Sample Systemd service files are available under `dist/systemd` |
|||
- A sample System V init script is available in `dist/init.sh` |
|||
- A persistent process can be started by running `php arsse.php daemon` |
|||
- It is also possible [to use cron](/en/Using_The_Arsse/Other_Topics.html#page_Refreshing_newsfeeds_with_a_cron_job) or a similar task-scheduling tool |
|||
7. [Create users](/en/Using_The_Arsse/Managing_Users) to grant them access |
|||
|
|||
# Upgrading |
|||
|
|||
Upgrading The Arsse is usually simple: |
|||
|
|||
1. Download the latest release |
|||
2. Check the `UPGRADING` file for any special notes |
|||
3. Stop the newsfeed refreshing service if it is running |
|||
4. Back up your configurationm and database |
|||
5. Extract the new version on top of the old one |
|||
6. Restart the newsfeed refreshing service |
|||
|
|||
By default The Arsse will perform any required database schema upgrades when the new version is executed. |
|||
|
|||
Occasionally changes to Web server configuration have been required, when new protocols become supported; such changes are always explicit in the `UPGRADING` file |
@ -0,0 +1,16 @@ |
|||
# Installing from a package manager |
|||
|
|||
We currently provide a few pre-built installation packages for the following operating systems: |
|||
|
|||
- [Arch Linux and derivatives](On_Arch_Linux) |
|||
- [Debian and derivatives](On_Debian_and_Derivatives) |
|||
|
|||
These packages significantly simplify installation, though a bit of manual effort may still be required. Updating The Arsse using these packages should require no manual intervention. |
|||
|
|||
# Installing manually |
|||
|
|||
For other systems The Arsse must currently be installed manually. As each operating system is different, we can only provide very general instructions: |
|||
|
|||
- [Installing on other systems](On_Other_Systems) |
|||
|
|||
We hope to support more operating systems in the future. |
@ -0,0 +1,24 @@ |
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.1.0</dd> |
|||
<dt>dbDriver identifier</dt> |
|||
<dd>sqlite3</dd> |
|||
<dt>Minimum version</dt> |
|||
<dd>3.8.3</dd> |
|||
<dt>Configuration</dt> |
|||
<dd><a href="../Configuration.html#page_Database_settings">General</a>, <a href="../Configuration.html#page_Database_settings_specific_to_SQLite_3">Specific</a></dd> |
|||
</dl> |
|||
|
|||
SQLite requires very little set-up. By default the database will be created at one of the following locations depending on installation method: |
|||
|
|||
| Installation method | Default database path | |
|||
|---------------------|------------------------------------------------------| |
|||
| Arch Linux package | `/var/lib/arsse/arsse.db` | |
|||
| Debian package | `/var/lib/dbconfig-common/sqlite3/arsse/arsse` | |
|||
| Manual installation | `arsse.db` in the The Arsse's installation directory | |
|||
|
|||
This path can be changed with the [`dbSQLite3File` setting](/en/Getting_Started/Configuration#page_dbSQLite3File). |
|||
|
|||
Regardless of the location used, The Arsse **must** be able to both read from and write to the database file, as well as create files in its directory. This is because SQLite also creates a write-ahead log file and a shared-memory file during operation. |
@ -0,0 +1,37 @@ |
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.6.0</dd> |
|||
<dt>dbDriver identifier</dt> |
|||
<dd>postgresql</dd> |
|||
<dt>Minimum version</dt> |
|||
<dd>10</dd> |
|||
<dt>Configuration</dt> |
|||
<dd><a href="../Configuration.html#page_Database_settings">General</a>, <a href="../Configuration.html#page_Database_settings_specific_to_PostgreSQL">Specific</a></dd> |
|||
</dl> |
|||
|
|||
If for whatever reason an SQLite database does not suit your configuration, PostgreSQL is the best alternative. It is functionally equivalent to SQLite in every way. |
|||
|
|||
# Set-up |
|||
|
|||
In order to use a PostgreSQL database for The Arsse, the database must already exist. The procedure for creating a database can differ between systems, but a typical Linux procedure is as follows: |
|||
|
|||
```sh |
|||
sudo -u postgres psql -c "CREATE USER arsseuser WITH PASSWORD 'super secret password'" |
|||
sudo -u postgres psql -c "CREATE DATABASE arssedb WITH OWNER arsseuser" |
|||
``` |
|||
|
|||
The Arsse must then be configured to use the created database. A suitable [configuration file](/en/Getting_Started/Configuration) might look like this: |
|||
|
|||
```php |
|||
<?php |
|||
return [ |
|||
'dbDriver' => "postgresql", |
|||
'dbPostgreSQLUser' => "arsseuser", |
|||
'dbPostgreSQLPass' => "super secret password", |
|||
'dbPostgreSQLDb' => "arssedb", |
|||
]; |
|||
``` |
|||
|
|||
Numerous alternate configurations are possible; the above is merely the simplest. |
@ -0,0 +1,42 @@ |
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.6.0</dd> |
|||
<dt>dbDriver identifier</dt> |
|||
<dd>mysql</dd> |
|||
<dt>Minimum version</dt> |
|||
<dd>8.0.11</dd> |
|||
<dt>Configuration</dt> |
|||
<dd><a href="../Configuration.html#page_Database_settings">General</a>, <a href="../Configuration.html#page_Database_settings_specific_to_MySQL">Specific</a></dd> |
|||
</dl> |
|||
|
|||
While MySQL can be used as a database for The Arsse, this is **not recommended** due to MySQL's technical limitations. It is fully functional, but may fail with some newsfeeds where other database systems do not. Additionally, it is particularly important before upgrading from one version of The Arsse to the next to back up your database: a failure in a database upgrade can corrupt your database much more easily than when using other database systems. |
|||
|
|||
You are therefore strongly advised not to use MySQL. Though our MySQL test suite ensures functionally identical behaviour to SQLite and PostgreSQL for the supplied test data in a default MySQL configuration, there are [many other subtle ways in which it can fail](https://web.archive.org/web/20190929090114/https://grimoire.ca/mysql/choose-something-else), and we do not have the manpower to account for most of these with certainty. |
|||
|
|||
Also please note that as of this writing MariaDB cannot be used in place of MySQL as it lacks features of MySQL 8 which The Arsse requires (see the [relevant MariaDB issue](https://jira.mariadb.org/browse/MDEV-18511) for details). The awkwardly-named [_Percona Server for MySQL_](https://www.percona.com/software/mysql-database/percona-server), on the other hand, will work. |
|||
|
|||
# Set-up |
|||
|
|||
In order to use a MySQL database for The Arsse, the database must already exist. The procedure for creating a database can differ between systems, but a typical Linux procedure is as follows: |
|||
|
|||
```sh |
|||
sudo mysql -e "CREATE USER 'arsseuser'@'localhost' IDENTIFIED BY 'super secret password'" |
|||
sudo mysql -e "CREATE DATABASE arssedb" |
|||
sudo mysql -e "GRANT ALL ON arssedb.* TO 'arsseuser'@'localhost'" |
|||
``` |
|||
|
|||
The Arsse must then be configured to use the created database. A suitable [configuration file](/en/Getting_Started/Configuration) might look like this: |
|||
|
|||
```php |
|||
<?php |
|||
return [ |
|||
'dbDriver' => "mysql", |
|||
'dbMySQLUser' => "arsseuser", |
|||
'dbMySQLPass' => "super secret password", |
|||
'dbMySQLDb' => "arssedb", |
|||
]; |
|||
``` |
|||
|
|||
Numerous alternate configurations are possible; the above is merely the simplest. |
@ -0,0 +1,11 @@ |
|||
The Arsse supports the following database backends: |
|||
|
|||
- [SQLite 3.8.3](SQLite) and later |
|||
- [PostgreSQL 10](PostgreSQL) and later |
|||
- [MySQL 8.0.11](MySQL) and later |
|||
|
|||
All of the above are supported both via their PDO driver extensions as well as their native PHP extensions. One or the other is selected based on availability in your PHP installation. |
|||
|
|||
Functionally there is no reason to prefer either SQLite or PostgreSQL over the other. SQLite is significantly simpler to set up in most cases, requiring only read and write access to a containing directory in order to function; PostgreSQL may perform better than SQLite when serving hundreds of users or more, though this has not been tested. |
|||
|
|||
MySQL, on the other hand, is **not recommended** due to various technical limitations. |
@ -0,0 +1,426 @@ |
|||
# The configuration file |
|||
|
|||
Depending on how The Arsse was installed, it will look for configuration in the following places: |
|||
|
|||
| Installation method | Default configuration file path | |
|||
|---------------------|--------------------------------------------------------| |
|||
| Arch Linux package | `/etc/webapps/arsse/config.php` | |
|||
| Debian package | `/etc/arsse/config.php` | |
|||
| Manual installation | `config.php` in the The Arsse's installation directory | |
|||
|
|||
It is not an error for this file not to exist or to be empty: The Arsse will function with no configuration whatsoever, provided other conditions allow. |
|||
|
|||
The configuration file is a PHP script which returns an associative array with keys and values for one or more settings. Any settings which are not specified in the configuration file will be set to their defaults. Invalid values will cause an error on start-up, while unknown keys are ignored. A basic configuration file might look like this: |
|||
|
|||
```php |
|||
<?php return [ |
|||
'lang' => "en", |
|||
'dbDriver' => "sqlite3", |
|||
'dbSQLite3File' => "/var/lib/arsse/arsse.db", |
|||
]; |
|||
``` |
|||
|
|||
# List of all settings |
|||
|
|||
The `config.defaults.php` file included with copies of The Arsse contains an annotated listing of every configuration setting with its default value. The settings are also documented in more detail below. |
|||
|
|||
## General settings |
|||
|
|||
### lang |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `"en"` | |
|||
|
|||
The default language locale, mostly used when reporting errors on the command line or in logs. Currently only `"en"` (English) is available. |
|||
|
|||
## Database settings |
|||
|
|||
### dbDriver |
|||
|
|||
| Type | Default | |
|||
|--------|-------------| |
|||
| string | `"sqlite3"` | |
|||
|
|||
The database driver to use. The following values are understood: |
|||
|
|||
- `"sqlite3"` for SQLite databases |
|||
- `"postgresql"` for PostgreSQL databases |
|||
- `"mysql"` for MySQL databases |
|||
|
|||
It is also possible to specify the fully-qualified name of a class which implements the database driver interface. For example, specifying `"JKingWeb\Arsse\Db\SQLite3\PDODriver"` would use the PDO driver for SQLite 3. |
|||
|
|||
### dbAutoUpdate |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| boolean | `true` | |
|||
|
|||
Whether to attempt to automatically upgrade the database schema when upgrading The Arsse to a new version with schema changes. |
|||
|
|||
If set to `false`, the database schema must be manually upgraded. Schema files can be found under `sql/<backend>/#.sql`; the `UPGRADING` file will advise when a schema upgrade is required. |
|||
|
|||
### dbTimeoutConnect |
|||
|
|||
| Type | Default | |
|||
|------------------|---------| |
|||
| interval or null | `5.0` | |
|||
|
|||
The number of seconds to wait before returning a timeout error when connecting to a database server. The special value `null` waits the maximum amount of time, while `0.0` waits the minimum amount of time. The minimums are maximums for each backend are as follows: |
|||
|
|||
| Backend | Minimum | Maximum | |
|||
|------------|----------|----------| |
|||
| SQLite 3 | *(does not apply)* | *(does not apply)* | |
|||
| PostgreSQL | 1 second | forever | |
|||
| MySQL | 1 second | forever | |
|||
|
|||
Note that in practice neither PostgreSQL nor MySQL will wait indefinitely: they are still subject to PHP's socket timeouts. Consult [PostgreSQL's documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-CONNECT-TIMEOUT) for details on how the timeout is interpreted by PostgreSQL. |
|||
|
|||
### dbTimeoutExec |
|||
|
|||
| Type | Default | |
|||
|----------|---------| |
|||
| interval | `null` | |
|||
|
|||
The number of seconds to wait before returning a timeout error when executing a database operation (i.e. computing results). The special value `null` waits the maximum amount of time, while `0.0` waits the minimum amount of time. The minimums are maximums for each backend are as follows: |
|||
|
|||
| Backend | Minimum | Maximum | |
|||
|------------|---------------|----------| |
|||
| SQLite 3 | *(does not apply)* | *(does not apply)* | |
|||
| PostgreSQL | 1 millisecond | forever | |
|||
| MySQL | 1 second | forever | |
|||
|
|||
With MySQL this timeout only applies to read operations, whereas PostgreSQL will time out write operations as well. |
|||
|
|||
### dbTimeoutLock |
|||
|
|||
| Type | Default | |
|||
|----------|---------| |
|||
| interval | `60.0` | |
|||
|
|||
The number of seconds to wait before returning a timeout error when acquiring database locks. The special value `null` waits the maximum amount of time, while `0.0` waits the minimum amount of time. The minimums are maximums for each backend are as follows: |
|||
|
|||
| Backend | Minimum | Maximum | |
|||
|------------|----------------|-----------------------| |
|||
| SQLite 3 | 0 milliseconds | at least 24 days | |
|||
| PostgreSQL | 1 millisecond | forever | |
|||
| MySQL | 1 second | approximately 1 year | |
|||
|
|||
Note that PostgreSQL counts time spent waiting for locks as part of the above execution timeout. The maximum timeout for SQLite is `PHP_INT_MAX` milliseconds, which on 32-bit systems is just under 25 days, and on 64-bit systems is billions of years. |
|||
|
|||
## Database settings specific to SQLite 3 |
|||
|
|||
### dbSQLite3File |
|||
|
|||
| Type | Default | |
|||
|----------------|---------| |
|||
| string or null | `null` | |
|||
|
|||
The full path and file name of SQLite database. The special value `null` evaluates to a file named `"arsse.db"` in the directory where The Arsse is installed. |
|||
|
|||
### dbSQLite3Key |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
The key used to encrypt/decrypt the SQLite database. This is only relevant if using the [SQLite Encryption Extension](https://www.sqlite.org/see/). |
|||
|
|||
## Database settings specific to PostgreSQL |
|||
|
|||
### dbPostgreSQLHost |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
The host name, address, or socket path of the PostgreSQL database server. |
|||
|
|||
Consult [PostgreSQL's documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-HOST) for more details. |
|||
|
|||
### dbPostgreSQLUser |
|||
|
|||
| Type | Default | |
|||
|--------|-----------| |
|||
| string | `"arsse"` | |
|||
|
|||
The log-in user name for the PostgreSQL database server. |
|||
|
|||
### dbPostgreSQLPass |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
The log-in password for the PostgreSQL database server. |
|||
|
|||
### dbPostgreSQLPort |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| integer | `5432` | |
|||
|
|||
The TCP port on which to connect to the PostgreSQL database server, if connecting via TCP. |
|||
|
|||
### dbPostgreSQLDb |
|||
|
|||
| Type | Default | |
|||
|--------|-----------| |
|||
| string | `"arsse"` | |
|||
|
|||
The name of the database used by The Arsse on the PostgreSQL database server. |
|||
|
|||
### dbPostgreSQLSchema |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
The name of the schema used by The Arsse on the PostgreSQL database server. When not set to the empty string, the PostgreSQL search path is modified to consist of the specified schema with a fallback to the public schema. |
|||
|
|||
Consult [PostgreSQL's documentation](https://www.postgresql.org/docs/current/ddl-schemas.html) for more details. |
|||
|
|||
### dbPostgreSQLService |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
A PostgreSQL service file entry to use *instead of* the above configuration; if using a service entry all above PostgreSQL-specific parameters except schema are ignored. |
|||
|
|||
Consult [PostgreSQL's documentation](https://www.postgresql.org/docs/current/libpq-pgservice.html) for more details. |
|||
|
|||
## Database settings specific to MySQL |
|||
|
|||
### dbMySQLHost |
|||
|
|||
| Type | Default | |
|||
|--------|---------------| |
|||
| string | `"localhost"` | |
|||
|
|||
The host name or address of the MySQL database server. The values `"localhost"` and `"."` are special. |
|||
|
|||
Consult [MySQL's documentation](https://dev.mysql.com/doc/refman/8.0/en/connecting.html) for more details. |
|||
|
|||
### dbMySQLUser |
|||
|
|||
| Type | Default | |
|||
|--------|-----------| |
|||
| string | `"arsse"` | |
|||
|
|||
The log-in user name for the MySQL database server. |
|||
|
|||
### dbMySQLPass |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
The log-in password for the MySQL database server. |
|||
|
|||
### dbMySQLPort |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| integer | `3306` | |
|||
|
|||
The TCP port on which to connect to the MySQL database server, if connecting via TCP. |
|||
|
|||
### dbMySQLDb |
|||
|
|||
| Type | Default | |
|||
|--------|-----------| |
|||
| string | `"arsse"` | |
|||
|
|||
The name of the database used by The Arsse on the MySQL database server. |
|||
|
|||
### dbMySQLSocket |
|||
|
|||
| Type | Default | |
|||
|--------|---------| |
|||
| string | `""` | |
|||
|
|||
A Unix domain socket or named pipe to use for the MySQL database server when not connecting via TCP. |
|||
|
|||
## User management settings |
|||
|
|||
### userDriver |
|||
|
|||
| Type | Default | |
|||
|--------|--------------| |
|||
| string | `"internal"` | |
|||
|
|||
The user management driver to use. Currently only `"internal"` is available, which stores user IDs and hashed passwords in the configured database. |
|||
|
|||
It is also possible to specify the fully-qualified name of a class which implements the user management driver interface. For example, specifying `"JKingWeb\Arsse\User\Internal\Driver"` would use the internal driver. |
|||
|
|||
### userPreAuth |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| boolean | `false` | |
|||
|
|||
Whether users are authenticated by the Web server before requests are passed to The Arsse. If set to `true` The Arsse will perform no HTTP-level authentication and assume that the user ID supplied in either the `REMOTE_USER` CGI variable or the `Authorization` HTTP header-field (if `Basic` authentication was used) is authentic. |
|||
|
|||
For synchronization protocols which implement their own authentication (such as Tiny Tiny RSS), this setting may or may not affect how protocol-level authentication is handled; consult the section on The Arsse's [supported protocols](/en/Supported_Protocols) for more information. |
|||
|
|||
If the user has not previously logged in, an entry is created for them in the database automatically. If the Web server uses `Basic` HTTP authentication and passes along the `Authorization` field, a hash of the user's password will also be stored in The Arsse's database. |
|||
|
|||
### userHTTPAuthRequired |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| boolean | `false` | |
|||
|
|||
Whether to require successful HTTP authentication before processing API-level authentication, for protocol which implement their own authentication. |
|||
|
|||
### userSessionEnforced |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| boolean | `true` | |
|||
|
|||
Whether invalid or expired API session tokens should prevent logging in when HTTP authentication is used, for protocol which implement their own authentication. |
|||
|
|||
### userSessionTimeout |
|||
|
|||
| Type | Default | |
|||
|----------|-----------| |
|||
| interval | `"PT24H"` | |
|||
|
|||
The period of inactivity after which log-in sessions should be considered invalid. Session timeouts should not be made too long, to guard against session hijacking. |
|||
|
|||
### userSessionLifetime |
|||
|
|||
| Type | Default | |
|||
|----------|-----------| |
|||
| interval | `"P7D"` | |
|||
|
|||
The maximum lifetime of log-in sessions regardless of recent activity. Session lifetimes should not be made too long, to guard against session hijacking. |
|||
|
|||
### userTempPasswordLength |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| integer | `20` | |
|||
|
|||
The desired length in characters of randomly-generated user passwords. When [adding users](/en/Using_The_Arsse/Managing_Users), omitting a desired password generates a random one; this setting controls the length of these passwords. |
|||
|
|||
## Newsfeed fetching service settings |
|||
|
|||
### serviceDriver |
|||
|
|||
| Type | Default | |
|||
|--------|----------------| |
|||
| string | `"subprocess"` | |
|||
|
|||
The newsfeed fetching service driver to use. The following values are understood: |
|||
|
|||
- `"serial"`: Fetches newsfeeds and processed them one at a time. This is the slowest method, but is simple and reliable. |
|||
- `"subprocess"`: Fetches and processes multiple newsfeeds concurrently by starting a separate process for each newsfeed using PHP's [`popen`](https://php.net/manual/en/function.popen.php) function. This uses more memory and processing power, but takes less total time. |
|||
|
|||
It is also possible to specify the fully-qualified name of a class which implements the service driver interface. For example, specifying `"JKingWeb\Arsse\Service\Serial\Driver"` would use the serial driver. |
|||
|
|||
### serviceFrequency |
|||
|
|||
| Type | Default | |
|||
|----------|----------| |
|||
| interval | `"PT2M"` | |
|||
|
|||
The interval the newsfeed fetching service observes between checks for new articles. Note that requests to foreign servers are not necessarily made at this frequency: each newsfeed is assigned its own time at which to be next retrieved. This setting instead defines the length of time the fetching service will sleep between periods of activity. |
|||
|
|||
Consult "[How Often Newsfeeds Are Fetched](/en/Using_The_Arsse/Other_Topics#page_How_often_newsfeeds_are_fetched)" for details on newsfeed update frequency. |
|||
|
|||
### serviceQueueWidth |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| integer | `5` | |
|||
|
|||
The maximum number of concurrent newsfeed updates to perform, if a concurrent service driver is used. |
|||
|
|||
### fetchTimeout |
|||
|
|||
| Type | Default | |
|||
|----------|---------| |
|||
| interval | `10.0` | |
|||
|
|||
The maximum number of seconds to wait for data when fetching newsfeeds from foreign servers. |
|||
|
|||
### fetchSizeLimit |
|||
|
|||
| Type | Default | |
|||
|---------|-------------------| |
|||
| integer | `2 * 1024 * 1024` | |
|||
|
|||
The maximum size, in bytes, of data to accept when fetching a newsfeed. Newsfeeds larger than this will be rejected to guard against denial-of-servioce attacks. |
|||
|
|||
The default value is equal to two megabytes. |
|||
|
|||
### fetchEnableScraping |
|||
|
|||
| Type | Default | |
|||
|---------|---------| |
|||
| boolean | `true` | |
|||
|
|||
Whether to allow the possibility of fetching full article contents from an article's source, if a newsfeed only provides excerpts. Whether fetching will actually happen is governed by a per-newsfeed toggle (defaulting to `false`) which currently can only be changed via the Miniflux protocol. |
|||
|
|||
### fetchUserAgentString |
|||
|
|||
| Type | Default | |
|||
|----------------|---------| |
|||
| string or null | `null` | |
|||
|
|||
The [user agent](https://tools.ietf.org/html/rfc7231#section-5.5.3) The Arsse will identify as when fetching newsfeeds. The special value null will use an identifier similar to the following: |
|||
|
|||
``` |
|||
Arsse/0.6.0 (Linux 4.15.0; x86_64; https://thearsse.com/) |
|||
``` |
|||
|
|||
## Housekeeping settings |
|||
|
|||
### purgeFeeds |
|||
|
|||
| Type | Default | |
|||
|------------------|-----------| |
|||
| interval or null | `"PT24H"` | |
|||
|
|||
How long to keep a newsfeed and its articles in the database after all its subscriptions have been deleted. Specifying `null` will retain unsubscribed newsfeeds forever, whereas an interval evaluating to zero (e.g. `"PT0S"`) will delete them immediately. |
|||
|
|||
Note that articles of orphaned newsfeeds are still subject to the `purgeArticleUnread` threshold below. |
|||
|
|||
### purgeArticlesRead |
|||
|
|||
| Type | Default | |
|||
|------------------|---------| |
|||
| interval or null | `"P7D"` | |
|||
|
|||
How long to keep a an article in the database after all users subscribed to its newsfeed have read it. Specifying `null` will retain articles up to the `purgeArticlesUnread` threshold below, whereas an interval evaluating to zero (e.g. `"PT0S"`) will delete them immediately. |
|||
|
|||
If an article is starred by any user, it is retained indefinitely regardless of this setting. |
|||
|
|||
This setting also governs when an article is hidden from a user after being read by that user, regardless of its actual presence in the database. |
|||
|
|||
### purgeArticlesUnread |
|||
|
|||
| Type | Default | |
|||
|------------------|----------| |
|||
| interval or null | `"P21D"` | |
|||
|
|||
How long to keep a an article in the database regardless of whether any users have read it. Specifying `null` will retain articles forever, whereas an interval evaluating to zero (e.g. `"PT0S"`) will delete them immediately. |
|||
|
|||
If an article is starred by any user, it is retained indefinitely regardless of this setting. |
|||
|
|||
# Obsolete settings |
|||
|
|||
### dbSQLite3Timeout |
|||
|
|||
| Type | Historical Default | |
|||
|----------|--------------------| |
|||
| interval | `60.0` | |
|||
|
|||
*This setting has been replaced by [dbTimeoutLock](#page_dbTimeoutLock).* |
|||
|
|||
The number of seconds for SQLite to wait before returning a timeout error when trying to acquire a write lock on the database file. Setting this to a low value may cause operations to fail with an error. |
|||
|
|||
Consult [SQLite's documentation](https://sqlite.org/c3ref/busy_timeout.html) for more details. |
@ -0,0 +1,88 @@ |
|||
[TOC] |
|||
|
|||
# Preface |
|||
|
|||
This section describes in brief some CLI commands. Please read [the general notes on the command line interface](index) before continuing. |
|||
|
|||
# Adding users |
|||
|
|||
When first installed, The Arsse has no users configured. You may add users by executing the following command: |
|||
|
|||
```sh |
|||
sudo arsse user add "user@example.com" "example password" |
|||
``` |
|||
|
|||
The password argument is optional: if no password is provided, a random one is generated and printed out: |
|||
|
|||
```console |
|||
$ sudo arsse user add "jane.doe" |
|||
Ji0ivMYqi6gKxQK1MHuE |
|||
``` |
|||
|
|||
# Setting and changing passwords |
|||
|
|||
Setting a user's password is nearly identical to adding a user: |
|||
|
|||
```sh |
|||
sudo arsse user set-pass "user@example.com" "new password" |
|||
``` |
|||
|
|||
As when adding a user, the password argument is optional: if no password is provided, a random one is generated and printed out: |
|||
|
|||
```console |
|||
$ sudo arsse user set-pass "jane.doe" |
|||
Ummn173XjbJT4J3Gnx0a |
|||
``` |
|||
|
|||
## Setting and changing passwords for Fever |
|||
|
|||
Before a user can make use of [the Fever protocol](/en/Supported_Protocols/Fever), a Fever-specific password for that user must be set. It is _highly recommended_ that this not be the samer as the user's main password. The password can be set by adding the `--fever` option to the normal password-changing command: |
|||
|
|||
```sh |
|||
sudo arsse user set-pass --fever "user@example.com" "fever password" |
|||
``` |
|||
|
|||
As when setting a main password, the password argument is optional: if no password is provided, a random one is generated and printed out: |
|||
|
|||
```console |
|||
$ sudo arsse user set-pass --fever "jane.doe" |
|||
YfZJHq4fNTRUKDYhzQdR |
|||
``` |
|||
|
|||
## Managing login tokens for Miniflux |
|||
|
|||
[Miniflux](/en/Supported_Protocols/Miniflux) clients may optionally log in using tokens: randomly-generated strings which act as persistent passwords. For now these must be generated using the command-line interface: |
|||
|
|||
```console |
|||
$ sudo arsse token create "jane.doe" |
|||
xRK0huUE9KHNHf_x_H8JG0oRDo4t_WV44whBtr8Ckf0= |
|||
``` |
|||
|
|||
Multiple tokens may be generated for use with different clients, and descriptive labels can be assigned for later identification: |
|||
|
|||
```console |
|||
$ sudo arsse token create "jane.doe" Newsflash |
|||
xRK0huUE9KHNHf_x_H8JG0oRDo4t_WV44whBtr8Ckf0= |
|||
$ sudo arsse token create "jane.doe" Reminiflux |
|||
L7asI2X_d-krinGJd1GsiRdFm2o06ZUlgD22H913hK4= |
|||
``` |
|||
|
|||
There are also commands for listing and revoking tokens. Please consult the integrated help for more details. |
|||
|
|||
# Setting and changing user metadata |
|||
|
|||
Users may also have various metadata properties set. These largely exist for compatibility with [the Miniflux protocol](/en/Supported_Protocols/Miniflux) and have no significant effect. One exception to this, however, is the `admin` flag, which signals whether the user may perform privileged operations where they exist in the supported protocols. |
|||
|
|||
The flag may be changed using the following command: |
|||
|
|||
```sh |
|||
sudo arsse user set "jane.doe" admin true |
|||
``` |
|||
|
|||
As a shortcut it is also possible to create administrators directly: |
|||
|
|||
```sh |
|||
sudo arsse user add "user@example.com" "example password" --admin |
|||
``` |
|||
|
|||
Please consult the integrated help for more details on metadata and their effects. |
@ -0,0 +1,54 @@ |
|||
[TOC] |
|||
|
|||
# Preface |
|||
|
|||
This section describes in brief some CLI commands. Please read [the general notes on the command line interface](index) before continuing. |
|||
|
|||
# Importing newsfeeds from OPML |
|||
|
|||
It's possible to import not only newsfeeds but also folders and Fever groups using OPML files. The process is simple: |
|||
|
|||
```sh |
|||
sudo arsse import "user@example.com" "subscriptions.opml" |
|||
``` |
|||
|
|||
The importer is forgiving, but some OPML files may fail, with the reason printed out. Files are either imported in total, or not at all. |
|||
|
|||
# Exporting newsfeeds to OPML |
|||
|
|||
It's possible to export not only newsfeeds but also folders and Fever groups to OPML files. The process is simple: |
|||
|
|||
```sh |
|||
sudo arsse export "user@example.com" "subscriptions.opml" |
|||
``` |
|||
|
|||
The output might look like this: |
|||
|
|||
```xml |
|||
<opml version="2.0"> |
|||
<head/> |
|||
<body> |
|||
<outline text="Folder"> |
|||
<outline text="Subfolder"> |
|||
<outline type="rss" text="Feed 1" xmlUrl="http://example.com/feed1"/> |
|||
</outline> |
|||
<outline type="rss" text="Feed 2" xmlUrl="http://example.com/feed2" category="group 1,group 2"/> |
|||
<outline type="rss" text="Feed 3" xmlUrl="http://example.com/feed3" category="group 1"/> |
|||
</outline> |
|||
<outline type="rss" text="Feed 4" xmlUrl="http://example.com/feed4" category="group 2,group 3"/> |
|||
</body> |
|||
</opml> |
|||
``` |
|||
|
|||
# Managing newsfeeds via OPML |
|||
|
|||
Not all protocols supported by The Arsse allow modifying newsfeeds or folders, et cetera; additionally, not all clients support these capabilities even if the protocol has the necessary features. An OPML export/import sequence with the `--replace` import option specified, however, makes any kind of modification possible. For example: |
|||
|
|||
```sh |
|||
# export your newsfeeds |
|||
sudo arsse export "user@example.com" "subscriptions.opml" |
|||
# make any changes you want in your editor of choice |
|||
nano "subscriptions.opml" |
|||
# re-import the modified information |
|||
sudo arsse import "user@example.com" "subscriptions.opml" --replace |
|||
``` |
@ -0,0 +1,34 @@ |
|||
[TOC] |
|||
|
|||
# Preface |
|||
|
|||
This section describes in brief some CLI commands. Please read [the general notes on the command line interface](index) before continuing. |
|||
|
|||
# Refreshing newsfeeds with a cron job |
|||
|
|||
Normally The Arsse has a systemd service which checks newsfeeds for updates and processes them into its database for the user. If for whatever reason this is not practical a [cron](https://en.wikipedia.org/wiki/Cron) job may be used instead. |
|||
|
|||
Keeping newsfeeds updated with cron is not difficult. Simply run the following command: |
|||
|
|||
|
|||
```sh |
|||
sudo crontab -u arsse -e |
|||
``` |
|||
|
|||
And add a line such as this one: |
|||
|
|||
``` |
|||
*/2 * * * * /usr/bin/arsse refresh-all |
|||
``` |
|||
|
|||
Thereafter The Arsse's will be scheduled to check newsfeeds every two minutes. Consult the manual pages for the `crontab` [format](http://man7.org/linux/man-pages/man5/crontab.5.html) and [command](http://man7.org/linux/man-pages/man1/crontab.1.html) for details. |
|||
|
|||
# How often newsfeeds are fetched |
|||
|
|||
Though by default The Arsse will wake up every two minutes, newsfeeds are not actually downloaded so frequently. Instead, each newsfeed is assigned a time at which it should next be fetched, and once that time is reached a [conditional request](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests) is made. The interval between requests for a particular newsfeed can vary from 15 minutes to 24 hours based on multiple factors such as: |
|||
|
|||
- The length of time since the newsfeed last changed |
|||
- The interval between publishing of articles in the newsfeed |
|||
- Whether the last fetch or last several fetches resulted in error |
|||
|
|||
As a general rule, newsfeeds which change frequently are checked frequently, and those which change seldom are fetched at most daily. |
@ -0,0 +1,9 @@ |
|||
# Preface |
|||
|
|||
This section details a few administrative tasks which may need to be performed after installing The Arsse. As no Web-based administrative interface is included, these tasks are generally performed via command line interface. |
|||
|
|||
Though this section describes some commands briefly, complete documentation of The Arsse's command line interface is not included in this manual. Documentation for CLI commands can instead be viewed using the system manual service by executing `man arsse`. |
|||
|
|||
# A Note on Command Invocation |
|||
|
|||
Particularly if using an SQLite database, it's important that administrative commands be executed as the same user who owns The Arsse's files. To that end our releases include an `arsse` executable which drops privileges when executed as root. Commands in this section assume this executable is being used. |
@ -0,0 +1,59 @@ |
|||
[TOC] |
|||
|
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.9.0</dd> |
|||
<dt>Base URL</dt> |
|||
<dd>/</dd> |
|||
<dt>API endpoint</dt> |
|||
<dd>/v1/</dd> |
|||
<dt>Specifications</dt> |
|||
<dd><a href="https://miniflux.app/docs/api.html">API Reference</a>, <a href="https://miniflux.app/docs/rules.html#filtering-rules">Filtering Rules</a></dd> |
|||
</dl> |
|||
|
|||
The Miniflux protocol is a fairly well-designed protocol supporting a wide variety of operations on newsfeeds, folders (termed "categories"), and articles; it also allows for user administration, and native OPML importing and exporting. Architecturally it is similar to the Nextcloud News protocol, but has more capabilities. |
|||
|
|||
Miniflux version 2.0.28 is emulated, though not all features are implemented |
|||
|
|||
# Missing features |
|||
|
|||
- JSON Feed format is not suported |
|||
- Various feed-related features are not supported; attempting to use them has no effect |
|||
- Rewrite rules and scraper rules |
|||
- Custom User-Agent strings |
|||
- The `disabled`, `ignore_http_cache`, and `fetch_via_proxy` flags |
|||
- Changing the URL, username, or password of a feed |
|||
- Manually refreshing feeds |
|||
- Titles and types are not available during feed discovery and are filled with generic data |
|||
- Reading time is not calculated and will always be zero |
|||
- Only the first enclosure of an article is retained |
|||
- Comment URLs of articles are not exposed |
|||
|
|||
# Differences |
|||
|
|||
- Various error codes and messages differ due to significant implementation differences |
|||
- The "All" category is treated specially (see below for details) |
|||
- Feed and category titles consisting only of whitespace are rejected along with the empty string |
|||
- Filtering rules may not function identically (see below for details) |
|||
- The `checked_at` field of feeds indicates when the feed was last updated rather than when it was last checked |
|||
- Creating a feed with the `scrape` property set to `true` might not return scraped content for the initial synchronization |
|||
- Search strings will match partial words |
|||
- OPML import either succeeds or fails atomically: if one feed fails, no feeds are imported |
|||
|
|||
# Behaviour of filtering (block and keep) rules |
|||
|
|||
The Miniflux documentation gives only a brief example of a pattern for its filtering rules; the allowed syntax is described in full [in Google's documentation for RE2](https://github.com/google/re2/wiki/Syntax). Being a PHP application, The Arsse instead accepts [PCRE syntax](http://www.pcre.org/original/doc/html/pcresyntax.html) (or since PHP 7.3 [PCRE2 syntax](https://www.pcre.org/current/doc/html/pcre2syntax.html)), specifically in UTF-8 mode. Delimiters should not be included, and slashes should not be escaped; anchors may be used if desired. For example `^(?i)RE/MAX$` is a valid pattern. |
|||
|
|||
For convenience the patterns are tested after collapsing whitespace. Unlike Miniflux, The Arsse tests the patterns against an article's author-supplied categories if they do not match its title. Also unlike Miniflux, when filter rules are modified they are re-evaluated against all applicable articles immediately. |
|||
|
|||
# Special handling of the "All" category |
|||
|
|||
Nextcloud News' root folder and Tiny Tiny RSS' "Uncategorized" catgory are mapped to Miniflux's initial "All" category. This Miniflux category can be renamed, but it cannot be deleted. Attempting to do so will delete the child feeds it contains, but not the category itself. |
|||
|
|||
Because the root folder does not existing in the database as a separate entity, it will always sort first when ordering by `category_id` or `category_title`. |
|||
|
|||
# Interaction with nested categories |
|||
|
|||
Tiny Tiny RSS is unique in allowing newsfeeds to be grouped into categories nested to arbitrary depth. When newsfeeds are placed into nested categories, they simply appear in the top-level category when accessed via the Miniflux protocol. This does not affect OPML exports, where full nesting is preserved. |
@ -0,0 +1,38 @@ |
|||
[TOC] |
|||
|
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.1.0</dd> |
|||
<dt>Base URL</dt> |
|||
<dd>/</dd> |
|||
<dt>API endpoint</dt> |
|||
<dd>/index.php/apps/news/api/v1-2/</dd> |
|||
<dt>Specifications</dt> |
|||
<dd><a href="https://github.com/nextcloud/news/blob/master/docs/api/api-v1-2.md">Version 1.2</a></dd> |
|||
</dl> |
|||
|
|||
The Nextcloud News protocol was the first supported by The Arsse, and has been supported in full since version 0.3.0. |
|||
|
|||
It allows organizing newsfeeds into single-level folders, and supports a wide range of operations on newsfeeds, folders, and articles. |
|||
|
|||
# Differences |
|||
|
|||
- Article GUID hashes are not hashes like in NCN; they are integers rendered as strings |
|||
- Article fingerprints are a combination of hashes rather than a single hash |
|||
- When marking articles as starred the feed ID is ignored, as they are not needed to establish uniqueness |
|||
- The feed updater ignores the `userId` parameter: feeds in The Arsse are deduplicated, and have no owner |
|||
- The `/feeds/all` route lists only feeds which should be checked for updates, and it also returns all `userId` attributes as empty strings: feeds in The Arsse are deduplicated, and have no owner |
|||
- The "updater" console commands mentioned in the protocol specification are not implemented, as The Arsse does not implement the required Nextcloud subsystems |
|||
- The `lastLoginTimestamp` attribute of the user metadata is always the current time: The Arsse's implementation of the protocol is fully stateless |
|||
- Syntactically invalid JSON input will yield a `400 Bad Request` response instead of falling back to GET parameters |
|||
- Folder names consisting only of whitespace are rejected along with the empty string |
|||
- Feed titles consisting only of whitespace or the empty string are rejected with a `422 Unprocessable Entity` reponse instead of being accepted |
|||
- Bulk-marking operations without a `newestItemId` argument result in a `422 Unprocessable Entity` reponse instead of silently failing |
|||
- Creating a feed in a folder which does not exist places the feed in the root folder rather than suppressing the feed |
|||
- Moving a feed to a folder which does not exist results in a `422 Unprocessable Entity` reponse rather than suppressing the feed |
|||
|
|||
# Interaction with nested folders |
|||
|
|||
Tiny Tiny RSS is unique in allowing newsfeeds to be grouped into folders nested to arbitrary depth. When newsfeeds are placed into nested folders, they simply appear in the top-level folder when accessed via the Nextcloud News protocol. |
@ -0,0 +1,95 @@ |
|||
[TOC] |
|||
|
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.2.0</dd> |
|||
<dt>Base URL</dt> |
|||
<dd>/tt-rss/</dd> |
|||
<dt>API endpoint</dt> |
|||
<dd>/tt-rss/api</dd> |
|||
<dt>Specifications</dt> |
|||
<dd><a href="https://tt-rss.org/wiki/ApiReference">Main</a>, <a href="https://tt-rss.org/wiki/SearchSyntax">search syntax</a>, <a href="https://github.com/jangernert/FeedReader/blob/master/data/tt-rss-feedreader-plugin/README.md">FeedReader extensions</a>, <a href="https://github.com/hrk/tt-rss-newsplus-plugin/blob/master/README.md">News+ extension</a></dd> |
|||
</dl> |
|||
|
|||
The Arsse supports not only the Tiny Tiny RSS protocol, but also extensions required by the FeedReader client and the more commonly supported `getCompactHeadlines` extension. |
|||
|
|||
It allows organizing newsfeeds into nested folders, and supports an odd patchwork subset of Tiny Tiny RSS' full capabilities. The FeedReader extensions round out the protocol with significantly more features. Unlike with TT-RSS itself, API access is always enabled with The Arsse. |
|||
|
|||
# Missing features |
|||
|
|||
The Arsse does not currently support the entire protocol. Notably missing features include manipulation of the special "Published" newsfeed, as well as searching. The full list of missing features is as follows: |
|||
|
|||
- The `shareToPublished` operation is not implemented; it returns `UNKNOWN_METHOD` |
|||
- Setting an article's "published" flag with the `updateArticle` operation is not implemented and will gracefully fail |
|||
- The `sanitize`, `force_update`, and `has_sandbox` parameters of the `getHeadlines` operation are ignored |
|||
- String `feed_id` values for the `getCompactHeadlines` operation are not supported and will yield an `INCORRECT_USAGE` error |
|||
- Articles are limited to a single attachment rather than multiple attachments |
|||
- The `getPref` operation is not implemented; it returns `UNKNOWN_METHOD` |
|||
|
|||
# Differences |
|||
|
|||
- Input that cannot be parsed as JSON normally returns a `NOT_LOGGED_IN` error; The Arsse returns a non-standard `MALFORMED_INPUT` error instead |
|||
- Feed, category, and label names are normally unrestricted; The Arsse rejects empty strings, as well as strings composed solely of whitespace |
|||
- Discovering multiple feeds during `subscribeToFeed` processing normally produces an error; The Arsse instead chooses the first feed it finds |
|||
- Providing the `setArticleLabel` operation with an invalid label normally silently fails; The Arsse returns an `INVALID_USAGE` error instead |
|||
- Processing of the `search` parameter of the `getHeadlines` operation differs in the following ways: |
|||
- Values other than `"true"` or `"false"` for the `unread`, `star`, and `pub` special keywords treat the entire token as a search term rather than as `"false"` |
|||
- Invalid dates are ignored rather than assumed to be `"1970-01-01"` |
|||
- Specifying multiple non-negative dates usually returns no results as articles must match all specified dates simultaneously; The Arsse instead returns articles matching any of the specified dates |
|||
- Dates are always relative to UTC |
|||
- Full-text search is not yet employed with any database, including PostgreSQL |
|||
- Article hashes are normally SHA1; The Arsse uses SHA256 hashes |
|||
- Article attachments normally have unique IDs; The Arsse always gives attachments an ID of `"0"` |
|||
- The `getCounters` operation normally omits members with zero unread; The Arsse includes everything to appease some clients |
|||
|
|||
# Other notes |
|||
|
|||
- TT-RSS accepts base64-encoded passwords, though this is undocumented; The Arsse accepts base64-encoded passwords as well |
|||
- TT-RSS sometimes returns an incorrect count from the `setArticleLabel` operation; The Arsse returns a correct count in all cases |
|||
- TT-RSS sometimes returns out-of-date cached information; The Arsse does not use caches as TT-RSS does, so information is always current |
|||
- TT-RSS returns results for _feed_ ID `-3` when providing the `getHeadlines` operation with _category_ ID `-3`; The Arsse retuns the correct results |
|||
- The protocol doucmentation advises not to use `limit` or `skip` together with `unread_only` for the `getFeeds` operation as it produces unpredictable results; The Arsse produces predictable results by first retrieving all unread feeds and then applying `skip` and `limit` |
|||
- The protocol documentation on values for the `view_mode` parameter of the `getHeadlines` operation is out of date; The Arsse matches the actual implementation and supports the undocumented `published` and `has_note` values exposed by the Web user interface |
|||
- The protocol documentation makes mention of a `search_mode` parameter for the `getHeadlines` operation, but this seems to be ignored; The Arsse does not implement it |
|||
- The protocol documentation makes mention of an `output_mode` parameter for the `getCounters` operation, but this seems to be ignored; The Arsse does not implement it |
|||
- The documentation for the `getCompactHeadlines` operation states the default value for `limit` is 20, but the reference implementation defaults to unlimited; The Arsse also defaults to unlimited |
|||
- It is assumed TT-RSS exposes other undocumented behaviour; unless otherwise noted The Arsse only implements documented behaviour |
|||
|
|||
# Interaction with HTTP authentication |
|||
|
|||
Tiny Tiny RSS itself is unaware of HTTP authentication: if HTTP authentication is used in the server configuration, it has no effect on authentication in the API. The Arsse, however, makes use of HTTP authentication for Nextcloud News, and can do so for TT-RSS as well. In a default configuration The Arsse functions in the same way as TT-RSS: HTTP authentication and API authentication are completely separate and independent. Alternative behaviour is summarized below: |
|||
|
|||
- With default settings: |
|||
- Clients may optionally provide HTTP credentials |
|||
- API authentication proceeds as normal |
|||
- All feed icons are visible to unauthenticated clients |
|||
- Analogous to multi-user mode |
|||
- If the `userHTTPAuthRequired` setting is `true`: |
|||
- Clients must pass HTTP authentication |
|||
- API authentication proceeds as normal |
|||
- Feed icons are visible only to their owners |
|||
- Analoguous to multi-user mode with additional HTTP authentication |
|||
- If the `userSessionEnforced` setting is `false`: |
|||
- Clients may optionally provide HTTP credentials |
|||
- If HTTP authentication succeeded API authentication is skipped: tokens are issued upon login, but ignored for HTTP-authenticated requests |
|||
- All feed icons are visible to unauthenticated clients |
|||
- Analogous to single-user mode if using HTTP authentication, and to multi-user mode otherwise |
|||
- If the `userHTTPAuthRequired` setting is `true` and the `userSessionEnforced` setting is `false`: |
|||
- Clients must pass HTTP authentication |
|||
- API authentication is skipped: tokens are issued upon login, but thereafter ignored |
|||
- Feed icons are visible only to their owners |
|||
- Analogous to single-user mode |
|||
- If the `userPreAuth` setting is `true`: |
|||
- The Web server asserts HTTP authentication was successful |
|||
- API authentication only checks that HTTP and API user names match |
|||
- Feed icons are visible only to their owners |
|||
- Analoguous to multi-user mode with additional HTTP authentication |
|||
- If the `userPreAuth` setting is `true` and the `userSessionEnforced` setting is `false`: |
|||
- The Web server asserts HTTP authentication was successful |
|||
- API authentication is skipped: tokens are issued upon login, but thereafter ignored |
|||
- Feed icons are visible only to their owners |
|||
- Analogous to single-user mode |
|||
|
|||
In all cases, supplying invalid HTTP credentials will result in a 401 response. |
@ -0,0 +1,44 @@ |
|||
[TOC] |
|||
|
|||
# About |
|||
|
|||
<dl> |
|||
<dt>Supported since</dt> |
|||
<dd>0.8.0</dd> |
|||
<dt>Base URL</dt> |
|||
<dd>/fever/</dd> |
|||
<dt>API endpoint</dt> |
|||
<dd>/fever/?api</dd> |
|||
<dt>Specifications</dt> |
|||
<dd><a href="https://web.archive.org/web/20161217042229/https://feedafever.com/api">"Public beta"</a> (at the Internet Archive)</dd> |
|||
</dl> |
|||
|
|||
The Fever protocol is a basic protocol which has historically been popular with iOS and macOS clients. |
|||
|
|||
It allows marking articles as read or starred, but does not allow adding or modifying newsfeeds. Moreover, instead of being classified into folders, newfeeds may belong to multiple groups, which do not nest. |
|||
|
|||
# Missing features |
|||
|
|||
The Fever protocol is incomplete, unusual, _and_ a product of proprietary software which is no longer available. Conssequently some features have been omitted either out of necessity or because implementation details made the effort required too great. |
|||
|
|||
- All feeds are considered "Kindling" |
|||
- The "Hot Links" feature is not implemented; when requested, an empty array will be returned. As there is no way to classify a feed as a "Spark" in the protocol itself and no documentation exists on how link temperature was calculated, an implementation is unlikely to appear in the future |
|||
|
|||
# Special considerations |
|||
|
|||
- Because of Fever's unusual and insecure authentication scheme, a Fever-specific password [must be created](/en/Using_The_Arsse/Managing_Users) before a user can communicate via the Fever protocol |
|||
- The Fever protocol does not allow for adding or modifying feeds. Another protocol or OPML importing must be used to manage feeds |
|||
- Unlike other protocols supported by The Arsse, Fever uses "groups" (more commonly known as tags or labels) instead of folders to organize feeds. Currently [OPML importing](/en/Using_The_Arsse/Importing_and_Exporting) is the only means of managing groups |
|||
|
|||
# Other notes |
|||
|
|||
- The undocumented `group_ids`, `feed_ids`, and `as=unread` parameters are all supported |
|||
- XML output is supported, but may not behave as Fever did. Its use by clients is discouraged |
|||
|
|||
# Interaction with HTTP Authentication |
|||
|
|||
Fever was not designed with HTTP authentication in mind, and few clients respond to challenges. If the Web server or The Arsse is configured to require successful HTTP authentication, most Fever clients are not likely to be able to connect properly. |
|||
|
|||
# Interaction with Folders |
|||
|
|||
Unlike other protocols supported by The Arsse, Fever uses "groups" (more commonly known as tags or labels) to organize newsfeeds. These are fully supported and are exposed as categories in OPML import and export. They are treated separately from folders. |
@ -0,0 +1,8 @@ |
|||
The Arsse was designed from the start as a server for multiple synchronization protocols which clients can make use of. Currently the following protocols are supported: |
|||
|
|||
- [Miniflux](Miniflux) |
|||
- [Nextcloud News](Nextcloud_News) |
|||
- [Tiny Tiny RSS](Tiny_Tiny_RSS) |
|||
- [Fever](Fever) |
|||
|
|||
The protocols are merely different ways of accessing and manipulating the same data: subscribing to a newsfeed using one protocol will see the newsfeed also present when later connecting via another protocol, for example. Because not all protocols work according to the same concepts, however, sometimes the interactions between them are not obvious. These interactions are documented here when warranted. |
@ -0,0 +1,472 @@ |
|||
The Arsse does not at this time have any first party clients. However, because The Arsse [supports existing protocols](/en/Supported_Protocols), most clients built for these protocols are compatible with The Arsse. Below are those that we personally know of and have tested with The Arsse, presented in alphabetical order. |
|||
|
|||
<table class="clients"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="2">Name</th> |
|||
<th rowspan="2">OS</th> |
|||
<th colspan="4">Protocol</th> |
|||
<th rowspan="2">Notes</th> |
|||
</tr> |
|||
<tr> |
|||
<th>Miniflux</th> |
|||
<th>Nextcloud News</th> |
|||
<th>Tiny Tiny RSS</th> |
|||
<th>Fever</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<th colspan="7">Web</th> |
|||
<tr> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/yurikhan/miniflux-reader">Miniflux Reader</a></td> |
|||
<td></td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td>Functional, but has some display glitches.</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/jgerstbe/nx-news-ion">NX News</a></td> |
|||
<td></td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td>Extremely basic client.</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/reminiflux/reminiflux">reminiflux</a></td> |
|||
<td></td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Three-pane alternative front-end for Minflux. Does not include functionality for managing feeds. Requires token authentication.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/kucrut/ttrss-reader">Tiny Tiny RSS Reader</a></td> |
|||
<td></td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/TheScientist/ttrss-pwa">Tiny Tiny RSS Progressive Web App</a></td> |
|||
<td></td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Does not (<a href="https://github.com/TheScientist/ttrss-pwa/issues/7">yet</a>) support HTTP authentication. Does not include functionality for managing feeds.</p> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
<tbody> |
|||
<tr> |
|||
<th colspan="7">Desktop</th> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://jangernert.github.io/FeedReader/">FeedReader</a></td> |
|||
<td>Linux</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Excellent reader; discontinued in favour of NewsFlash.</p> |
|||
<p>Not compatible with HTTP authentication when using TT-RSS.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://lzone.de/liferea/">Liferea</a></td> |
|||
<td>Linux</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Not compatible with HTTP authentication.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://newsboat.org/">Newsboat</a></td> |
|||
<td>Linux, macOS</td> |
|||
<td class="Y">✔</td> |
|||
<td class="Y">✔</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Terminal-based client.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://gitlab.com/news-flash/news_flash_gtk">NewsFlash</a></td> |
|||
<td>Linux</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Successor to FeedReader. One of the best on any platform</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://reeder.app/">Reeder 3</a></td> |
|||
<td>macOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Also available for iOS. Reeder 5 no longer supports the Fever protocol.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/martinrotter/rssguard/">RSS Guard</a></td> |
|||
<td>Windows, macOS, Linux</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Very basic client.</p> |
|||
</td> |
|||
</tr> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://bitbucket.org/thescientist/tiny-tiny-rss-wp8-client/src/master/">Tiny Tiny RSS Reader</td> |
|||
<td>Windows</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Does not deal well with expired sessions; discontinued.</p> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
<tbody> |
|||
<tr> |
|||
<th colspan="7">Mobile</th> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://peterandlinda.com/cloudnews/">CloudNews</a></td> |
|||
<td>iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Very bland looking application, but it functions well.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://play.google.com/store/apps/details?id=com.seazon.feedme">FeedMe</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Not compatible with HTTP authentication.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="http://cocoacake.net/apps/fiery/">Fiery Feeds</a></td> |
|||
<td>iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Rentalware - For the software to be usable (you can't even add feeds otherwise) a subscription fee must be paid.</p> |
|||
<p>Support HTTP authentication with Fever.</p> |
|||
<p>Currently keeps showing items in the unread badge which have already been read.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/fbarthelery/geekttrss">Geekttrss</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://play.google.com/store/apps/details?id=com.constantin.microflux">Microflux for Miniflux</a></td> |
|||
<td>Android</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://play.google.com/store/apps/details?id=mobi.newsjet.rss">NewsJet RSS</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/SimonSchubert/NewsOut">Newsout</a></td> |
|||
<td>Android, iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>iOS version only as source code.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/nextcloud/news-android/">Nextcloud News</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Official Android client for Nextcloud News.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/schaal/ocreader/">OCReader</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://play.google.com/store/apps/details?id=com.isaiasmatewos.readably">Readably</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Fetches favicons independently.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/readrops/Readrops">Readrops</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td></td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/ali322/reed">Reed</a></td> |
|||
<td>Android</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Binaries only available from GitHub.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://reeder.app/">Reeder</a></td> |
|||
<td>iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Also available for macOS.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="http://tt-rss.org/">Tiny Tiny RSS</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Official Android client for Tiny Tiny RSS.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="http://github.com/nilsbraden/ttrss-reader-fork/">TTRSS-Reader</a></td> |
|||
<td>Android</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://www.goldenhillsoftware.com/unread/">Unread</a></td> |
|||
<td>iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Trialware with one-time purchase.</p> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
|
|||
## Untested clients |
|||
|
|||
<table class="clients"> |
|||
<thead> |
|||
<tr> |
|||
<th rowspan="2">Name</th> |
|||
<th rowspan="2">OS</th> |
|||
<th colspan="4">Protocol</th> |
|||
<th rowspan="2">Notes</th> |
|||
</tr> |
|||
<tr> |
|||
<th>Miniflux</th> |
|||
<th>Nextcloud News</th> |
|||
<th>Tiny Tiny RSS</th> |
|||
<th>Fever</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr> |
|||
<td><a href="https://github.com/jeena/feedthemonkey">FeedTheMonkey</a></td> |
|||
<td>Linux</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/Huessenbergnetz/Fuoten">Fuoten</a></td> |
|||
<td>Sailfish</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/mkiol/kaktus">Kaktus</a></td> |
|||
<td>Sailfish, BlackBerry</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
<!-- |
|||
<tr> |
|||
<td><a href="https://github.com/fabienheureux/liseur">Liseur</a></td> |
|||
<td>Windows?</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Level of functionality unclear.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/jakobend/maxiflux">maxiflux</a></td> |
|||
<td>Web</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td>Level of functionality unclear.</td> |
|||
</tr> |
|||
--> |
|||
<tr> |
|||
<td><a href="https://github.com/DocMarty84/miniflutt">Miniflutt</a></td> |
|||
<td>Android</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td>Does not display articles (<a href="https://github.com/DocMarty84/miniflutt/issues/3">see bug</a>)</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://open-store.io/app/newsie.martinferretti">Newsie</a></td> |
|||
<td>Ubuntu Touch</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://readkitapp.com/">ReadKit</a></td> |
|||
<td>macOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Requires purchase. Presumed to work.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/matoung/SparkReader">SparkReader</a></td> |
|||
<td>Windows</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td> |
|||
<p>Requires manual configuration.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="http://www.pluchon.com/en/tiny_reader_rss.php">tiny Reader RSS</a></td> |
|||
<td>iOS</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p>Does not support HTTP authentication.</p> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><a href="https://github.com/cnlpete/ttrss">ttrss</a></td> |
|||
<td>Sailfish</td> |
|||
<td class="N">✘</td> |
|||
<td class="N">✘</td> |
|||
<td class="Y">✔</td> |
|||
<td class="N">✘</td> |
|||
<td> |
|||
<p></p> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
@ -0,0 +1 @@ |
|||
Welcome to the user manual for The Advanced RSS Environment. It is included with each copy of the software, and is also [available online](https://thearsse.com/manual/en/). Please select a language above. |
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@ |
|||
{ |
|||
"favicon": "<theme_url>favicon.png", |
|||
"js": [ |
|||
"<theme_url>daux.min.js" |
|||
], |
|||
"css": [ |
|||
"<theme_url>arsse.css" |
|||
] |
|||
} |
@ -0,0 +1,2 @@ |
|||
var e=document.querySelectorAll(".s-content pre"),t=document.querySelector(".CodeToggler"),n="daux_code_blocks_hidden";function a(t){for(var a=0;a<e.length;a++)e[a].classList.toggle("Hidden",t);try{localStorage.setItem(n,t)}catch(e){}}t&&(e.length?function(){var e=t.querySelector(".CodeToggler__button--main");e.addEventListener("change",(function(e){a(!e.target.checked)}),!1);var r=!1;try{"false"===(r=localStorage.getItem(n))?r=!1:"true"===r&&(r=!0),r&&(a(!!r),e.checked=!r)}catch(e){}}():t.classList.add("Hidden"));var r=document.querySelector(".Collapsible__trigger");if(r){var o=document.querySelector(".Collapsible__content");r.addEventListener("click",(function(e){o.classList.contains("Collapsible__content--open")?(o.style.height=0,o.classList.remove("Collapsible__content--open"),r.setAttribute("aria-expanded","false")):(r.setAttribute("aria-expanded","true"),o.style.transitionDuration="150ms",o.style.height="".concat(o.scrollHeight,"px"),o.classList.add("Collapsible__content--open"))}))}var l=document.querySelectorAll("pre > code:not(.hljs)");if(l.length){var i=document.getElementsByTagName("head")[0],c=document.createElement("script");c.type="text/javascript",c.async=!0,c.src="".concat(window.base_url,"daux_libraries/highlight.pack.js"),c.onload=function(e){[].forEach.call(l,window.hljs.highlightBlock)},i.appendChild(c)}function s(e){var t=void 0!==e.preventDefault;t&&e.preventDefault();var n=function(e){for(var t=e;(t=t.parentNode)&&9!==t.nodeType;)if(1===t.nodeType&&t.classList.contains("Nav__item"))return t;throw new Error("Could not find a NavItem...")}(e.target),a=n.querySelector("ul.Nav");t&&n.classList.contains("Nav__item--open")?(a.style.height="".concat(a.scrollHeight,"px"),a.style.transitionDuration="150ms",a.style.height="0px",n.classList.remove("Nav__item--open")):t?(a.style.transitionDuration="150ms",a.addEventListener("transitionend",(function e(t){"0px"!==t.target.style.height&&(t.target.style.height="auto"),t.target.removeEventListener("transitionend",e)})),a.style.height="".concat(a.scrollHeight,"px"),n.classList.add("Nav__item--open")):a.style.height="auto"}for(var d,u=document.querySelectorAll(".Nav__item.has-children i.Nav__arrow"),h=u.length-1;h>=0;h--)(d=u[h]).addEventListener("click",s),d.parentNode.parentNode.classList.contains("Nav__item--open")&&s({target:d});var g=document.querySelectorAll(".Nav__item__link--nopage"),v=!0,p=!1,_=void 0;try{for(var y,m=g[Symbol.iterator]();!(v=(y=m.next()).done);v=!0){y.value.addEventListener("click",s)}}catch(e){p=!0,_=e}finally{try{v||null==m.return||m.return()}finally{if(p)throw _}} |
|||
//# sourceMappingURL=daux.min.js.map
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,328 @@ |
|||
/* Daux imports; fonts are omitted */ |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/vendor/normalize.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_variables.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_mixins.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_structure.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_typography.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_components.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_homepage.scss"; |
|||
@import "../../../vendor-bin/daux/vendor/daux/daux.io/src/css/theme_daux/_print.scss" print; |
|||
|
|||
|
|||
|
|||
/* The Arsse overrides */ |
|||
|
|||
@font-face { |
|||
font-family: 'League Gothic'; |
|||
src: url('fonts/leaguegothic.woff2') format('woff2'), |
|||
url('fonts/leaguegothic.woff') format('woff'); |
|||
font-style: normal; |
|||
font-display: swap; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: 'Cabin'; |
|||
src: url('fonts/cabin-regular.woff2') format('woff2'), |
|||
url('fonts/cabin-regular.woff') format('woff'); |
|||
font-weight: normal; |
|||
font-style: normal; |
|||
font-display: swap; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: 'Cabin'; |
|||
src: url('fonts/cabin-italic.woff2') format('woff2'), |
|||
url('fonts/cabin-italic.woff') format('woff'); |
|||
font-style: italic; |
|||
font-display: swap; |
|||
} |
|||
|
|||
@font-face { |
|||
font-family: 'Cabin'; |
|||
src: url('fonts/cabin-bold.woff2') format('woff2'), |
|||
url('fonts/cabin-bold.woff') format('woff'); |
|||
font-weight: bold; |
|||
font-style: normal; |
|||
font-display: swap; |
|||
} |
|||
|
|||
|
|||
:root { |
|||
--font-family-text: "Cabin", "Trebuchet MS", -apple-system, ".SFNSText-Regular", "San Francisco", |
|||
"Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", Arial, |
|||
sans-serif; |
|||
--font-family-monospace: Monaco, Menlo, Consolas, "Lucida Console", |
|||
"Courier New", monospace; |
|||
--font-family-heading: "League Gothic", -apple-system, ".SFNSText-Regular", "San Francisco", |
|||
"Roboto", "Segoe UI", "Helvetica Neue", "Lucida Grande", Arial, |
|||
sans-serif; |
|||
|
|||
--type-size-1: 4rem; |
|||
--type-size-2: 3.236rem; |
|||
--type-size-3: 2.618rem; |
|||
--type-size-4: 2rem; |
|||
--type-size-5: 1.618rem; |
|||
--type-size-6: 1.309rem; |
|||
|
|||
--red: #e63c2f; |
|||
--blue: #15284b; |
|||
--light-blue: #93b7bb; |
|||
--beige: #e8d5d3; |
|||
--green: #2c9a42; |
|||
|
|||
--dark-gray: color(var(--beige) blend(var(--blue) 50%)); |
|||
--gray: color(var(--beige) blend(var(--blue) 25%)); |
|||
--light-gray: color(var(--beige) blend(var(--blue) 12.5%)); |
|||
--lighter-gray: var(--beige); |
|||
--lightest-gray: color(var(--beige) blend(#fff 75%)); |
|||
|
|||
--dark: var(--blue); |
|||
--light: var(--light-blue); |
|||
|
|||
--sidebar-background: var(--beige); |
|||
--sidebar-link-active-background: var(--light-blue); |
|||
--sidebar-collapsible--hamburger-color: var(--beige); |
|||
|
|||
--text: var(--blue); |
|||
--link-color: var(--red); |
|||
--brand-color: var(--blue); |
|||
--brand-background: var(--red); |
|||
|
|||
--code-tag-background-color: var(--lightest-gray); |
|||
--code-tag-border-radius: 0; |
|||
--code-tag-box-shadow: none; |
|||
|
|||
--homepage-navbar-background: var(--red); |
|||
--hero-button-block-background: var(--beige); |
|||
--homepage-hero-background: #fff; |
|||
--content-floating-blocks-background: var(--blue); |
|||
} |
|||
|
|||
body { |
|||
line-height: 1.618; |
|||
} |
|||
|
|||
a.Link--external::after { |
|||
content: ''; |
|||
} |
|||
|
|||
.s-content { |
|||
code { |
|||
display: inline-block; |
|||
padding-top: 0; |
|||
padding-bottom: 0; |
|||
padding: 0.5ch; |
|||
border: 0; |
|||
|
|||
&::before, &::after { |
|||
content: ''; |
|||
} |
|||
|
|||
pre & { |
|||
display: inline; |
|||
} |
|||
} |
|||
|
|||
table { |
|||
border-collapse: separate; |
|||
border-spacing: 2px; |
|||
border: 2px solid var(--gray); |
|||
|
|||
thead, tbody { |
|||
background-color: #fff; |
|||
} |
|||
|
|||
tr { |
|||
border-top: 0; |
|||
|
|||
&:nth-child(2n) { |
|||
background-color: transparent; |
|||
|
|||
td { |
|||
background-color: var(--lightest-gray); |
|||
} |
|||
} |
|||
} |
|||
|
|||
th, td { |
|||
border: 0; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.s-content table, .Nav__item .Nav__item { |
|||
font-size: 1rem; |
|||
} |
|||
|
|||
.Brand, h1, h2, h3, h4, h5, h6 { |
|||
font-weight: normal; |
|||
} |
|||
|
|||
.Button { |
|||
border-radius: 0; |
|||
} |
|||
|
|||
.HomepageButtons .Button--hero { |
|||
font-weight: normal; |
|||
font-size: var(--type-size-6); |
|||
} |
|||
|
|||
.Page__header { |
|||
border-bottom: 2px solid var(--lighter-gray); |
|||
} |
|||
|
|||
.Pager li > a { |
|||
border: 2px solid var(--lighter-gray); |
|||
border-radius: 0; |
|||
|
|||
&:hover, &:focus { |
|||
background-color: var(--lighter-gray); |
|||
} |
|||
} |
|||
|
|||
.Pager--prev a::before { |
|||
content: "\2190\00a0"; |
|||
} |
|||
.Pager--next a::after { |
|||
content: "\00a0\2192"; |
|||
} |
|||
|
|||
.Navbar { |
|||
height: auto; |
|||
box-shadow: none; |
|||
|
|||
.Brand { |
|||
float: none; |
|||
line-height: inherit; |
|||
height: auto; |
|||
} |
|||
} |
|||
|
|||
.Homepage { |
|||
padding-top: 10px !important; |
|||
} |
|||
|
|||
.Nav__item { |
|||
font-size: var(--type-size-6); |
|||
} |
|||
|
|||
.Nav__arrow:before, .Nav .Nav .Nav__item a .Nav__arrow:before { |
|||
font-family: var(--font-family-heading); |
|||
width: 1ch; |
|||
height: 1ch; |
|||
} |
|||
|
|||
.TableOfContentsContainer__title { |
|||
border-bottom: 4px solid var(--lighter-gray); |
|||
} |
|||
|
|||
ul.TableOfContents { |
|||
border-left: 6px solid var(--lighter-gray); |
|||
} |
|||
|
|||
.Columns__right--full .TableOfContentsContainer { |
|||
.TableOfContentsContainer__content > .TableOfContents { |
|||
border-right: 2px solid var(--lighter-gray); |
|||
} |
|||
|
|||
a { |
|||
border-bottom: 1px solid var(--lighter-gray); |
|||
} |
|||
} |
|||
|
|||
.clients { |
|||
thead tr:first-child th { |
|||
text-align: left; |
|||
|
|||
&:first-child { |
|||
width: 15%; |
|||
} |
|||
|
|||
&:nth-child(3) { |
|||
width: 50%; |
|||
text-align: center; |
|||
} |
|||
} |
|||
|
|||
thead tr + tr th { |
|||
width: 12%; |
|||
text-align: center; |
|||
} |
|||
|
|||
tbody td { |
|||
&:nth-child(3), &:nth-child(4), &:nth-child(5), &:nth-child(6) { |
|||
text-align: center; |
|||
} |
|||
|
|||
&.Y { |
|||
color: var(--green); |
|||
} |
|||
|
|||
&.N { |
|||
color: var(--red); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.hljs, .s-content pre { |
|||
background: var(--blue); |
|||
color: var(--beige); |
|||
} |
|||
|
|||
.hljs { |
|||
display: block; |
|||
overflow-x: auto; |
|||
padding: 0.5em; |
|||
} |
|||
|
|||
.hljs-emphasis { |
|||
font-style: italic; |
|||
} |
|||
|
|||
.hljs-strong { |
|||
font-weight: bold; |
|||
} |
|||
|
|||
.hljs-comment, .hljs-quote { |
|||
color: #978e9c; |
|||
} |
|||
|
|||
/* Green */ |
|||
.hljs-keyword, .hljs-selector-tag, .hljs-addition { |
|||
color: #acb39a; |
|||
} |
|||
|
|||
/* Cyan */ |
|||
.hljs-number, .hljs-string, .hljs-meta .hljs-meta-string, .hljs-literal, .hljs-doctag, .hljs-regexp { |
|||
color: var(--light-blue); |
|||
} |
|||
|
|||
/* Blue */ |
|||
.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class { |
|||
color: #82b7e5; |
|||
} |
|||
|
|||
/* Yellow */ |
|||
.hljs-attribute, .hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-class .hljs-title, .hljs-type { |
|||
color: #c5b031; |
|||
} |
|||
|
|||
/* Orange */ |
|||
.hljs-symbol, .hljs-bullet, .hljs-subst, .hljs-meta, .hljs-meta .hljs-keyword, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-link { |
|||
color: #ea8031; |
|||
} |
|||
|
|||
/* Red */ |
|||
.hljs-built_in, .hljs-deletion { |
|||
color: var(--red); |
|||
} |
|||
|
|||
.hljs-formula { |
|||
background: #686986; |
|||
} |
|||
|
|||
@media (--viewport-large) { |
|||
.Columns__left { |
|||
border: 0; |
|||
} |
|||
} |
@ -0,0 +1,28 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse\Context; |
|||
|
|||
abstract class AbstractContext { |
|||
protected $props = []; |
|||
protected $parent = null; |
|||
|
|||
protected function act(string $prop, int $set, $value) { |
|||
if ($set) { |
|||
if (is_null($value)) { |
|||
unset($this->props[$prop]); |
|||
$this->$prop = (new \ReflectionClass($this))->getDefaultProperties()[$prop]; |
|||
} else { |
|||
$this->props[$prop] = true; |
|||
$this->$prop = $value; |
|||
} |
|||
return $this->parent ?? $this; |
|||
} else { |
|||
return isset($this->props[$prop]); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse\Context; |
|||
|
|||
trait BooleanMembers { |
|||
public $unread = null; |
|||
public $starred = null; |
|||
public $hidden = null; |
|||
public $labelled = null; |
|||
public $annotated = null; |
|||
|
|||
public function unread(bool $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function starred(bool $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function hidden(bool $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function labelled(bool $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function annotated(bool $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
} |
@ -0,0 +1,262 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse\Context; |
|||
|
|||
use JKingWeb\Arsse\Misc\ValueInfo; |
|||
use JKingWeb\Arsse\Misc\Date; |
|||
|
|||
trait ExclusionMembers { |
|||
public $folder = null; |
|||
public $folders = []; |
|||
public $folderShallow = null; |
|||
public $foldersShallow = []; |
|||
public $tag = null; |
|||
public $tags = []; |
|||
public $tagName = null; |
|||
public $tagNames = []; |
|||
public $subscription = null; |
|||
public $subscriptions = []; |
|||
public $edition = null; |
|||
public $editions = []; |
|||
public $article = null; |
|||
public $articles = []; |
|||
public $label = null; |
|||
public $labels = []; |
|||
public $labelName = null; |
|||
public $labelNames = []; |
|||
public $annotationTerms = []; |
|||
public $searchTerms = []; |
|||
public $titleTerms = []; |
|||
public $authorTerms = []; |
|||
public $articleRange = [null, null]; |
|||
public $editionRange = [null, null]; |
|||
public $modifiedRange = [null, null]; |
|||
public $modifiedRanges = []; |
|||
public $markedRange = [null, null]; |
|||
public $markedRanges = []; |
|||
|
|||
protected function cleanIdArray(array $spec, bool $allowZero = false): array { |
|||
$spec = array_values($spec); |
|||
for ($a = 0; $a < sizeof($spec); $a++) { |
|||
if (ValueInfo::id($spec[$a], $allowZero)) { |
|||
$spec[$a] = (int) $spec[$a]; |
|||
} else { |
|||
$spec[$a] = null; |
|||
} |
|||
} |
|||
return array_values(array_unique(array_filter($spec, function($v) { |
|||
return !is_null($v); |
|||
}))); |
|||
} |
|||
|
|||
protected function cleanStringArray(array $spec): array { |
|||
$spec = array_values($spec); |
|||
$stop = sizeof($spec); |
|||
for ($a = 0; $a < $stop; $a++) { |
|||
if (strlen($str = ValueInfo::normalize($spec[$a], ValueInfo::T_STRING | ValueInfo::M_DROP) ?? "")) { |
|||
$spec[$a] = $str; |
|||
} else { |
|||
unset($spec[$a]); |
|||
} |
|||
} |
|||
return array_values(array_unique($spec)); |
|||
} |
|||
|
|||
protected function cleanDateRangeArray(array $spec): array { |
|||
$spec = array_values($spec); |
|||
$stop = sizeof($spec); |
|||
for ($a = 0; $a < $stop; $a++) { |
|||
if (!is_array($spec[$a]) || sizeof($spec[$a]) !== 2) { |
|||
unset($spec[$a]); |
|||
} else { |
|||
$spec[$a] = ValueInfo::normalize($spec[$a], ValueInfo::T_DATE | ValueInfo::M_ARRAY | ValueInfo::M_DROP); |
|||
if ($spec[$a] === [null, null]) { |
|||
unset($spec[$a]); |
|||
} |
|||
} |
|||
} |
|||
return array_values(array_unique($spec, \SORT_REGULAR)); |
|||
} |
|||
|
|||
public function folder(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function folders(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec, true); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function folderShallow(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function foldersShallow(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec, true); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function tag(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function tags(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function tagName(string $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function tagNames(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function subscription(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function subscriptions(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function edition(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function article(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function editions(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function articles(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function label(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function labels(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanIdArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function labelName(string $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function labelNames(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function annotationTerms(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function searchTerms(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function titleTerms(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function authorTerms(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanStringArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function articleRange(?int $start = null, ?int $end = null) { |
|||
if ($start === null && $end === null) { |
|||
$spec = null; |
|||
} else { |
|||
$spec = [$start, $end]; |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function editionRange(?int $start = null, ?int $end = null) { |
|||
if ($start === null && $end === null) { |
|||
$spec = null; |
|||
} else { |
|||
$spec = [$start, $end]; |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function modifiedRange($start = null, $end = null) { |
|||
if ($start === null && $end === null) { |
|||
$spec = null; |
|||
} else { |
|||
$spec = [Date::normalize($start), Date::normalize($end)]; |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function modifiedRanges(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanDateRangeArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function markedRange($start = null, $end = null) { |
|||
if ($start === null && $end === null) { |
|||
$spec = null; |
|||
} else { |
|||
$spec = [Date::normalize($start), Date::normalize($end)]; |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function markedRanges(array $spec = null) { |
|||
if (isset($spec)) { |
|||
$spec = $this->cleanDateRangeArray($spec); |
|||
} |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse\Context; |
|||
|
|||
abstract class RootContext extends AbstractContext { |
|||
public $limit = 0; |
|||
public $offset = 0; |
|||
|
|||
public function limit(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
|
|||
public function offset(int $spec = null) { |
|||
return $this->act(__FUNCTION__, func_num_args(), $spec); |
|||
} |
|||
} |
@ -0,0 +1,51 @@ |
|||
<?php |
|||
/** @license MIT |
|||
* Copyright 2017 J. King, Dustin Wilson et al. |
|||
* See LICENSE and AUTHORS files for details */ |
|||
|
|||
declare(strict_types=1); |
|||
|
|||
namespace JKingWeb\Arsse\Context; |
|||
|
|||
class UnionContext extends RootContext implements \ArrayAccess, \Countable, \IteratorAggregate { |
|||
protected $contexts = []; |
|||
|
|||
#[\ReturnTypeWillChange] |
|||
public function offsetExists($offset) { |
|||
return isset($this->contexts[$offset]); |
|||
} |
|||
|
|||
#[\ReturnTypeWillChange] |
|||
public function offsetGet($offset) { |
|||
return $this->contexts[$offset] ?? null; |
|||
} |
|||
|
|||
#[\ReturnTypeWillChange] |
|||
public function offsetSet($offset, $value) { |
|||
assert($value instanceof RootContext, new \Exception("Union contexts may only contain other non-exclusion contexts")); |
|||
if (isset($offset)) { |
|||
$this->contexts[$offset] = $value; |
|||
} else { |
|||
$this->contexts[] = $value; |
|||
} |
|||
} |
|||
|
|||
#[\ReturnTypeWillChange] |
|||
public function offsetUnset($offset) { |
|||
unset($this->contexts[$offset]); |
|||
} |
|||
|
|||
public function count(): int { |
|||
return count($this->contexts); |
|||
} |
|||
|
|||
public function getIterator(): \Traversable { |
|||
foreach ($this->contexts as $k => $c) { |
|||
yield $k => $c; |
|||
} |
|||
} |
|||
|
|||
public function __construct(RootContext ...$context) { |
|||
$this->contexts = $context; |
|||
} |
|||
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue