Skip to content

Commit

Permalink
Docs: better documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Victrid committed May 15, 2024
1 parent f8cf410 commit 73c4e09
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 41 deletions.
94 changes: 73 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,88 @@
# Image Cache Extension
# Image Cache Extension for FreshRSS

This FreshRSS extension allows you to cache feeds’ pictures in your own facility.
This extension allows you to cache images from the feeds in FreshRSS. It helps speed up feed loading times and reduce bandwidth usage by caching images on a server.

To use it, upload this entire directory to the FreshRSS `./extensions` directory on your server and enable it on the extension panel in FreshRSS.
## Installation

There is a Cloudflare worker implementation of the cache utilizing its Cache API. Check this [repo](https://github.com/Victrid/image-cache-worker) (It's can be run on free tier).
1. **Download and Setup**:
- Download the zip file from the [Releases page](https://github.com/Victrid/freshrss-image-cache-plugin/releases).
- Extract the folder and place it in the `extensions` directory of your FreshRSS installation, ensuring that the `metadata.json` file is in the root of the `imagecache` folder.
- Enable the extension through the FreshRSS extension panel.

## Configuration settings
After installation, your directory structure should resemble:

- `cache_url` (default: `https://example.com/pic?url=`): The URL of the image used to load when the user reads the feed article.
```
extensions/
|-- imagecache/
| |-- metadata.json
| |-- imagecache.php
| |-- ...
|-- some-other-extension/
|-- ...
```

- `post_url` (default: `https://example.com/prepare`): Address used to inform the caching service when FreshRSS fetches a new article.
## Usage

The plugin will send a JSON POST request to this address in this format:
**Note**: This extension does not cache images directly within the FreshRSS instance. Instead, it works with an external cache service to store images.

```json
{
"url": "https://http.cat/418.jpg",
"access_token": "YOUR_ACCESS_TOKEN"
}
```
### How It Works

- `access_token` (default: `""`): See the JSON request above.
The diagram below illustrates the extension's operation:

- `url_encode` (default: `1`): whether to URL-encode (RFC 3986) the proxied URL.
![ImageCache Workflow](imagecache.svg)

## Important Note
When proactive caching is enabled, FreshRSS sends a request to your cache service to store the image if a new feed entry includes image URLs. This modifies the image URL so users access the cached version instead of the original source.

Your cache implementation should not rely on the `post`-method, in other words, the `cache_url` should support cache-miss situations.
### Setting Up a Cache Server

## See Also
You have two options for setting up your cache server:

[ImageProxy](https://github.com/FreshRSS/Extensions/tree/master/xExtension-ImageProxy) plugin: Don’t need a cache, just proxy? Use ImageProxy plugin instead.
1. **Self-Hosted Server**:
- Use the example provided in [piccache.php.example](piccache.php.example). Rename it to `piccache.php` and place it in your `/path/to/FreshRSS/p` directory.
- Update the configuration in `piccache.php` as follows:

This extension is based on ImageProxy plugin, and is licensed under GPLv3.
```php
define("CACHE_PLACE_PATH", "/path/to/cache/folder");
define("ACCESS_TOKEN", "SoMe_oBsCuRe_aCcEsS_ToKeN");
```

- (For Docker users) You can build a custom image with the following Dockerfile:

```dockerfile
FROM freshrss/freshrss:latest

COPY piccache.php /var/www/FreshRSS/p/piccache.php
```

- Configure FreshRSS to use the caching service:

```yaml
Cache URL: "http://192.168.1.123:4567/piccache.php?url="
Enable proactive cache: checked
Proactive Cache URL: "http://192.168.1.123:4567/piccache.php"
Access Token: "SoMe_oBsCuRe_aCcEsS_ToKeN"
```

This script is basic and does not handle cleaning up old caches or implementing crawler-detection avoidance. If you need a reliable cache server, consider the cloudflare worker solution below.

2. **Cloudflare Worker**:
- If you have limited bandwidth or experience high latency, consider using a [Cloudflare Worker](https://github.com/Victrid/image-cache-worker). This solution caches images on Cloudflare's CDN, which can be set up on their free tier without a custom domain.

## Additional Information

When proactive cache is enabled, the plugin sends a JSON POST request to the cache URL in the following format:

```json
{
"url": "https://http.cat/418.jpg",
"access_token": "YOUR_ACCESS_TOKEN"
}
```

## Alternatives

Consider the [ImageProxy](https://github.com/FreshRSS/Extensions/tree/master/xExtension-ImageProxy) plugin if you need a simpler solution for proxying images without caching.

## License

This extension is inspired by the ImageProxy plugin and is available under the GPLv3 license.
8 changes: 1 addition & 7 deletions configure.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@
?>
<form action="<?= _url('extension', 'configure', 'e', urlencode($this->getName())) ?>" method="post">
<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<h3>User fetch settings</h3>
<h3><?= _t('ext.imagecache.fetch_settings') ?></h3>
<div class="form-group">
<label class="group-name" for="image_cache_url"><?= _t('ext.imagecache.cache_url') ?></label>
<div class="group-controls">
<input type="url" name="image_cache_url" id="image_cache_url" value="<?= FreshRSS_Context::userConf()->image_cache_url ?>">
</div>
</div>
<div class="form-group">
<label class="group-name" for="image_cache_url_encode"><?= _t('ext.imagecache.url_encode') ?></label>
<div class="group-controls">
<input type="checkbox" name="image_cache_url_encode" id="image_cache_url_encode" value="1" <?= FreshRSS_Context::userConf()->image_cache_url_encode ? 'checked' : '' ?>>
</div>
</div>
<h3><?= _t('ext.imagecache.proactive_cache') ?></h3>
<p><?= _t('ext.imagecache.proactive_cache_desc') ?></p>
<div class="form-group">
Expand Down
5 changes: 0 additions & 5 deletions extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ public function init(): void
FreshRSS_Context::userConf()->image_cache_access_token = self::CACHE_ACCESS_TOKEN;
$save = true;
}
if (is_null(FreshRSS_Context::userConf()->image_cache_url_encode)) {
FreshRSS_Context::userConf()->image_cache_url_encode = self::URL_ENCODE;
$save = true;
}
if (is_null(FreshRSS_Context::userConf()->image_cache_post_enabled)) {
FreshRSS_Context::userConf()->image_cache_post_enabled = self::CACHE_POST_ENABLED;
$save = true;
Expand All @@ -55,7 +51,6 @@ public function handleConfigureAction(): void
FreshRSS_Context::userConf()->image_cache_url = Minz_Request::paramString('image_cache_url');
FreshRSS_Context::userConf()->image_cache_post_url = Minz_Request::paramString('image_cache_post_url');
FreshRSS_Context::userConf()->image_cache_access_token = Minz_Request::paramString('image_cache_access_token');
FreshRSS_Context::userConf()->image_cache_url_encode = Minz_Request::paramString('image_cache_url_encode');
FreshRSS_Context::userConf()->image_cache_post_enabled = Minz_Request::paramString('image_cache_post_enabled');
FreshRSS_Context::userConf()->save();
}
Expand Down
8 changes: 4 additions & 4 deletions i18n/en/ext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

return array(
'imagecache' => array(
'cache_url' => 'Cache URL (for user to fetch)',
'url_encode' => 'Encode the URL',
'post_url' => 'Post URL (for freshRSS to inform)',
'access_token' => 'Access Token (for freshRSS to inform)',
'cache_url' => 'Cache URL',
'post_url' => 'Proactive Cache URL',
'access_token' => 'Access Token',
'fetch_settings' => 'Fetch settings',
'proactive_cache' => 'FreshRSS Proactive Cache Settings',
'proactive_cache_enabled' => 'Enable proactive cache',
'proactive_cache_desc' => 'The proactive cache allows FreshRSS to notify cache server to download pictures ' .
Expand Down
8 changes: 4 additions & 4 deletions i18n/zh-CN/ext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

return array(
'imagecache' => array(
'cache_url' => '缓存URL(用于用户获取)',
'url_encode' => '对URL进行转义',
'post_url' => '通知URL(用于建立缓存)',
'access_token' => '访问token(用于建立缓存)',
'cache_url' => '缓存URL',
'post_url' => '主动缓存URL',
'access_token' => '主动缓存访问令牌',
'fetch_settings' => '用户请求设置',
'proactive_cache' => '主动缓存设置',
'proactive_cache_enabled' => '启用主动缓存',
'proactive_cache_desc' => '主动缓存允许FreshRSS在获取到新文章时就通知缓存服务器下载图片。这样可以加快看到图片的速度。',
Expand Down
3 changes: 3 additions & 0 deletions imagecache.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
85 changes: 85 additions & 0 deletions piccache.php.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php
define("CACHE_PLACE_PATH", sys_get_temp_dir());
define("ACCESS_TOKEN", "your_access_token");
# Also possible:
# define("CACHE_PLACE_PATH", "C:\\your\\Directory");
# define("CACHE_PLACE_PATH", "/var/www/html/directory");
# Remember to set correct privileges allowing PHP access.
function join_paths(...$paths)
{
return preg_replace('~[/\\\\]+~', DIRECTORY_SEPARATOR, implode(DIRECTORY_SEPARATOR, $paths));
}

;

function get_name($url)
{
$tmp_path = join_paths(CACHE_PLACE_PATH, "piccache");
if (!file_exists($tmp_path)) mkdir(join_paths($tmp_path), 0777);
return join_paths($tmp_path, hash('sha256', $url));
}

function is_strict_url($url)
{
$valid = filter_var($url, FILTER_VALIDATE_URL);
if ($valid === false) return false;

$parsed_url = parse_url($url);
// Must be http or https
if (!in_array($parsed_url['scheme'], array('http', 'https'))) return false;

return true;
}

function get($url)
{
return file_exists(get_name($url)) ? get_name($url) : null;
}

function set($url)
{
$file_name = get_name($url);
$content = file_get_contents($url);
file_put_contents($file_name, $content);
return $file_name;
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$post = json_decode(file_get_contents('php://input'), true);
if (!$post || !array_key_exists("url", $post) || !array_key_exists("access_token", $post)) {
http_response_code(400);
exit();
}
if ($post['access_token'] !== ACCESS_TOKEN) {
http_response_code(403);
exit();
}
if (!is_strict_url($post['url'])) {
http_response_code(400);
exit();
}
set($post['url']);
header('Content-Type: application/json; charset=utf-8');
echo '{"status": "OK"}' . PHP_EOL;
exit();
} elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
$url = $_GET['url'];
if (!$url || !is_strict_url($url)) {
http_response_code(400);
exit();
}
$file = get($url);
header("X-Piccache-Status: " . ($file ? "HIT" : "MISS"));
if (!$file) $file = set($url);
$finfo = finfo_open(FILEINFO_MIME);
header('Content-Type: ' . finfo_file($finfo, $file));
finfo_close($finfo);
header('Content-Length: ' . filesize($file));
$fp = fopen($file, 'rb');
fpassthru($fp);
exit();
} else {
http_response_code(405);
exit();
}
?>

0 comments on commit 73c4e09

Please sign in to comment.