Add atom feed

This commit is contained in:
Knah Tsaeb 2024-10-04 16:25:50 +02:00
parent 2cea764110
commit fb1d1557f4
8 changed files with 206 additions and 37 deletions

View file

@ -2,7 +2,7 @@ FROM ubuntu/apache2
MAINTAINER Knah Tsaeb <knah-tsaeb_nanogal@knah-tsaeb.org> MAINTAINER Knah Tsaeb <knah-tsaeb_nanogal@knah-tsaeb.org>
LABEL version="0.1.0" LABEL version="0.2.0"
LABEL description="Apache 2 / PHP / NanoGal" LABEL description="Apache 2 / PHP / NanoGal"
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
@ -30,7 +30,7 @@ WORKDIR /var/www/
ENTRYPOINT "start.sh" ENTRYPOINT "start.sh"
# Build image # Build image
# docker build -t nanogal:0.1.0 . # docker build -t nanogal:0.2.0 .
# Run container # Run container
# docker run -v nanogal_datas:/var/www/datas:ro -v nanogal_photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.1.0 # docker run -v nanogal_datas:/var/www/datas:ro -v nanogal_photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.2.0
# docker run -v /opt/nanogal/datas:/var/www/datas:ro -v /opt/nanogal/photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.1.0 # docker run -v /opt/nanogal/datas:/var/www/datas:ro -v /opt/nanogal/photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.2.0

View file

