diff options
| author | David T. Sadler <davidtsadler@googlemail.com> | 2021-05-14 17:12:36 +0100 |
|---|---|---|
| committer | David T. Sadler <davidtsadler@googlemail.com> | 2021-05-14 17:12:36 +0100 |
| commit | 5e627d4cbbfb46a05c8a704379d08955248b4ea3 (patch) | |
| tree | 53fac13157bcca991acd4e00b68177a7a0ef0997 | |
| parent | 7c375848a271cb179938e35c94fb3a18a49bf43a (diff) | |
Add atom feeds
| -rw-r--r-- | html_templates/default.html | 16 | ||||
| -rw-r--r-- | scripts/build.php | 6 | ||||
| -rw-r--r-- | scripts/functions.php | 197 | ||||
| -rw-r--r-- | src/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/arch/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/gemini/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/jigsaw/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/laravel/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/linux/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/markdown/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/netlify/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/nextcloud/index.gmi | 2 | ||||
| -rw-r--r-- | src/posts/php/index.gmi | 2 | ||||
| -rw-r--r-- | www_assets/css/site.css | 2 |
15 files changed, 183 insertions, 60 deletions
diff --git a/html_templates/default.html b/html_templates/default.html index e7a133d..b9ce3b6 100644 --- a/html_templates/default.html +++ b/html_templates/default.html @@ -6,8 +6,18 @@ <title>{{ $title }}</title> <link rel="shortcut icon" href="/images/favicon.png"> <link rel="stylesheet" href="/css/site.css"> + <link href="/posts/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts"/> + <link href="/posts/arch/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Arch"/> + <link href="/posts/gemini/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Gemini"/> + <link href="/posts/jigsaw/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Jigsaw"/> + <link href="/posts/laravel/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Laravel"/> + <link href="/posts/linux/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Linux"/> + <link href="/posts/markdown/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Markdown"/> + <link href="/posts/netlify/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Netlify"/> + <link href="/posts/nextcloud/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About Nextcloud"/> + <link href="/posts/php/atom.xml" type="application/atom+xml" rel="alternate" title="The Home of David T. Sadler - All Posts About PHP"/> </head> - <body> - <section>{{ $contents }}</section> - </body> + <body + <section>{{ $contents }}</section> + </body> </html> diff --git a/scripts/build.php b/scripts/build.php index ecb0d9d..eecb677 100644 --- a/scripts/build.php +++ b/scripts/build.php @@ -104,9 +104,9 @@ if (!is_readable($assetsDiretory)) { exit(1); } -$siteMetaData = getSiteMetaData($src); +$pages = getPages($src, $geminiOutput, $wwwOutput); -buildGeminiSite($siteMetaData, $geminiOutput); +buildGeminiSite($pages); -buildWWWSite($siteMetaData, $wwwOutput, $htmlTemplateDiretory, $assetsDiretory); +buildWWWSite($pages, $hostname, $htmlTemplateDiretory, $assetsDiretory, $wwwOutput); diff --git a/scripts/functions.php b/scripts/functions.php index f1f4e1e..50acc22 100644 --- a/scripts/functions.php +++ b/scripts/functions.php @@ -18,7 +18,7 @@ function usage(): void exit(1); } -function getSiteMetaData(string $src): array +function getPages(string $src, string $geminiOutput, string $wwwOutput): array { $src = realpath($src); @@ -27,57 +27,74 @@ function getSiteMetaData(string $src): array \RecursiveIteratorIterator::SELF_FIRST ); - $metaData = []; + $pages = []; foreach ($iter as $fileInfo) { if (!is_file($fileInfo->getRealPath())) { continue; } - $metaData[] = getFileMetaData($src, $fileInfo); + $pages[] = getPageMetaData($fileInfo, $src, $geminiOutput, $wwwOutput); } - return $metaData; + return $pages; } -function getFileMetaData(string $src, \SplFileInfo $fileInfo): array +function getPageMetaData(\SplFileInfo $fileInfo, string $src, string $geminiOutput, string $wwwOutput): array { $input = $fileInfo->getRealPath(); - $url = str_replace($src, '', $input); + $pathData = parsePath($input); + + $geminiUrl = str_replace($src, '', $input); + $wwwUrl = str_replace('.gmi', '.html', $geminiUrl); - $urlData = parseUrl($url); $contentData = parseContent(file_get_contents($input)); return [ - 'input' => $input, - 'url' => $url, - 'date' => $urlData['date'], - 'category' => $urlData['category'], - 'isPost' => $urlData['isPost'], - 'title' => $contentData['title'], - 'author' => $contentData['author'], + 'input' => $input, + 'geminiUrl' => $geminiUrl, + 'wwwUrl' => $wwwUrl, + 'date' => $pathData['date'], + 'tag' => $pathData['tag'], + 'isPost' => $pathData['isPost'], + 'isTag' => $pathData['isTag'], + 'title' => $contentData['title'], + 'author' => $contentData['author'], + 'html' => gemtext2hmtl(file_get_contents($input)), + 'geminiOutput' => "$geminiOutput$geminiUrl", + 'wwwOutput' => "$wwwOutput$wwwUrl", ]; } -function parseUrl(string $url): array +function parsePath(string $path): array { $date = null; - $category = null; + $tag = null; $isPost = false; + $isTag = false; /** - * Assume that only posts have both a date and a category. + * Assume that only posts have both a date and a tag. */ - if (preg_match('/\/posts\/(.+)\/(\d\d\d\d-\d\d-\d\d)\//', $url, $matches) === 1) { - $date = $matches[2]; - $category = $matches[1]; + if (preg_match('/\/posts\/(.+)\/(\d\d\d\d-\d\d-\d\d)\//', $path, $matches) === 1) { + [, $tag, $date] = $matches; + $isPost = true; } + /** + * Assume tags have an index file that contains related posts. + */ + if (preg_match('/posts\/(?:[^\/]|\/\/)+\/index/', $path, $matches) === 1) { + $tag = explode('/', $matches[0])[1]; + $isTag = true; + } + return [ - 'date' => $date, - 'category' => $category, - 'isPost' => $isPost, + 'date' => $date, + 'tag' => $tag, + 'isPost' => $isPost, + 'isTag' => $isTag, ]; } @@ -100,28 +117,24 @@ function parseContent(string $content): array ]; } -function buildGeminiSite(array $siteMetaData, string $output): void +function buildGeminiSite(array $pages): void { - foreach ($siteMetaData as $fileMetaData) { - $destFile = $output.DIRECTORY_SEPARATOR.$fileMetaData['url']; - - $destDirectory = dirname($destFile); + foreach ($pages as $page) { + $destDirectory = dirname($page['geminiOutput']); if (!file_exists($destDirectory) && !mkdir($destDirectory, 0777, true)) { echo "Unable to create Gemini site directory $destDirectory."; exit(1); } - copy($fileMetaData['input'], $destFile); + copy($page['input'], $page['geminiOutput']); } } -function buildWWWSite(array $siteMetaData, string $output, string $htmlTemplateDiretory, $assetsDiretory): void +function buildWWWSite(array $pages, string $hostname, string $htmlTemplateDiretory, $assetsDiretory, string $output): void { - foreach ($siteMetaData as $fileMetaData) { - $destFile = $output.DIRECTORY_SEPARATOR.$fileMetaData['url']; - - $destDirectory = dirname($destFile); + foreach ($pages as $page) { + $destDirectory = dirname($page['wwwOutput']); if (!file_exists($destDirectory) && !mkdir($destDirectory, 0777, true)) { echo "Unable to create WWW site directory $destDirectory."; @@ -129,19 +142,21 @@ function buildWWWSite(array $siteMetaData, string $output, string $htmlTemplateD } file_put_contents( - str_replace('.gmi', '.html', $destFile), + $page['wwwOutput'], buildHtmlFile( - $fileMetaData, - gemtext2hmtl(file_get_contents($fileMetaData['input'])), - $htmlTemplateDiretory + $page['title'], + $page['html'], + file_get_contents($htmlTemplateDiretory.DIRECTORY_SEPARATOR.'default.html') ) ); } copyWWWAssets($assetsDiretory, $output); + + generateAtomFeeds($pages, $hostname); } -function buildHtmlFile(array $fileMetaData, string $contents, string $htmlTemplateDiretory): string +function buildHtmlFile(string $title, string $contents, string $template): string { return str_replace( [ @@ -149,10 +164,10 @@ function buildHtmlFile(array $fileMetaData, string $contents, string $htmlTempla '{{ $contents }}' ], [ - $fileMetaData['title'], + $title, $contents, ], - file_get_contents($htmlTemplateDiretory.DIRECTORY_SEPARATOR.'default.html') + $template ); } @@ -222,7 +237,9 @@ function gemtext2hmtl(string $gemtext): string } elseif (preg_match(QUOTE, $line($index), $matches) === 1) { $html[] = "<blockquote>$matches[1]</blockquote>"; } else { - $html[] = "<p>{$line($index)}</p>"; + if ($line($index) !== '') { + $html[] = "<p>{$line($index)}</p>"; + } } $index++; @@ -261,3 +278,99 @@ function copyWWWAssets(string $assetsDiretory, string $output): void } } +function generateAtomFeeds(array $pages, string $hostname): void +{ + $posts = array_filter($pages, fn ($post) => $post['isPost']); + + $tags = array_filter($pages, fn ($post) => $post['isTag']); + + /** + * Sort by latest to previous date. + */ + usort($posts, fn ($a, $b) => $b['date'] <=> $a['date']); + + /** + * Group posts by tag. + */ + $groupedPosts = array_reduce($posts, function ($carry, $post) { + $carry[$post['tag']][] = $post; + + return $carry; + }, []); + + /** + * Put posts with their tag page. + */ + $tags = array_map(function ($tag) use ($groupedPosts) { + return array_merge($tag, ['posts' => $groupedPosts[$tag['tag']]]); + }, $tags); + + foreach ($tags as $tag) { + tagToAtomFeed($tag, $hostname); + } + + /** + * Get the page that lists all posts. + */ + $allPostsIndex = array_values(array_filter($pages, fn ($post) => preg_match('/posts\/index/', $post['wwwUrl']) == 1))[0]; + + $allPostsIndex['posts'] = $posts; + + tagToAtomFeed($allPostsIndex, $hostname); +} + +function tagToAtomFeed(array $tag, string $hostname): void +{ + file_put_contents( + str_replace('index.html', 'atom.xml', $tag['wwwOutput']), + buildAtomFeed( + $tag['title'], + "https://$hostname".str_replace('index.html', 'atom.xml', $tag['wwwUrl']), + "https://$hostname".$tag['wwwUrl'], + $tag['posts'][0]['date'].'T12:00:00Z', + implode('', array_map(fn ($post) => postToAtomEntry($post, $hostname), $tag['posts'])) + ) + ); +} + +function postToAtomEntry(array $post, string $hostname): string +{ + return buildAtomEntry( + $post['title'], + "https://$hostname{$post['wwwUrl']}", + $post['author'], + "{$post['date']}T12:00:00Z", + $post['html'], + ); +} + +function buildAtomFeed(string $title, string $href, string $altHref, string $date, string $entries): string +{ + return <<<EOF_STR +<?xml version="1.0" encoding="utf-8"?> +<feed xmlns="http://www.w3.org/2005/Atom"> + <title type="text">$title</title> + <id>$href</id> + <link rel="alternate" type="text/html" href="$altHref"/> + <link rel="self" type="application/atom+xml" href="$href"/> + <updated>$date</updated> + $entries +</feed> +EOF_STR; +} + +function buildAtomEntry(string $title, string $href, string $author, string $date, string $content): string +{ + return <<<EOF_STR +<entry> + <title type="text">$title</title> + <id>$href</id> + <link rel="alternate" type="text/html" href="$href"/> + <author><name>$author</name></author> + <published>$date</published> + <updated>$date</updated> + <content>![CDATA[$content]]</content> +</entry> +EOF_STR; +} + diff --git a/src/index.gmi b/src/index.gmi index f8508a4..88a4810 100644 --- a/src/index.gmi +++ b/src/index.gmi @@ -1,4 +1,4 @@ -# The home of David T. Sadler +# The Home of David T. Sadler Hello and welcome to my little bit of the internet where I occasionally write about things that interest me. You might find my posts interesting or you might not and that's okay. diff --git a/src/posts/arch/index.gmi b/src/posts/arch/index.gmi index caf235d..52b4756 100644 --- a/src/posts/arch/index.gmi +++ b/src/posts/arch/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Arch +# The Home of David T. Sadler - All Posts About Arch => /posts/arch/2020-09-07/installing-zsh-and-powerlevel10k-on-arch-linux/ 2020-09-07 - Installing Zsh and Powerlevel10k on Arch Linux => /posts/arch/2020-08-31/enabling-audio-in-arch-linux/ 2020-08-31 - Enabling Audio in Arch Linux diff --git a/src/posts/gemini/index.gmi b/src/posts/gemini/index.gmi index 8e39e23..6efe787 100644 --- a/src/posts/gemini/index.gmi +++ b/src/posts/gemini/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Gemini +# The Home of David T. Sadler - All Posts About Gemini => /posts/gemini/2021-02-08/how-to-host-your-own-gemini-site-in-the-cloud/ 2021-02-08 - How to Host Your Own Gemini Site in the Cloud diff --git a/src/posts/index.gmi b/src/posts/index.gmi index c56b346..2aad1f8 100644 --- a/src/posts/index.gmi +++ b/src/posts/index.gmi @@ -1,4 +1,4 @@ -# David T. Sadler's Posts +# The Home of David T. Sadler - All Posts => /posts/nextcloud/2021-02-15/accessing-nextcloud-with-webdav-on-arch/ 2021-02-15 - Accessing Nextcloud With WebDAV on Arch => /posts/gemini/2021-02-08/how-to-host-your-own-gemini-site-in-the-cloud/ 2021-02-08 - How to Host Your Own Gemini Site in the Cloud diff --git a/src/posts/jigsaw/index.gmi b/src/posts/jigsaw/index.gmi index c8752aa..d0700f2 100644 --- a/src/posts/jigsaw/index.gmi +++ b/src/posts/jigsaw/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Jigsaw +# The Home of David T. Sadler - All Posts About Jigsaw => /posts/jigsaw/2020-06-01/scheduling-posts-in-jigsaw/ 2020-06-01 - Scheduling Posts in Jigsaw diff --git a/src/posts/laravel/index.gmi b/src/posts/laravel/index.gmi index 6227b2c..6ee13bd 100644 --- a/src/posts/laravel/index.gmi +++ b/src/posts/laravel/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Laravel +# The Home of David T. Sadler - All Posts About Laravel => /posts/laravel/2020-12-21/installing-laravel-homestead-in-arch-linux/ 2020-12-21 - Installing Laravel Homestead in Arch Linux => /posts/laravel/2020-12-14/sqlstate-hy000-2002-php-network-getaddresses-getaddrinfo-failed/ 2020-12-14 - SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed diff --git a/src/posts/linux/index.gmi b/src/posts/linux/index.gmi index be90865..bb5e57a 100644 --- a/src/posts/linux/index.gmi +++ b/src/posts/linux/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Linux +# The Home of David T. Sadler - All Posts About Linux => /posts/linux/2020-07-13/sudo-sorry-you-must-have-a-tty-to-run-sudo/ 2020-07-13 - Sudo: sorry, you must have a tty to run sudo diff --git a/src/posts/markdown/index.gmi b/src/posts/markdown/index.gmi index 73f9a8e..94a4717 100644 --- a/src/posts/markdown/index.gmi +++ b/src/posts/markdown/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Markdown +# The Home of David T. Sadler - All Posts About Markdown => /posts/markdown/2020-03-30/creating-an-ebook-with-markdown/ 2020-03-30 - Creating an Ebook With Markdown diff --git a/src/posts/netlify/index.gmi b/src/posts/netlify/index.gmi index fa06136..3de8bee 100644 --- a/src/posts/netlify/index.gmi +++ b/src/posts/netlify/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Netlify +# The Home of David T. Sadler - All Posts About Netlify => /posts/netlify/2020-06-08/publishing-jigsaw-posts-with-netlify-build-hooks/ 2020-06-08 - Publishing Jigsaw Posts With Netlify Build Hooks diff --git a/src/posts/nextcloud/index.gmi b/src/posts/nextcloud/index.gmi index b9eeba5..99d6201 100644 --- a/src/posts/nextcloud/index.gmi +++ b/src/posts/nextcloud/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged Nextcloud +# The Home of David T. Sadler - All Posts About Nextcloud => /posts/nextcloud/2021-02-15/accessing-nextcloud-with-webdav-on-arch/ 2021-02-15 - Accessing Nextcloud With WebDAV on Arch diff --git a/src/posts/php/index.gmi b/src/posts/php/index.gmi index f0238a7..4e40910 100644 --- a/src/posts/php/index.gmi +++ b/src/posts/php/index.gmi @@ -1,4 +1,4 @@ -# All Posts Tagged PHP +# The Home of David T. Sadler - All Posts About PHP => /posts/php/2021-01-18/installing-php-8-for-windows-10/ 2021-01-18 - Installing PHP 8 for Windows 10 diff --git a/www_assets/css/site.css b/www_assets/css/site.css index 394e3e7..8e80eca 100644 --- a/www_assets/css/site.css +++ b/www_assets/css/site.css @@ -1,3 +1,3 @@ section a { - display: block; + display: block; } |
