diff options
Diffstat (limited to 'scripts')
| -rw-r--r-- | scripts/build.php | 6 | ||||
| -rw-r--r-- | scripts/functions.php | 197 |
2 files changed, 158 insertions, 45 deletions
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; +} + |