@ -35,7 +35,7 @@ Image use
```shell ```shell
wget https://forge.leslibres.org/Knah-Tsaeb/NanoGal/raw/branch/main/Dockerfile wget https://forge.leslibres.org/Knah-Tsaeb/NanoGal/raw/branch/main/Dockerfile
docker buildx build --no-cache -t nanogal:0.1.0 . docker buildx build --no-cache -t nanogal:0.2.0 .
``` ```
#### Start container #### Start container
@ -43,13 +43,13 @@ docker buildx build --no-cache -t nanogal:0.1.0 .
You can use native docker volume. You can use native docker volume.
```shell ```shell
docker run -v nanogal_datas:/var/www/datas:ro -v nanogal_photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.1.0 docker run -v nanogal_datas:/var/www/datas:ro -v nanogal_photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.2.0
``` ```
Or use absolute path Or use absolute path
```shell ```shell
docker run -v /opt/nanogal/datas:/var/www/datas:ro -v /opt/nanogal/photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.1.0 docker run -v /opt/nanogal/datas:/var/www/datas:ro -v /opt/nanogal/photos:/var/www/public/photos:ro -e TZ=UTC -p 8187:80 --name nanogal nanogal:0.2.0
``` ```
### Classic way ### Classic way
@ -70,8 +70,8 @@ If you want, you can delete this data. Under GNU/Linux you can install `exiftool
### Adding your photos ### Adding your photos
- Simply add your photos to the `photos` directory via FTP or SFTP. - Simply add your photos to the `photos` directory via FTP or SFTP or use sync app (look idea section).
- You can create as many subdirectories as you want. - You can create any subdirectories as you want.
### Adding a comment to a gallery ### Adding a comment to a gallery
@ -111,7 +111,8 @@ $userConfig = [
'thumbSize' => 250, // Thumbnail height/width (square thumbs) 'thumbSize' => 250, // Thumbnail height/width (square thumbs)
'displayExifInfo' => false, // Display Exif info in caption 'displayExifInfo' => false, // Display Exif info in caption
'disableCache' => false, // Enable or disable cache 'disableCache' => false, // Enable or disable cache
'showShareLink' => false // Show link for thumb, full, markdown link (thumb + link to full) 'showShareLink' => false, // Show link for thumb, full, markdown link (thumb + link to full)
'nbItemsAtom' => 25 // Number of item in atom feed
]; ];
``` ```
@ -129,12 +130,13 @@ $userConfig = [
| displayExifInfo | bool | false | Display Exif info in caption | | displayExifInfo | bool | false | Display Exif info in caption |
| disableCache | bool | false | Enable or disable cache | | disableCache | bool | false | Enable or disable cache |
| showShareLink | boll | false | Show share link for thumb, full, markdown link (thumb + link to full) | | showShareLink | boll | false | Show share link for thumb, full, markdown link (thumb + link to full) |
| nbItemsAtom | int | 25 | Number of item in atom feed
#### Notes #### Notes
If you change the thumbsize, thumbnails are not re-create. If the difference between older and newer size are small, I think you don't need regen all thumb. But if you prefer, you can delete `cache/thumbs/*` for force re-create thumbnails. If you change the thumbsize, thumbnails are not re-create. If the difference between older and newer size are small, I think you don't need regen all thumb. But if you prefer, you can delete `cache/thumbs/*` for force re-create thumbnails.
If you change any parameter, the cache file (html file) are delete and recreate. If you change any parameter, the cache file (html file and atom file) are delete and recreate.
## Ideas ## Ideas
@ -145,12 +147,12 @@ If you have NextCloud installed on your server, you can use it to manage your Na
In the NextCloud settings: Settings > Administration > External Storage: In the NextCloud settings: Settings > Administration > External Storage:
| Option | Description | | Option | Description |
| --- | --- | | --- | --- |
| Folder Name | The name of the folder as it will appear in NextCloud. | | Folder Name | The name of the folder as it will appear in NextCloud. |
| External Storage | Choose Local | | External Storage | Choose Local |
| Authentication | None | | Authentication | None |
| Configuration | Enter the path where your images are stored (the path to the NanoGal /photos directory) | | Configuration | Enter the path where your images are stored (the path to the NanoGal /photos directory) |
Don't forget to disable encrypt for this folder. Don't forget to disable encrypt for this folder.

View file

@ -10,6 +10,7 @@ class Cache {
private $counter = []; private $counter = [];
private $fileName = '../cache/cache.json'; private $fileName = '../cache/cache.json';
private $fileCache; private $fileCache;
static $atomFileName = '../cache/feed.atom';
private $currentConfig; private $currentConfig;
private $saveConfig; private $saveConfig;
@ -101,7 +102,7 @@ class Cache {
$this->fileCache[$this->currentDir] = -1; $this->fileCache[$this->currentDir] = -1;
} }
if ($this->counter[$this->currentDir] !== $this->fileCache[$this->currentDir]) { if (!empty($this->counter[$this->currentDir]) && ($this->counter[$this->currentDir] !== $this->fileCache[$this->currentDir])) {
$this->fileCache = array_merge($this->fileCache, $this->counter); $this->fileCache = array_merge($this->fileCache, $this->counter);
return true; return true;
} }
@ -172,4 +173,37 @@ class Cache {
} }
} }
} }
/**
* Deleting the Atom feed cache file if exists.
*
* @return void
*/
static function clearAtomFeed(): void {
if (file_exists(self::$atomFileName)) {
unlink(self::$atomFileName);
}
}
/**
* Retrieves the Atom feed cache content if file exists.
*
* @return string|false Returns the content of the Atom feed cache file, or false if the file does not exist.
*/
static function getAtomFeed(): string|false {
if (file_exists(self::$atomFileName)) {
return file_get_contents(self::$atomFileName);
}
return false;
}
/**
* Writes content to the Atom feed cache file.
*
* @param string $content The content to be written to the Atom feed file.
* @return void
*/
static function setAtomFeed(string $content): void {
file_put_contents(self::$atomFileName, $content);
}
} }

View file

