Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
703b078
i18n WIP
NotsoanoNimus Jul 25, 2024
a121868
i18n WIP
NotsoanoNimus Jul 25, 2024
9d68b50
[i18n] make bridge languages dynamic if elected
NotsoanoNimus Jul 25, 2024
7d4c9c5
[CryptomeBridge] i18n of some bridge properties
NotsoanoNimus Jul 25, 2024
dc3d007
[i18n] Refactor library and add magic
NotsoanoNimus Jul 25, 2024
3698b2f
[GBAtemp] Fix title extraction (#4151)
ORelio Jul 28, 2024
1551d42
[GithubTrendingBridge] Add support for spoken languages (#4149)
tillcash Jul 28, 2024
0f22c82
[NovayaGazetaEuropeBridge]: fix warnings (#4154)
mazzz1y Jul 28, 2024
15885aa
[HardwareInfoBridge] delete bridge for discontinued website (#4124)
t0stiman Jul 28, 2024
a71526c
[Mailman2Bridge] fix message separation and improve "From_ lines" dis…
enwuenwu Jul 28, 2024
bfd7a95
[AnisearchBridge.php] fixed youtube link (#4159)
Tone866 Jul 28, 2024
726d24c
[RutubeBridge] New option to fetch video from search results (#4162)
em92 Jul 28, 2024
8199677
[Vk2Bridge] Handling albums (#4163)
em92 Jul 28, 2024
3451395
[EconomistWorldInBriefBridge] Add cookie to options (#4165)
SqrtMinusOne Jul 28, 2024
fcabaf8
fix bulletpoints for nordbayern (#4166)
theScrabi Jul 28, 2024
85023da
fix(reddit): increase default cache ttl (#4168)
dvikan Jul 28, 2024
c67a41f
[RumbleBridge] Facelift, Validation, & Livestreams (#4160)
NotsoanoNimus Jul 29, 2024
c16ae93
[EBayBridge] Repair & Augment the eBay Feed (#4157)
NotsoanoNimus Jul 29, 2024
d1e1e5d
[ARDMediathekBridge] fixing API URL, start using show title (#4170) (…
Mar-Koeh Jul 30, 2024
e6540d8
[EconomistBridge] Add cookie (#4173)
SqrtMinusOne Jul 30, 2024
df5da21
refactor: return proper response object (#4169)
dvikan Jul 31, 2024
1df7bb3
[EBayBridge] fix undefined vars errors (#4175)
NotsoanoNimus Jul 31, 2024
417ff98
fix: convert php errors to exceptions when in debug mode (#4176)
dvikan Jul 31, 2024
72f817a
feat: enable all bridges by default (#4177)
dvikan Jul 31, 2024
7780479
fix(FeedParser): scrape out content from rss content:encoded (#4178)
dvikan Jul 31, 2024
6a613a7
fix: bug in prior refactor (#4179)
dvikan Jul 31, 2024
78e6a76
fix(FeedParser): dont emit content module (#4180)
dvikan Jul 31, 2024
a92f986
[SubstackBridge] Add Substack bridge (#4174)
SqrtMinusOne Jul 31, 2024
4255d1b
fix: improve github issue template (#4181)
dvikan Jul 31, 2024
ac723e7
[AnisearchBridge] fixed typo (#4182)
Tone866 Aug 1, 2024
4fe5068
docs: improve docker docs (#4183)
dvikan Aug 1, 2024
44059f5
[RutubeBridge] Fix playlist mode returning empty result (#4184)
em92 Aug 2, 2024
3cf268e
yuop (#4193)
dvikan Aug 6, 2024
355786f
Catch up to latest master branch
NotsoanoNimus Aug 8, 2024
7a0ea28
replace self:: with -> for methodcalls in Nordbayern bridge (#4195)
theScrabi Aug 7, 2024
cbcd3ef
fix: restore php error_log writing (#4196)
dvikan Aug 7, 2024
fcf4b3e
fix: bug in prior refactor (#4197)
dvikan Aug 7, 2024
5e33cb3
add NurembergerNachrichten bridge (#4185)
theScrabi Aug 7, 2024
01b7740
[TldrTechBridge] Fix bridge (#4187)
SqrtMinusOne Aug 7, 2024
6f252d7
[CentreFranceBridge] Add bridge (#4189)
quent1-fr Aug 7, 2024
cfca018
[BodaccBridge] Add bridge (#4190)
quent1-fr Aug 7, 2024
975ad16
[AnfrBridge] Add bridge (#4191)
quent1-fr Aug 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ config/*
!config/nginx.conf
!config/php-fpm.conf
!config/php.ini
docker-compose.*

######################
## VisualStudioCode ##
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
* [Niehztog](https://github.com/Niehztog)
* [NikNikYkt](https://github.com/NikNikYkt)
* [Nono-m0le](https://github.com/Nono-m0le)
* [NotsoanoNimus](https://github.com/NotsoanoNimus)
* [obsiwitch](https://github.com/obsiwitch)
* [Ololbu](https://github.com/Ololbu)
* [ORelio](https://github.com/ORelio)
Expand Down
65 changes: 44 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,10 @@ Requires minimum PHP 7.4.

### How to install on traditional shared web hosting

RSS-Bridge can basically be unzipped in a web folder. Should be working instantly.
RSS-Bridge can basically be unzipped into a web folder. Should be working instantly.

Latest zip as of Sep 2023: https://github.com/RSS-Bridge/rss-bridge/archive/refs/tags/2023-09-24.zip
Latest zip:
https://github.com/RSS-Bridge/rss-bridge/archive/refs/heads/master.zip (2MB)

### How to install on Debian 12 (nginx + php-fpm)

Expand All @@ -66,7 +67,7 @@ timedatectl set-timezone Europe/Oslo

apt install git nginx php8.2-fpm php-mbstring php-simplexml php-curl php-intl

# Create a new user account
# Create a user account
useradd --shell /bin/bash --create-home rss-bridge

cd /var/www
Expand Down Expand Up @@ -101,7 +102,10 @@ Nginx config:

server {
listen 80;

# TODO: change to your own server name
server_name example.com;

access_log /var/log/nginx/rss-bridge.access.log;
error_log /var/log/nginx/rss-bridge.error.log;
log_not_found off;
Expand Down Expand Up @@ -150,8 +154,11 @@ listen = /run/php/rss-bridge.sock
listen.owner = www-data
listen.group = www-data

# Create 10 workers standing by to serve requests
pm = static
pm.max_children = 10

# Respawn worker after 500 requests (workaround for memory leaks etc.)
pm.max_requests = 500
```

Expand Down Expand Up @@ -179,7 +186,7 @@ Install the latest release.

```shell
cd /var/www
composer create-project -v --no-dev rss-bridge/rss-bridge
composer create-project -v --no-dev --no-scripts rss-bridge/rss-bridge
```

### How to install with Caddy
Expand All @@ -192,8 +199,16 @@ Install by downloading the docker image from Docker Hub:

```bash
# Create container
docker create --name=rss-bridge --publish 3000:80 rssbridge/rss-bridge
docker create --name=rss-bridge --publish 3000:80 --volume $(pwd)/config:/config rssbridge/rss-bridge
```

You can put custom `config.ini.php` and bridges into `./config`.

**You must restart container for custom changes to take effect.**

See `docker-entrypoint.sh` for details.

```bash
# Start container
docker start rss-bridge
```
Expand All @@ -207,30 +222,29 @@ Browse http://localhost:3000/
docker build -t rss-bridge .

# Create container
docker create --name rss-bridge --publish 3000:80 rss-bridge
docker create --name rss-bridge --publish 3000:80 --volume $(pwd)/config:/config rss-bridge
```

You can put custom `config.ini.php` and bridges into `./config`.

**You must restart container for custom changes to take effect.**

See `docker-entrypoint.sh` for details.

```bash
# Start container
docker start rss-bridge
```

Browse http://localhost:3000/

### Install with docker-compose

Create a `docker-compose.yml` file locally with with the following content:
```yml
version: '2'
services:
rss-bridge:
image: rssbridge/rss-bridge:latest
volumes:
- </local/custom/path>:/config
ports:
- 3000:80
restart: unless-stopped
```
### Install with docker-compose (using Docker Hub)

You can put custom `config.ini.php` and bridges into `./config`.

**You must restart container for custom changes to take effect.**

Then launch with `docker-compose`:
See `docker-entrypoint.sh` for details.

```bash
docker-compose up
Expand Down Expand Up @@ -418,7 +432,16 @@ See `formats/PlaintextFormat.php` for an example.

These commands require that you have installed the dev dependencies in `composer.json`.

Run all tests:

./vendor/bin/phpunit

Run a single test class:

./vendor/bin/phpunit --filter UrlTest

Run linter:

./vendor/bin/phpcs --standard=phpcs.xml --warning-severity=0 --extensions=php -p ./

https://github.com/squizlabs/PHP_CodeSniffer/wiki
Expand Down
14 changes: 7 additions & 7 deletions actions/ConnectivityAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ public function __construct()
$this->bridgeFactory = new BridgeFactory();
}

public function execute(Request $request)
public function __invoke(Request $request): Response
{
if (!Debug::isEnabled()) {
return new Response('This action is only available in debug mode!', 403);
return new Response(xlat('errors:actions:display:debug_required'), 403);
}

$bridgeName = $request->get('bridge');
if (!$bridgeName) {
return render_template('connectivity.html.php');
return new Response(render_template('connectivity.html.php'));
}
$bridgeClassName = $this->bridgeFactory->createBridgeClassName($bridgeName);
if (!$bridgeClassName) {
return new Response('Bridge not found', 404);
return new Response(xlat('errors:general:not_found'), 404);
}
return $this->reportBridgeConnectivity($bridgeClassName);
}

private function reportBridgeConnectivity($bridgeClassName)
{
if (!$this->bridgeFactory->isEnabled($bridgeClassName)) {
throw new \Exception('Bridge is not whitelisted!');
throw new \Exception(xlat('errors:general:whitelist'));
}

$bridge = $this->bridgeFactory->create($bridgeClassName);
Expand All @@ -54,8 +54,8 @@ private function reportBridgeConnectivity($bridgeClassName)
];
try {
$response = getContents($bridge::URI, [], $curl_opts, true);
$result['http_code'] = $response['code'];
if (in_array($response['code'], [200])) {
$result['http_code'] = $response->getCode();
if (in_array($result['http_code'], [200])) {
$result['successful'] = true;
}
} catch (\Exception $e) {
Expand Down
8 changes: 4 additions & 4 deletions actions/DetectAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

class DetectAction implements ActionInterface
{
public function execute(Request $request)
public function __invoke(Request $request): Response
{
$url = $request->get('url');
$format = $request->get('format');

if (!$url) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'You must specify a url']));
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:specify_url')]));
}
if (!$format) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'You must specify a format']));
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:specify_format')]));
}

$bridgeFactory = new BridgeFactory();
Expand Down Expand Up @@ -39,7 +39,7 @@ public function execute(Request $request)
}

return new Response(render(__DIR__ . '/../templates/error.html.php', [
'message' => 'No bridge found for given URL: ' . $url,
'message' => xlat('errors:general:not_found_for_url') . ': ' . $url,
]));
}
}
41 changes: 26 additions & 15 deletions actions/DisplayAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public function __construct()
$this->logger = RssBridge::getLogger();
}

public function execute(Request $request)
public function __invoke(Request $request): Response
{
$bridgeName = $request->get('bridge');
$format = $request->get('format');
Expand All @@ -32,23 +32,23 @@ public function execute(Request $request)
return new Response('', 304, ['last-modified' => $modificationTimeGMT . 'GMT']);
}
}
return $cachedResponse->withHeader('rss-bridge', 'This is a cached response');
return $cachedResponse->withHeader('rss-bridge', xlat('errors:actions:display:cached'));
}

if (!$bridgeName) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'Missing bridge parameter']), 400);
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:missing_parameter')]), 400);
}
$bridgeFactory = new BridgeFactory();
$bridgeClassName = $bridgeFactory->createBridgeClassName($bridgeName);
if (!$bridgeClassName) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'Bridge not found']), 404);
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:not_found')]), 404);
}

if (!$format) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'You must specify a format']), 400);
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:format')]), 400);
}
if (!$bridgeFactory->isEnabled($bridgeClassName)) {
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => 'This bridge is not whitelisted']), 400);
return new Response(render(__DIR__ . '/../templates/error.html.php', ['message' => xlat('errors:general:whitelist')]), 400);
}

if (
Expand Down Expand Up @@ -145,7 +145,7 @@ private function createResponse(Request $request, BridgeAbstract $bridge, string
if ($errorCount >= $reportLimit) {
if ($errorOutput === 'feed') {
// Render the exception as a feed item
$items[] = $this->createFeedItemFromException($e, $bridge);
$items = [$this->createFeedItemFromException($e, $bridge)];
} elseif ($errorOutput === 'http') {
return new Response(render(__DIR__ . '/../templates/exception.html.php', ['e' => $e]), 500);
} elseif ($errorOutput === 'none') {
Expand Down Expand Up @@ -174,7 +174,7 @@ private function createFeedItemFromException($e, BridgeAbstract $bridge): FeedIt

// Create a unique identifier every 24 hours
$uniqueIdentifier = urlencode((int)(time() / 86400));
$title = sprintf('Bridge returned error %s! (%s)', $e->getCode(), $uniqueIdentifier);
$title = sprintf('%s %s! (%s)', xlat('errors:actions:display:error'), $e->getCode(), $uniqueIdentifier);
$item->setTitle($title);
$item->setURI(get_current_url());
$item->setTimestamp(time());
Expand Down Expand Up @@ -213,22 +213,33 @@ private function logBridgeError($bridgeName, $code)
return $report['count'];
}

private static function createGithubIssueUrl($bridge, $e, string $message): string
private static function createGithubIssueUrl(BridgeAbstract $bridge, \Exception $e, string $message): string
{
return sprintf('https://github.com/RSS-Bridge/rss-bridge/issues/new?%s', http_build_query([
'title' => sprintf('%s failed with error %s', $bridge->getName(), $e->getCode()),
$maintainer = $bridge->getMaintainer();
if (str_contains($maintainer, ',')) {
$maintainers = explode(',', $maintainer);
} else {
$maintainers = [$maintainer];
}
$maintainers = array_map('trim', $maintainers);

$query = [
'title' => $bridge->getName() . ' failed with: ' . $e->getMessage(),
'body' => sprintf(
"```\n%s\n\n%s\n\nQuery string: %s\nVersion: %s\nOs: %s\nPHP version: %s\n```",
"```\n%s\n\n%s\n\nQuery string: %s\nVersion: %s\nOs: %s\nPHP version: %s\n```\nMaintainer: @%s",
$message,
implode("\n", trace_to_call_points(trace_from_exception($e))),
$_SERVER['QUERY_STRING'] ?? '',
Configuration::getVersion(),
PHP_OS_FAMILY,
phpversion() ?: 'Unknown'
phpversion() ?: 'Unknown',
implode(', @', $maintainers),
),
'labels' => 'Bridge-Broken',
'assignee' => $bridge->getMaintainer(),
]));
'assignee' => $maintainer[0],
];

return 'https://github.com/RSS-Bridge/rss-bridge/issues/new?' . http_build_query($query);
}

private static function createGithubSearchUrl($bridge): string
Expand Down
10 changes: 5 additions & 5 deletions actions/FindfeedAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
*/
class FindfeedAction implements ActionInterface
{
public function execute(Request $request)
public function __invoke(Request $request): Response
{
$url = $request->get('url');
$format = $request->get('format');

if (!$url) {
return new Response('You must specify a url', 400);
return new Response(xlat('errors:general:specify_url'), 400);
}
if (!$format) {
return new Response('You must specify a format', 400);
return new Response(xlat('errors:general:specify_format'), 400);
}

$bridgeFactory = new BridgeFactory();
Expand Down Expand Up @@ -69,7 +69,7 @@ public function execute(Request $request)
$results[] = $content;
}
if ($results === []) {
return new Response(Json::encode(['message' => 'No bridge found for given url']), 404, ['content-type' => 'application/json']);
return new Response(Json::encode(['message' => xlat('errors:general:not_found_for_url')]), 404, ['content-type' => 'application/json']);
}
return new Response(Json::encode($results), 200, ['content-type' => 'application/json']);
}
Expand All @@ -82,7 +82,7 @@ private function getParameterName($bridge, $context, $key)
} else if (isset($bridge::PARAMETERS['global'][$key]['name'])) {
$name = $bridge::PARAMETERS['global'][$key]['name'];
} else {
$name = 'Variable "' . $key . '" (No name provided)';
$name = xlat('errors:actions:findfeed:no_name_var', $key);
}
return $name;
}
Expand Down
10 changes: 5 additions & 5 deletions actions/FrontpageAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

final class FrontpageAction implements ActionInterface
{
public function execute(Request $request)
public function __invoke(Request $request): Response
{
$messages = [];
$activeBridges = 0;
Expand All @@ -12,8 +12,8 @@ public function execute(Request $request)

foreach ($bridgeFactory->getMissingEnabledBridges() as $missingEnabledBridge) {
$messages[] = [
'body' => sprintf('Warning : Bridge "%s" not found', $missingEnabledBridge),
'level' => 'warning'
'body' => xlat('errors:general:not_found_named', $missingEnabledBridge),
'level' => 'warning',
];
}

Expand All @@ -26,13 +26,13 @@ public function execute(Request $request)
}

// todo: cache this renderered template?
return render(__DIR__ . '/../templates/frontpage.html.php', [
return new Response(render(__DIR__ . '/../templates/frontpage.html.php', [
'messages' => $messages,
'admin_email' => Configuration::getConfig('admin', 'email'),
'admin_telegram' => Configuration::getConfig('admin', 'telegram'),
'bridges' => $body,
'active_bridges' => $activeBridges,
'total_bridges' => count($bridgeClassNames),
]);
]));
}
}
Loading