Skip to content

Commit

Permalink
Рефакторит формирование RSS-ленты подкаста
Browse files Browse the repository at this point in the history
  • Loading branch information
monochromer committed Jan 17, 2025
1 parent b78aa04 commit 2bada55
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 108 deletions.
1 change: 0 additions & 1 deletion eleventy.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export default async function(eleventyConfig) {
templateFormats: [
'md',
'njk',
'11ty.js',
],
};
};
26 changes: 24 additions & 2 deletions src/eleventy-config/filters.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import hyphenLibRu from 'hyphen/ru/index.js';
import markdownIt from 'markdown-it';
import htmlmin from 'html-minifier-terser';
import { stripHeadings, stripLists } from '../libs/markdown-transforms.js';

const markdown = markdownIt({
html: true,
Expand Down Expand Up @@ -61,12 +62,33 @@ export default function(eleventyConfig) {
return markdown.renderInline(value);
});

eleventyConfig.addFilter('htmlmin', (value) => {
return htmlmin.minify(
eleventyConfig.addFilter('htmlmin', async(value) => {
return await htmlmin.minify(
value, {
collapseWhitespace: true,
removeEmptyElements: true,
}
);
});

eleventyConfig.addFilter('duration', (time) => {
// если длительность берётся из json-файла, то она задана в миллисекундах
if (typeof time === 'number') {
return Math.round(time / 1000);
}

return time.split(':').reduceRight((acc, item, index, items) => {
return acc += parseFloat(item) * Math.pow(60, items.length - 1 - index);
}, 0);
});

const podcastMarkdown = markdownIt({
html: true,
})
.use(stripHeadings)
.use(stripLists);

eleventyConfig.addFilter('podcastMarkdown', (content) => {
return podcastMarkdown.render(content);
});
};
62 changes: 62 additions & 0 deletions src/libs/markdown-transforms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
function stripHeadings(md) {
md.core.ruler.push('strip_headings', (state) => {
state.tokens.forEach((token) => {
if (token.type === 'heading_open') {
token.tag = 'p';
token.type = 'paragraph_open';
}

if (token.type === 'heading_close') {
token.tag = 'p';
token.type = 'paragraph_close';
}
});
});
}

function stripLists(md) {
md.core.ruler.push('strip_lists', (state) => {
let newTokens = [];
let isListItemProcessing = false;

state.tokens.forEach((token) => {
if (token.type === 'bullet_list_open') {
const listOpenToken = new state.Token('html_paragraph', 'p', 1);
newTokens.push(listOpenToken);
return;
}

if (token.type === 'bullet_list_close') {
const listCloseToken = new state.Token('html_paragraph', 'p', -1);
newTokens.push(listCloseToken);
return;
}

if (token.type === 'list_item_open') {
isListItemProcessing = true;
return;
}

if (token.type === 'list_item_close') {
isListItemProcessing = false;
return;
}

if (token.type === 'inline' && isListItemProcessing) {
const bulletToken = new state.Token('html_inline', '', 0);
bulletToken.content = '• ';
token.children.unshift(bulletToken);

const breakToken = new state.Token('html_inline', '', 0);
breakToken.content = '<br>';
token.children.push(breakToken);
}

newTokens.push(token);
});

state.tokens = newTokens;
});
}

export { stripHeadings, stripLists };
105 changes: 0 additions & 105 deletions src/pages/podcast/feed.11ty.js

This file was deleted.

75 changes: 75 additions & 0 deletions src/pages/podcast/feed.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
permalink: /podcast/feed/index.xml
---

<?xml version='1.0' encoding='utf-8'?>
<rss
version='2.0'
xmlns:atom='http://www.w3.org/2005/Atom'
xmlns:itunes='http://www.itunes.com/dtds/podcast-1.0.dtd'
xmlns:content='http://purl.org/rss/1.0/modules/content/'
>
<channel>
<title>{{podcast.title}}</title>
<description><![CDATA[{{podcast.description | inlineMarkdown | safe}}]]></description>
<copyright>{{podcast.copyright}}</copyright>
<language>{{podcast.language}}</language>
<link>{{podcast.url}}</link>

<atom:link href='{{podcast.url}}feed/' rel='self' type='application/rss+xml'/>

<itunes:subtitle>{{podcast.subtitle}}</itunes:subtitle>
<itunes:type>{{podcast.type}}</itunes:type>
<itunes:author>{{podcast.author}}</itunes:author>
<itunes:explicit>{{podcast.explicit}}</itunes:explicit>
<itunes:owner>
<itunes:name>{{podcast.owner.name}}</itunes:name>
<itunes:email>{{podcast.owner.email}}</itunes:email>
</itunes:owner>
<itunes:image href='{{podcast.url}}cover.png'/>

{% for category in podcast.categories %}
<itunes:category text='{{category.title}}'>
{% for categoryItem in category.items %}
<itunes:category text='{{categoryItem}}'/>
{% endfor %}
</itunes:category>
{% endfor %}

{% for episode in collections.episodes | reverse %}
{% set hosts = episode.data.hosts | join(', ') %}
<item>
<title>{{episode.fileSlug}}. {{episode.data.title}}</title>
<link>{{podcast.url}}{{episode.fileSlug}}/</link>
<pubDate>{{episode.date.toUTCString()}}</pubDate>
{% set hostsAndChaptersBlock %}
<p>Ведущие: {{hosts}}</p>
{% if episode.data.chapters.length > 0 %}
<p>Темы</p>
<p>
{% for chapter in episode.data.chapters %}
{{chapter.time}} {{chapter.title}}{% if not loop.last %}<br>{% endif %}
{% endfor %}
</p>
{% endif %}
{% endset %}
<description><![CDATA[
{{hostsAndChaptersBlock | safe}}
{{episode.rawInput | podcastMarkdown | htmlmin | safe }}
]]></description>
<guid isPermaLink='true'>{{podcast.url}}episodes/{{episode.fileSlug}}.mp3</guid>
<enclosure
type='audio/mpeg'
url='{{podcast.url}}episodes/{{episode.fileSlug}}.mp3'
length='{{episode.data.fileSize}}'
/>
<itunes:episode>{{episode.fileSlug}}</itunes:episode>
<itunes:duration>{{episode.data.duration | duration}}</itunes:duration>
<itunes:author>{{hosts}}</itunes:author>
<itunes:explicit>{{podcast.explicit}}</itunes:explicit>
<itunes:summary>{{episode.date | ruDate}}: {{episode.data.title}}. {{hosts}}</itunes:summary>
<itunes:image href='{{podcast.url}}cover.png'/>
</item>
{% endfor %}
</channel>
</rss>

0 comments on commit 2bada55

Please sign in to comment.