mirror of https://github.com/YGGverse/Pulsar.git
yggverse
7 months ago
5 changed files with 210 additions and 1 deletions
@ -1,2 +1,33 @@ |
|||||||
# Pulsar |
# Pulsar |
||||||
RSS Aggregator for Gemini Protocol |
|
||||||
|
RSS Aggregator for [Gemini Protocol](https://geminiprotocol.net) |
||||||
|
|
||||||
|
Simple RSS feed converter to static Gemtext format, useful for news portals or localhost usage. |
||||||
|
|
||||||
|
## Usage |
||||||
|
|
||||||
|
1. `git clone https://github.com/YGGverse/Pulsar.git` |
||||||
|
2. `cp example/config.json config.json` - setup your feeds there! |
||||||
|
3. `php src/crawler.php` - crontab schedule |
||||||
|
|
||||||
|
## Config |
||||||
|
|
||||||
|
Configuration file supports multiple feed channels with custom configurations: |
||||||
|
|
||||||
|
* `source` - string, filepath or URL to the valid RSS feed |
||||||
|
* `target` - string, relative or absolute path to Gemtext dumps |
||||||
|
* `item` |
||||||
|
* `limit` - integer, how many items to display |
||||||
|
* `template` - string, custom pattern for feed item, that supports following macros |
||||||
|
* `{nl}` - new line separator |
||||||
|
* `{link}` - item link |
||||||
|
* `{guid}` - item guid |
||||||
|
* `{pubDate}` - item pubDate, soon with custom time format e.g. `{pubDate:Y-m-d H:s}` |
||||||
|
* `{title}` - item title |
||||||
|
* `{description}` - item description |
||||||
|
|
||||||
|
Resulting files could be generated to the any folder for personal reading on localhost, or shared with others using [gmid](https://github.com/omar-polo/gmid), [twins](https://code.rocket9labs.com/tslocum/twins) or any other [Gemini server](https://github.com/kr1sp1n/awesome-gemini#servers). |
||||||
|
|
||||||
|
## Instances |
||||||
|
|
||||||
|
Coming soon! |
@ -0,0 +1,19 @@ |
|||||||
|
{ |
||||||
|
"name": "yggverse/pulsar", |
||||||
|
"description": "RSS Aggregator for Gemini Protocol", |
||||||
|
"keywords": [ "yggverse", "gemini", "gemini-protocol", "gemtext", "gmi", "rss", "feed", "converter", "aggregator" ], |
||||||
|
"homepage": "https://github.com/yggverse/pulsar", |
||||||
|
"type": "project", |
||||||
|
"license": "MIT", |
||||||
|
"autoload": { |
||||||
|
"psr-4": { |
||||||
|
"Yggverse\\Pulsar\\": "src/" |
||||||
|
} |
||||||
|
}, |
||||||
|
"authors": [ |
||||||
|
{ |
||||||
|
"name": "YGGverse" |
||||||
|
} |
||||||
|
], |
||||||
|
"require": {} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
{ |
||||||
|
"feed": |
||||||
|
[ |
||||||
|
{ |
||||||
|
"source":"https://www.omglinux.com/feed", |
||||||
|
"target":"data/omglinux.com/feed.gmi", |
||||||
|
"item": |
||||||
|
{ |
||||||
|
"template":"=> {link} {title}{nl}{nl}{description}", |
||||||
|
"limit":20 |
||||||
|
} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"source":"https://omgubuntu.co.uk/feed", |
||||||
|
"target":"data/omgubuntu.co.uk/feed.gmi", |
||||||
|
"item": |
||||||
|
{ |
||||||
|
"template":"=> {link} {title}{nl}{nl}{description}", |
||||||
|
"limit":20 |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,132 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
// Prevent multi-thread execution |
||||||
|
$semaphore = sem_get( |
||||||
|
crc32( |
||||||
|
__DIR__ |
||||||
|
), 1 |
||||||
|
); |
||||||
|
|
||||||
|
if (false === sem_acquire($semaphore, true)) |
||||||
|
{ |
||||||
|
exit; |
||||||
|
} |
||||||
|
|
||||||
|
// Init config |
||||||
|
$config = json_decode( |
||||||
|
file_get_contents( |
||||||
|
__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'config.json' |
||||||
|
) |
||||||
|
); |
||||||
|
|
||||||
|
// Update feeds |
||||||
|
foreach ($config->feed as $feed) |
||||||
|
{ |
||||||
|
// Init feed location |
||||||
|
$filename = str_starts_with( |
||||||
|
$feed->target, |
||||||
|
DIRECTORY_SEPARATOR |
||||||
|
) ? $feed->target : __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . $feed->target; |
||||||
|
|
||||||
|
// Init destination storage |
||||||
|
@mkdir( |
||||||
|
dirname( |
||||||
|
$filename |
||||||
|
), |
||||||
|
0755, |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
// Get feed data |
||||||
|
if (!$channel = simplexml_load_file($feed->source)->channel) |
||||||
|
{ |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
// Update title |
||||||
|
if (!empty($channel->title)) |
||||||
|
{ |
||||||
|
$title = trim( |
||||||
|
strip_tags( |
||||||
|
html_entity_decode( |
||||||
|
$channel->title |
||||||
|
) |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
else |
||||||
|
{ |
||||||
|
$title = parse_url( |
||||||
|
$feed->source, |
||||||
|
PHP_URL_HOST |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
file_put_contents( |
||||||
|
$filename, |
||||||
|
sprintf( |
||||||
|
'# %s', |
||||||
|
$title |
||||||
|
) . PHP_EOL |
||||||
|
); |
||||||
|
|
||||||
|
// Append description |
||||||
|
if (!empty($channel->description)) |
||||||
|
{ |
||||||
|
file_put_contents( |
||||||
|
$filename, |
||||||
|
PHP_EOL . trim( |
||||||
|
strip_tags( |
||||||
|
html_entity_decode( |
||||||
|
$channel->description |
||||||
|
) |
||||||
|
) |
||||||
|
) . PHP_EOL, |
||||||
|
FILE_APPEND | LOCK_EX |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// Append items |
||||||
|
$i = 1; foreach ($channel->item as $item) |
||||||
|
{ |
||||||
|
// Apply items limit |
||||||
|
if ($i > $feed->item->limit) |
||||||
|
{ |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
// Format item |
||||||
|
file_put_contents( |
||||||
|
$filename, |
||||||
|
PHP_EOL . trim( |
||||||
|
preg_replace( |
||||||
|
'/[\s]{3,}/ui', |
||||||
|
PHP_EOL . PHP_EOL, |
||||||
|
str_replace( |
||||||
|
[ |
||||||
|
'{nl}', |
||||||
|
'{link}', |
||||||
|
'{guid}', |
||||||
|
'{pubDate}', |
||||||
|
'{title}', |
||||||
|
'{description}' |
||||||
|
], |
||||||
|
[ |
||||||
|
PHP_EOL, |
||||||
|
!empty($item->link) ? trim($item->link) : '', |
||||||
|
!empty($item->guid) ? trim($item->guid) : '', |
||||||
|
!empty($item->pubDate) ? trim($item->pubDate) : '', |
||||||
|
!empty($item->title) ? trim(strip_tags(html_entity_decode($item->title))) : '', |
||||||
|
!empty($item->description) ? trim(strip_tags(html_entity_decode($item->description))) : '' |
||||||
|
], |
||||||
|
$feed->item->template |
||||||
|
) . PHP_EOL |
||||||
|
) |
||||||
|
) . PHP_EOL, |
||||||
|
FILE_APPEND | LOCK_EX |
||||||
|
); |
||||||
|
|
||||||
|
$i++; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue