Skip to content

New RSS component #252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Mar 5, 2024
1 change: 1 addition & 0 deletions examples/official-site/blog.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ select 'shell' as component,
'Poppins' as font,
'https://cdn.jsdelivr.net/npm/prismjs@1/components/prism-core.min.js' as javascript,
'https://cdn.jsdelivr.net/npm/prismjs@1/plugins/autoloader/prism-autoloader.min.js' as javascript,
'./rss.sql' as rss,
'/prism-tabler-theme.css' as css;

SELECT 'text' AS component,
Expand Down
3 changes: 2 additions & 1 deletion examples/official-site/index.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ select 'shell' as component,
'blog' as menu_item,
'documentation' as menu_item,
19 as font_size,
'Poppins' as font;
'Poppins' as font,
'./rss.sql' as rss;

SELECT 'hero' as component,
'SQLPage' as title,
Expand Down
21 changes: 21 additions & 0 deletions examples/official-site/rss.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
select 'http_header' as component,
'application/rss+xml' as "Content-Type";
select 'shell-empty' as component;
select 'rss' as component,
'SQLPage blog' as title,
'https://sql.ophir.dev/blog.sql' as link,
'latest news about SQLpage' as description,
'en' as language,
'https://sql.ophir.dev/rss.sql' as self_link,
'Technology' as category,
'2de3f968-9928-5ec6-9653-6fc6fe382cfd' as guid;
SELECT title,
description,
CASE
WHEN external_url IS NOT NULL THEN external_url
ELSE 'https://sql.ophir.dev/blog.sql?post=' || title
END AS link,
created_at AS date,
false AS explicit
FROM blog_posts
ORDER BY created_at DESC;
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,7 @@ INSERT INTO parameter(component, name, description, type, top_level, optional) S
('link', 'The target of the link in the top navigation bar.', 'URL', TRUE, TRUE),
('css', 'The URL of a CSS file to load and apply to the page.', 'URL', TRUE, TRUE),
('javascript', 'The URL of a Javascript file to load and execute on the page.', 'URL', TRUE, TRUE),
('rss', 'The URL of an RSS feed to display in the top navigation bar. You can use the rss component to generate the field.', 'URL', TRUE, TRUE),
('image', 'The URL of an image to display next to the page title.', 'URL', TRUE, TRUE),
('icon', 'Name of an icon (from tabler-icons.io) to display next to the title in the navigation bar.', 'ICON', TRUE, TRUE),
('menu_item', 'Adds a menu item in the navigation bar at the top of the page. The menu item will have the specified name, and will link to as .sql file of the same name. A dropdown can be generated by passing a json object with a `title` and `submenu` properties.', 'TEXT', TRUE, TRUE),
Expand Down
273 changes: 273 additions & 0 deletions examples/official-site/sqlpage/migrations/37_rss.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
-- Documentation for the RSS component
INSERT INTO component (name, description, icon, introduced_in_version) VALUES (
'rss',
'Produces a data flow in the RSS format.
Can be used to generate a podcast feed.
To use this component, you must first return an HTTP header with the "application/rss+xml" content type (see http_header component). Next, you must use the shell-empty component to avoid that SQLPage generates HTML code.',
'rss',
'0.20.0'
);

INSERT INTO parameter (component,name,description,type,top_level,optional) VALUES (
'rss',
'title',
'Defines the title of the channel.',
'TEXT',
TRUE,
FALSE
),(
'rss',
'link',
'Defines the hyperlink to the channel.',
'URL',
TRUE,
FALSE
),(
'rss',
'description',
'Describes the channel.',
'TEXT',
TRUE,
FALSE
),(
'rss',
'language',
'Defines the language of the channel, specified in the ISO 639 format. For example, "en" for English, "fr" for French.',
'TEXT',
TRUE,
TRUE
),(
'rss',
'category',
'Defines the category of the channel. The value should be a string representing the category (e.g., "News", "Technology", etc.).',
'TEXT',
TRUE,
TRUE
),(
'rss',
'explicit',
'Indicates whether the channel contains explicit content. The value can be either TRUE or FALSE.',
'BOOLEAN',
TRUE,
TRUE
),(
'rss',
'image_url',
'Provides a URL linking to the artwork for the channel.',
'URL',
TRUE,
TRUE
),(
'rss',
'author',
'Defines the group, person, or people responsible for creating the channel.',
'TEXT',
TRUE,
TRUE
),(
'rss',
'copyright',
'Provides the copyright details for the channel.',
'TEXT',
TRUE,
TRUE
),(
'rss',
'self_link',
'URL of the RSS feed.',
'URL',
TRUE,
TRUE
),(
'rss',
'funding_url',
'Specifies the donation/funding links for the channel. The content of the tag is the recommended string to be used with the link.',
'URL',
TRUE,
TRUE
),(
'rss',
'type',
'Specifies the channel as either episodic or serial. The value can be either "episodic" or "serial".',
'TEXT',
TRUE,
TRUE
),(
'rss',
'complete',
'Specifies that a channel is complete and will not post any more items in the future.',
'BOOLEAN',
TRUE,
TRUE
),(
'rss',
'locked',
'Tells podcast hosting platforms whether they are allowed to import this feed.',
'BOOLEAN',
TRUE,
TRUE
),(
'rss',
'guid',
'The globally unique identifier (GUID) for a channel. The value is a UUIDv5.',
'TEXT',
TRUE,
TRUE
),(
'rss',
'title',
'Defines the title of the feed item (episode name, blog post title, etc.).',
'TEXT',
FALSE,
FALSE
),(
'rss',
'link',
'Defines the hyperlink to the item (blog post URL, etc.).',
'URL',
FALSE,
FALSE
),(
'rss',
'description',
'Describes the item',
'TEXT',
FALSE,
FALSE
),(
'rss',
'date',
'Indicates when the item was published (RFC-822 date-time).',
'TEXT',
FALSE,
TRUE
),(
'rss',
'enclosure_url',
'For podcast episodes, provides a URL linking to the audio/video episode content, in mp3, m4a, m4v, or mp4 format.',
'URL',
FALSE,
TRUE
),(
'rss',
'enclosure_length',
'The length in bytes of the audio/video episode content.',
'INTEGER',
FALSE,
TRUE
),(
'rss',
'enclosure_type',
'The MIME media type of the audio/video episode content (e.g., "audio/mpeg", "audio/m4a", "video/m4v", "video/mp4").',
'TEXT',
FALSE,
TRUE
),(
'rss',
'guid',
'The globally unique identifier (GUID) for an item.',
'TEXT',
FALSE,
TRUE
),(
'rss',
'episode',
'The chronological number that is associated with an item.',
'INTEGER',
FALSE,
TRUE
),(
'rss',
'season',
'The chronological number associated with an item''s season.',
'INTEGER',
FALSE,
TRUE
),(
'rss',
'episode_type',
'Defines the type of content for a specific item. The value can be either "full", "trailer", or "bonus".',
'TEXT',
FALSE,
TRUE
),(
'rss',
'block',
'Prevents a specific item from appearing in podcast listening applications.',
'BOOLEAN',
FALSE,
TRUE
),(
'rss',
'explicit',
'Indicates whether the item contains explicit content. The value can be either TRUE or FALSE.',
'BOOLEAN',
FALSE,
TRUE
),(
'rss',
'image_url',
'Provides a URL linking to the artwork for the item.',
'URL',
FALSE,
TRUE
),(
'rss',
'duration',
'The duration of an item in seconds.',
'INTEGER',
FALSE,
TRUE
),(
'rss',
'transcript_url',
'A link to a transcript or closed captions file for the item.',
'URL',
FALSE,
TRUE
),(
'rss',
'transcript_type',
'The type of the transcript or closed captions file for the item (e.g., "text/plain", "text/html", "text/vtt", "application/json", "application/x-subrip").',
'TEXT',
FALSE,
TRUE
);

-- Insert example(s) for the component
INSERT INTO example (component, description)
VALUES (
'rss',
'
### An RSS channel about SQLPage latest news.

```sql
select ''http_header'' as component, ''application/rss+xml'' as content_type;
select ''shell-empty'' as component;
select
''rss'' as component,
''SQLPage blog'' as title,
''https://sql.ophir.dev/blog.sql'' as link,
''latest news about SQLpage'' as description,
''en'' as language,
''Technology'' as category,
FALSE as explicit,
''https://sql.ophir.dev/favicon.ico'' as image_url,
''Ophir Lojkine'' as author,
''https://github.com/sponsors/lovasoa'' as funding_url,
''episodic'' as type;
select
''Hello everyone !'' as title,
''https://sql.ophir.dev/blog.sql?post=Come%20see%20me%20build%20twitter%20live%20on%20stage%20in%20Prague'' as link,
''If some of you european SQLPagers are around Prague this december, I will be giving a talk about SQLPage at pgconf.eu on December 14th.'' as description,
''http://127.0.0.1:8080/sqlpage_introduction_video.webm'' as enclosure_url,
123456789 as enclosure_length,
''video/webm'' as enclosure_type,
''2023-12-04'' as date;
```

Once you have your rss feed ready, you can submit it to podcast directories like
[Apple Podcasts](https://podcastsconnect.apple.com/my-podcasts),
[Spotify](https://podcasters.spotify.com/),
[Google Podcasts](https://podcastsmanager.google.com/)...
');
42 changes: 42 additions & 0 deletions sqlpage/templates/rss.handlebars
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
xmlns:podcast="https://podcastindex.org/namespace/1.0"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>{{title}}</title>
<link>{{link}}</link>
<description>{{description}}</description>
{{~#if language}}<language>{{language}}</language>{{/if}}
{{~#if category}}<itunes:category text="{{category}}">{{sub_category}}</itunes:category>{{/if}}
<itunes:explicit>{{#if explicit}}true{{else}}false{{/if}}</itunes:explicit>
{{~#if image_url}}<itunes:image href="{{image_url}}" />{{/if}}
{{~#if author}}<itunes:author>{{author}}</itunes:author>{{/if}}
{{~#if copyright}}<copyright>{{copyright}}</copyright>{{/if}}
{{~#if funding_url}}<podcast:funding url="{{funding_url}}">{{funding_text}}</podcast:funding>{{/if}}
{{~#if type}}<itunes:type>{{type}}</itunes:type>{{/if}}
{{~#if complete}}<itunes:complete>yes</itunes:complete>{{/if}}
{{~#if locked}}<podcast:locked>yes</podcast:locked>{{/if}}
{{~#if guid}}<podcast:guid>{{guid}}</podcast:guid>{{/if}}
{{~#if self_link}}<atom:link href="{{self_link}}" rel="self" type="application/rss+xml" />{{/if}}
{{#each_row}}
<item>
<title>{{title}}</title>
<link>{{link}}</link>
<description>{{description}}</description>
{{~#if date}}<pubDate>{{rfc2822_date date}}</pubDate>{{/if}}
{{~#if enclosure_url}}<enclosure length="{{enclosure_length}}" type="{{enclosure_type}}" url="{{enclosure_url}}" />{{/if}}
{{~#if guid}}<guid isPermaLink="false">{{guid}}</guid>{{/if}}
{{~#if episode}}<itunes:episode>{{episode}}</itunes:episode>{{/if}}
{{~#if season}}<itunes:season>{{season}}</itunes:season>{{/if}}
{{~#if episode_type}}<itunes:episodeType>{{episode_type}}</itunes:episodeType>{{/if}}
{{~#if block}}<itunes:block>yes</itunes:block>{{/if}}
{{~#if (not (eq explicit NULL))}}<itunes:explicit>{{#if explicit}}true{{else}}false{{/if}}</itunes:explicit>{{/if}}
{{~#if image_url}}<itunes:image href="{{image_url}}" />{{/if}}
{{~#if duration}}<itunes:duration>{{duration}}</itunes:duration>{{/if}}
{{~#if transcript_url}}<podcast:transcript url="{{transcript_url}}" type="{{transcript_type}}" />{{/if}}
</item>
{{/each_row}}
</channel>
</rss>
3 changes: 3 additions & 0 deletions sqlpage/templates/shell.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
{{#if refresh}}
<meta http-equiv="refresh" content="{{refresh}}">
{{/if}}
{{#if rss}}
<link rel="alternate" type="application/rss+xml" title="{{title}}" href="{{rss}}">
{{/if}}
<meta name="generator" content="SQLPage"/>
</head>

Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod app_config;
pub mod file_cache;
pub mod filesystem;
pub mod render;
pub mod template_helpers;
pub mod templates;
pub mod utils;
pub mod webserver;
Expand Down
Loading