@ -199,6 +199,35 @@ class FileAndDir {
} }
} }
/**
* Retrieves a list of the most recent image files, sorted by modification time.
*
* @return array An array of image files with their URLs and modification times.
*/
public function makeMoreRecentFile(): array {
$allFile = [];
$directory = new \RecursiveDirectoryIterator('photos/');
foreach (new \RecursiveIteratorIterator($directory) as $file) {
if (in_array($directory->getFilename(), $this->config['skipObjects'])) {
continue;
}
if (in_array($file->getExtension(), $this->fileExtensions['img'])) {
$allFile[] = [
'url' => $this->appUrl . '/' . $file->getPathname(),
'thumb' => $this->appUrl . '/' . $this->makeImageThumbUrl($file->getPathname()),
'tdate' => $file->getMTime(),
];
}
}
$order = $this->config['orderBy'] === 'asc' ? 1 : -1;
usort($allFile, function ($a, $b) use ($order) {
return $order * ($a['tdate'] - $b['tdate']);
});
return array_slice($allFile, 0, $this->config['nbItemsAtom'], true);
}
/** /**
* Determines the type of file based on its extension. * Determines the type of file based on its extension.
* *
@ -285,9 +314,16 @@ class FileAndDir {
$ext = strtolower($pathinfo['extension']); $ext = strtolower($pathinfo['extension']);
if (in_array($ext, $this->fileExtensions['img'])) { if (in_array($ext, $this->fileExtensions['img'])) {
$imageName = $file; $imageName = $file;
if(empty($this->currentDir)){
$path = $imageName;
} else {
$path = $this->currentDir . '/' . $imageName;
}
$imgParams = 'createthumb.php?' . http_build_query( $imgParams = 'createthumb.php?' . http_build_query(
array( array(
'filename' => $this->currentDir . '/' . $imageName 'filename' => $path
), ),
'', '',
'&amp;' '&amp;'

View file

@ -15,10 +15,10 @@ if (file_exists('../datas/config.php')) {
$config = array_merge($config, $userConfig); $config = array_merge($config, $userConfig);
} }
$get_filename = $_GET['filename']; $getFilename = $_GET['filename'];
$baseDir = getcwd(); $baseDir = getcwd();
if (!Utils::isPathAuthorized($get_filename)) { if (!Utils::isPathAuthorized($getFilename)) {
die("ERROR 01: Unauthorized access!"); die("ERROR 01: Unauthorized access!");
} }
@ -26,7 +26,7 @@ if (!is_dir('../cache/thumbs') && is_writable('.')) {
mkdir('../cache/thumbs', 0700); mkdir('../cache/thumbs', 0700);
} }
$pathInfos = pathinfo($get_filename); $pathInfos = pathinfo($getFilename);
$dirname = '../cache/' . str_replace('photos', 'thumbs', $pathInfos['dirname']); $dirname = '../cache/' . str_replace('photos', 'thumbs', $pathInfos['dirname']);
$filename = $pathInfos['filename']; $filename = $pathInfos['filename'];
$thumbname = '../cache/' . $dirname . '/' . $filename . '.' . $pathInfos['extension'] . '.webp'; $thumbname = '../cache/' . $dirname . '/' . $filename . '.' . $pathInfos['extension'] . '.webp';
@ -40,7 +40,7 @@ if (file_exists($thumbname)) {
exit; exit;
} }
if (!is_readable($get_filename) || !is_file($get_filename)) { if (!is_readable($getFilename) || !is_file($getFilename)) {
header('Content-type: image/svg+xml'); header('Content-type: image/svg+xml');
$cannotopenImg = file_get_contents('assets/images/cannotopen.svg'); $cannotopenImg = file_get_contents('assets/images/cannotopen.svg');
echo $cannotopenImg; echo $cannotopenImg;
@ -55,7 +55,7 @@ if (!file_exists($dirname)) {
$image = new Zebra_Image(); $image = new Zebra_Image();
$image->auto_handle_exif_orientation = true; $image->auto_handle_exif_orientation = true;
$image->source_path = $get_filename; $image->source_path = $getFilename;
$image->target_path = $thumbname; $image->target_path = $thumbname;
if (!$image->resize($config['thumbSize'], $config['thumbSize'], ZEBRA_IMAGE_CROP_CENTER)) { if (!$image->resize($config['thumbSize'], $config['thumbSize'], ZEBRA_IMAGE_CROP_CENTER)) {

84
public/feed.php Normal file
View file

@ -0,0 +1,84 @@
<?php
date_default_timezone_set('Europe/Paris');
require '../vendor/autoload.php';
use App\FileAndDir;
use App\Cache;
use Utils\Utils;
$config = [
'templateFile' => 'board', // Template filename (must be placed in 'public/templates' folder)
'title' => 'NanoGal', // Text to be displayed in browser titlebar
'description' => 'My gallery', // Use in meta tag "description"
'author' => 'NanoGal', // Your name
'skipObjects' => ['comment.html', '.gitkeep', 'aFolder', 'aFile.ext'], //Those files and folders will not be displayed (affects the page and the RSS feed)
'imageCaptionPosition' => 'right', // Position of caption in lightbox
'sortBy' => 'name', // Sort by name or date
'orderBy' => 'desc', // Order by asc or desc
'thumbSize' => 250, // Thumbnail height/width (square thumbs)
'displayExifInfo' => false, // Display Exif info in caption
'disableCache' => false, // Enable or disable cache
'showShareLink' => false, // Show link for thumb, full, markdown link (thumb + link to full)
'nbItemsAtom' => 25 // Number of item in atom feed
];
if (file_exists('../datas/config.php')) {
include '../datas/config.php';
$config = array_merge($config, $userConfig);
}
header('Content-Type: text/xml');
if ($config['disableCache'] === false) {
$cachedFeed = Cache::getAtomFeed();
if ($cachedFeed) {
echo $cachedFeed;
exit();
}
} else {
Cache::clearAtomFeed();
}
$gallery_link = $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST'];
$fileList = new FileAndDir('', '/', $config);
$filterList = $fileList->makeMoreRecentFile();
$date = date_create();
$updated = $date->format(DateTimeInterface::ATOM);
$atom = '<?xml version="1.0" encoding="UTF-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>' . $config['title'] . '</title>
<link href="' . $gallery_link . '/feed.php" rel="self" />
<link href="' . $gallery_link . '" />
<id>' . $gallery_link . '</id>
<icon>assets/favicons/favicon-96x96.png</icon>
<logo>assets/favicons/favicon-310x310.png</logo>
<generator>NanoGal</generator>
<author>
<name>' . $config['author'] . '</name>
</author>
<updated>' . $updated . '</updated>';
foreach ($filterList as $value) {
$atom .= '
<entry>
<title>' . basename($value['url']) . '</title>
<link href="' . $value['url'] . '"/>
<id>' . $value['url'] . '</id>
<updated>' . date(DATE_ATOM, $value['tdate']) . '</updated>
<published>' . date(DATE_ATOM, $value['tdate']) . '</published>
<content type="html" xml:lang="en">
<![CDATA[
<a href="' . $value['url'] . '"><img src="' . $value['thumb'] . '"></a>
]]>
</content>
</entry>';
}
$atom .= "</feed>";
if ($config['disableCache'] === false) {
Cache::setAtomFeed($atom);
}
echo $atom;

View file

@ -1,4 +1,5 @@
<?php <?php
date_default_timezone_set('Europe/Paris');
$time_start = microtime(true); $time_start = microtime(true);
require '../vendor/autoload.php'; require '../vendor/autoload.php';
@ -18,7 +19,7 @@ Not edit this param directly
2 - Create $userconfig array like : 2 - Create $userconfig array like :
$userConfig = [ $userConfig = [
'templateFile' => 'board', // Template filename (must be placed in 'templates' folder) 'templateFile' => 'board', // Template filename (must be placed in 'public/templates' folder)
'title' => 'NanoGal', // Text to be displayed in browser titlebar 'title' => 'NanoGal', // Text to be displayed in browser titlebar
'description' => 'My gallery', // Use in meta tag "description" 'description' => 'My gallery', // Use in meta tag "description"
'author' => 'NanoGal', // Your name 'author' => 'NanoGal', // Your name
@ -26,9 +27,11 @@ $userConfig = [
'imageCaptionPosition' => 'right', // Position of caption in lightbox 'imageCaptionPosition' => 'right', // Position of caption in lightbox
'sortBy' => 'name', // Sort by name or date 'sortBy' => 'name', // Sort by name or date
'orderBy' => 'desc', // Order by asc or desc 'orderBy' => 'desc', // Order by asc or desc
'thumbSize' => 250, // Thumbnail height/width (square thumbs)
'displayExifInfo' => false, // Display Exif info in caption 'displayExifInfo' => false, // Display Exif info in caption
'thumbSize' => 300, // Thumbnail height/width (square thumbs)
'disableCache' => false, // Enable or disable cache 'disableCache' => false, // Enable or disable cache
'showShareLink' => false, // Show link for thumb, full, markdown link (thumb + link to full)
'nbItemsAtom' => 25 // Number of item in atom feed
]; ];
*/ */
$config = [ $config = [
@ -43,7 +46,8 @@ $config = [
'thumbSize' => 250, // Thumbnail height/width (square thumbs) 'thumbSize' => 250, // Thumbnail height/width (square thumbs)
'displayExifInfo' => false, // Display Exif info in caption 'displayExifInfo' => false, // Display Exif info in caption
'disableCache' => false, // Enable or disable cache 'disableCache' => false, // Enable or disable cache
'showShareLink' => false // Show link for thumb, full, markdown link (thumb + link to full) 'showShareLink' => false, // Show link for thumb, full, markdown link (thumb + link to full)
'nbItemsAtom' => 25 // Number of item in atom feed
]; ];
if (file_exists('../datas/config.php')) { if (file_exists('../datas/config.php')) {
@ -55,7 +59,7 @@ $messages = '';
if (!function_exists('exif_read_data') && $config['displayExifInfo'] === true) { if (!function_exists('exif_read_data') && $config['displayExifInfo'] === true) {
$display_exif = 0; $display_exif = 0;
$messages = "Error: PHP EXIF is not available. Set &#36;display_exif = 0; in config.php to remove this message"; $messages = "Error: PHP EXIF is not available. Set &#36;display_exif = 0; in config.php to remove this message";
} }
$requestedDir = ''; $requestedDir = '';
@ -73,12 +77,15 @@ if ($config['disableCache'] === false) {
} }
if ($cache->changeFile() || $cache->changeConf() || !file_exists($cacheHash . '.html') || $config['disableCache'] === true) { if ($cache->changeFile() || $cache->changeConf() || !file_exists($cacheHash . '.html') || $config['disableCache'] === true) {
if ($cache->changeConf()) { if ($cache->changeConf()) {
$cache->clearCache(); $cache->clearCache();
} }
if ($config['disableCache'] !== true) { if($cache->changeFile() || $cache->changeConf()){
Cache::clearAtomFeed();
}
if ($config['disableCache'] === false) {
$cache->save(); $cache->save();
} }
@ -90,12 +97,12 @@ if ($cache->changeFile() || $cache->changeConf() || !file_exists($cacheHash . '.
ob_start(); ob_start();
$userCss = ''; $userCss = '';
// If user set personal css rule, load it
if (file_exists('../datas/user.css')) { if (file_exists('../datas/user.css')) {
$userCss = '<style>'.file_get_contents('../datas/user.css').'</style>'; $userCss = '<style>' . file_get_contents('../datas/user.css') . '</style>';
} }
// If template exist load it or load default template
if (file_exists('templates/' . $config['templateFile'] . '/' . $config['templateFile'] . '.php')) { if (file_exists('templates/' . $config['templateFile'] . '/' . $config['templateFile'] . '.php')) {
require 'templates/' . $config['templateFile'] . '/' . $config['templateFile'] . '.php'; require 'templates/' . $config['templateFile'] . '/' . $config['templateFile'] . '.php';
} else { } else {

View file

@ -7,11 +7,17 @@ use App\FileAndDir;
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title><?= $config['title']; ?></title>
<meta name="author" content="<?= $config['author']; ?>"> <meta name="author" content="<?= $config['author']; ?>">
<meta name="generator" content="NanoGal"> <meta name="generator" content="NanoGal">
<title><?= $config['title']; ?></title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="<?= $config['description']; ?>"> <meta name="description" content="<?= $config['description']; ?>">
<meta name="msapplication-TileImage" content="/assets/favicons/ms-icon-144x144.png">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="theme-color" content="#ffffff">
<link href="assets/css/glightbox.min.css" rel="stylesheet"> <link href="assets/css/glightbox.min.css" rel="stylesheet">
<link href="templates/board/board.css" rel="stylesheet"> <link href="templates/board/board.css" rel="stylesheet">
<link rel="apple-touch-icon" sizes="57x57" href="/assets/favicons/apple-icon-57x57.png"> <link rel="apple-touch-icon" sizes="57x57" href="/assets/favicons/apple-icon-57x57.png">
@ -26,9 +32,9 @@ use App\FileAndDir;
<link rel="icon" type="image/png" sizes="192x192" href="/assets/favicons/android-icon-192x192.png"> <link rel="icon" type="image/png" sizes="192x192" href="/assets/favicons/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/favicons/favicon-96x96.png"> <link rel="icon" type="image/png" sizes="96x96" href="/assets/favicons/favicon-96x96.png">
<link rel="manifest" href="/assets/favicons/manifest.json"> <link rel="manifest" href="/assets/favicons/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/assets/favicons/ms-icon-144x144.png"> <link rel="alternate" href="feed.php" type="application/atom+xml" title="Atom 0.3">
<meta name="theme-color" content="#ffffff">
<?= $userCss; ?> <?= $userCss; ?>
</head> </head>