Конвертація Nginx autoindex в RSS
В нашій спільноті є сервер IceCast, де віднедавна з'явилась рубрика Подкасти. Вона являє собою звичайну теку `ramfs`, куди скриптом `ytd` збираються аудіо-доріжки новин з Youtube:
https://codeberg.org/YGGverse/ytd
Штатний `autoindex=on` в Nginx - доволі зручний і поширений інструмент, але він не відрізняється широтою опцій. Спочатку, я відкрив для себе модуль "fancyindex", який дозволяє вказувати для списків файлів свою шапку і футер, а звідти - кастомізувати оформлення (зокрема робити тему адаптивною до темного середовища). Згодом, в контексті тих же Подкастів, з'явилась ідея організувати підписки по RSS, але стандартний `autoindex` вміє тільки формати XML і JSON.
Не довго шукаючи рішення і майже випадково не написавши свій проксі-сервер-велосипед, дізнався про ще один готовий модуль Nginx:
apt install libnginx-mod-http-xslt-filter
Для його роботи, потрібно створити віртуальний шлях:
server {
# ...
location ~ ^/podcast/([A-z0-9_\-/]+)/rss/?$ {
alias /mnt/icecast/podcast/$1/;
autoindex on;
autoindex_format xml;
xslt_param host "'$host'";
xslt_param proto "'$scheme'";
xslt_param port "'$server_port'";
xslt_param path "'/podcast/$1/'";
xslt_types application/xml;
xslt_stylesheet /etc/nginx/xslt/rss.xsl;
add_header Content-Type "application/rss+xml";
}
}
- я використовую регулярку, бо шляхів на підтеки багато і не знаю, чи патерн `.*` не стане траверсивною діркою
Тепер потрібно створити сам шаблон перетворення штатного `autoindex_format xml`, згідно `xslt_stylesheet /etc/nginx/xslt/rss.xsl`:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:param name="host" />
<xsl:param name="proto" />
<xsl:param name="port" />
<xsl:param name="path" />
<xsl:template match="/">
<rss version="2.0">
<channel>
<title>TITLE</title>
<description>DESCRIPTION</description>
<link><xsl:value-of select="concat($proto, '://', $host, ':', $port, $path)" /></link>
<xsl:for-each select="list/*[not(contains(., '.partial'))]">
<item>
<title><xsl:value-of select="."/></title>
<link><xsl:value-of select="concat($proto, '://', $host, ':', $port, $path, .)" /></link>
<pubDate><xsl:value-of select="@mtime"/></pubDate>
</item>
</xsl:for-each>
</channel>
</rss>
</xsl:template>
</xsl:stylesheet>
- TITLE, DESCRIPTION - ваші значення
- значення `xsl:param` - перекидаються з відповідних змінних оточення `/etc/nginx/default`
- фільтр `select="list/*[not(contains(., '.partial'))]"` в `xsl:for-each` - виключає з фіду розширення `.partial` (бо наш скрипт відвантаження реалізовано з `rclone` і RSS таким чином може сповіщати про недовантажені аудіо-файли)
- в прикладі також не вказано `<guid>` - можливо його варто вказати на прикладі патерну `<link>`
Тепер перезавантажуємо налаштування Nginx:
sudo systemctl reload nginx
І підписуємось на стрічку за адресою `http://host/podcast/name/rss`
Дивіться також
Fancyindex: кастомізований список файлів для Nginx
/uk/