feat(reading): clean and refactor routing for books -> reading to separate paths

This commit is contained in:
Cory Dransfeldt 2025-05-16 13:03:55 -07:00
parent 8d9455940e
commit 2666d6ed67
No known key found for this signature in database
21 changed files with 51 additions and 89 deletions

View file

@ -90,7 +90,7 @@ class BookImportHandler extends ApiHandler
"author" => $author, "author" => $author,
"description" => $description, "description" => $description,
"read_status" => "want to read", "read_status" => "want to read",
"slug" => "/books/" . $isbn, "slug" => "/reading/books/" . $isbn,
]; ];
$this->makeRequest("POST", "books", ["json" => $bookPayload]); $this->makeRequest("POST", "books", ["json" => $bookPayload]);

View file

@ -8,7 +8,7 @@ export default {
.sort((a, b) => b.value - a.value) .sort((a, b) => b.value - a.value)
.map( .map(
(year, index) => (year, index) =>
`<a href="/books/years/${year.value}">${year.value}</a>${ `<a href="/reading/years/${year.value}">${year.value}</a>${
index < years.length - 1 ? " • " : "" index < years.length - 1 ? " • " : ""
}` }`
) )

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "5.1.6", "version": "6.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coryd.dev", "name": "coryd.dev",
"version": "5.1.6", "version": "6.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"html-minifier-terser": "7.2.0", "html-minifier-terser": "7.2.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "5.1.6", "version": "6.0.0",
"description": "The source for my personal site. Built using 11ty (and other tools).", "description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module", "type": "module",
"engines": { "engines": {

View file

@ -2,6 +2,7 @@
require_once "icons.php"; require_once "icons.php";
require_once "media.php"; require_once "media.php";
require_once "paginator.php"; require_once "paginator.php";
require_once "routing.php";
require_once "strings.php"; require_once "strings.php";
require_once "tags.php"; require_once "tags.php";
?> ?>

8
server/utils/routing.php Normal file
View file

@ -0,0 +1,8 @@
<?php
function redirectTo404(): void {
header("Location: /404/", true, 302);
exit();
}
?>

View file

@ -11,11 +11,11 @@
@import url("./base/index.css") layer(base); @import url("./base/index.css") layer(base);
/* page styles */ /* page styles */
@import url("./pages/books.css") layer(page);
@import url("./pages/contact.css") layer(page); @import url("./pages/contact.css") layer(page);
@import url("./pages/links.css") layer(page); @import url("./pages/links.css") layer(page);
@import url("./pages/media.css") layer(page); @import url("./pages/media.css") layer(page);
@import url("./pages/music.css") layer(page); @import url("./pages/music.css") layer(page);
@import url("./pages/reading.css") layer(page);
@import url("./pages/watching.css") layer(page); @import url("./pages/watching.css") layer(page);
@import url("./pages/webrings.css") layer(page); @import url("./pages/webrings.css") layer(page);

View file

@ -9,18 +9,12 @@
$requestUri = $_SERVER["REQUEST_URI"]; $requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/"); $url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
if (strpos($url, "music/artists/") !== 0) { if (strpos($url, "music/artists/") !== 0) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$fetcher = new ArtistFetcher(); $fetcher = new ArtistFetcher();
$artist = $fetcher->fetch($url); $artist = $fetcher->fetch($url);
if (!$artist) { if (!$artist) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$artist["description"] = parseMarkdown($artist["description"]); $artist["description"] = parseMarkdown($artist["description"]);
$pageTitle = htmlspecialchars("Artists • " . $artist["name"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Artists • " . $artist["name"], ENT_QUOTES, "UTF-8");

View file

@ -1,7 +1,7 @@
<?php <?php
require __DIR__ . "/../vendor/autoload.php"; require __DIR__ . "/../../vendor/autoload.php";
require __DIR__ . "/../server/utils/init.php"; require __DIR__ . "/../../server/utils/init.php";
use App\Classes\BookFetcher; use App\Classes\BookFetcher;
use voku\helper\HtmlMin; use voku\helper\HtmlMin;
@ -9,37 +9,12 @@
$requestUri = $_SERVER["REQUEST_URI"]; $requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/"); $url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
if (preg_match('/^books\/years\/(\d{4})$/', $url, $matches)) { if (!preg_match('/^reading\/books\/([\dXx-]+)$/', $url)) redirectTo404();
$year = $matches[1];
$filePath = __DIR__ . "/years/{$year}.html";
if (file_exists($filePath)) {
echo file_get_contents($filePath);
exit();
} else {
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
}
if ($url === "books/years" || $url === "books") {
$indexPath = $url === "books" ? "index.html" : __DIR__ . "/../404/index.html";
readfile($indexPath);
exit();
}
if (!preg_match('/^books\/[\w-]+$/', $url)) {
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
$fetcher = new BookFetcher(); $fetcher = new BookFetcher();
$book = $fetcher->fetch($url); $book = $fetcher->fetch($url);
if (!$book) { if (!$book) redirectTo404();
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
$book["description"] = parseMarkdown($book["description"]); $book["description"] = parseMarkdown($book["description"]);
$pageTitle = htmlspecialchars("Books • {$book["title"]} by {$book["author"]}", ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Books • {$book["title"]} by {$book["author"]}", ENT_QUOTES, "UTF-8");

View file

@ -9,18 +9,12 @@
$requestUri = $_SERVER["REQUEST_URI"]; $requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/"); $url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
if (!preg_match('/^music\/genres\/[\w-]+$/', $url)) { if (!preg_match('/^music\/genres\/[\w-]+$/', $url)) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$fetcher = new GenreFetcher(); $fetcher = new GenreFetcher();
$genre = $fetcher->fetch($url); $genre = $fetcher->fetch($url);
if (!$genre) { if (!$genre) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$pageTitle = htmlspecialchars("Genres • " . $genre["name"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Genres • " . $genre["name"], ENT_QUOTES, "UTF-8");
$pageDescription = truncateText( $pageDescription = truncateText(

View file

@ -9,18 +9,12 @@
$requestUri = $_SERVER["REQUEST_URI"]; $requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/"); $url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
if (!preg_match('/^watching\/movies\/[\w-]+$/', $url)) { if (!preg_match('/^watching\/movies\/[\w-]+$/', $url)) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$fetcher = new MovieFetcher(); $fetcher = new MovieFetcher();
$movie = $fetcher->fetch($url); $movie = $fetcher->fetch($url);
if (!$movie) { if (!$movie) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$movie["description"] = parseMarkdown($movie["description"]); $movie["description"] = parseMarkdown($movie["description"]);
$pageTitle = htmlspecialchars("Movies • " . $movie["title"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Movies • " . $movie["title"], ENT_QUOTES, "UTF-8");

View file

@ -9,18 +9,12 @@
$requestUri = $_SERVER["REQUEST_URI"]; $requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/"); $url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
if (!preg_match('/^watching\/shows\/[\w-]+$/', $url)) { if (!preg_match('/^watching\/shows\/[\w-]+$/', $url)) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$fetcher = new ShowFetcher(); $fetcher = new ShowFetcher();
$show = $fetcher->fetch($url); $show = $fetcher->fetch($url);
if (!$show) { if (!$show) redirectTo404();
echo file_get_contents(__DIR__ . "/../../404/index.html");
exit();
}
$pageTitle = htmlspecialchars("Show • " . $show["title"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Show • " . $show["title"], ENT_QUOTES, "UTF-8");
$pageDescription = truncateText( $pageDescription = truncateText(

View file

@ -14,10 +14,7 @@
exit(); exit();
} }
if (!preg_match('/^tags\/(.+?)(?:\/(\d+))?$/', $url, $matches)) { if (!preg_match('/^tags\/(.+?)(?:\/(\d+))?$/', $url, $matches)) redirectTo404();
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
if (isset($matches[2]) && (int)$matches[2] === 1) { if (isset($matches[2]) && (int)$matches[2] === 1) {
header("Location: /tags/{$matches[1]}", true, 301); header("Location: /tags/{$matches[1]}", true, 301);
@ -26,10 +23,7 @@
$tag = strtolower(urldecode($matches[1])); $tag = strtolower(urldecode($matches[1]));
if (!preg_match('/^[\p{L}\p{N} _\.\-\&]+$/u', $tag)) { if (!preg_match('/^[\p{L}\p{N} _\.\-\&]+$/u', $tag)) redirectTo404();
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
$page = isset($matches[2]) ? max(1, (int)$matches[2]) : 1; $page = isset($matches[2]) ? max(1, (int)$matches[2]) : 1;
$pageSize = 20; $pageSize = 20;
@ -37,7 +31,7 @@
$tagged = $fetcher->fetch($tag, $page, $pageSize); $tagged = $fetcher->fetch($tag, $page, $pageSize);
if (!$tagged || count($tagged) === 0) { if (!$tagged || count($tagged) === 0) {
echo file_get_contents(__DIR__ . '/../404/index.html'); header("Location: /404/", true, 302);
exit(); exit();
} }

View file

@ -51,7 +51,7 @@
{%- when 'books' -%} {%- when 'books' -%}
{%- assign overviewBook = books.all | filterBooksByStatus: 'started' | reverse | first %} {%- assign overviewBook = books.all | filterBooksByStatus: 'started' | reverse | first %}
{%- assign ogImage = ogImageBaseUrl | append: overviewBook.image -%} {%- assign ogImage = ogImageBaseUrl | append: overviewBook.image -%}
{%- when 'books-year' -%} {%- when 'reading-year' -%}
{%- assign pageTitle = 'Books' | append: ' • ' | append: year.value | append: ' • ' | append: globals.site_name -%} {%- assign pageTitle = 'Books' | append: ' • ' | append: year.value | append: ' • ' | append: globals.site_name -%}
{%- capture pageDescription -%} {%- capture pageDescription -%}
Here's what I read in {{ year.value }}. Here's what I read in {{ year.value }}.

View file

@ -30,10 +30,18 @@ ErrorDocument 500 /500/index.html
## artists ## artists
RewriteRule ^music/artists/([^/]+)/?$ music/artists/index.php [L] RewriteRule ^music/artists/([^/]+)/?$ music/artists/index.php [L]
## books ## reading
RewriteRule ^books/([^/]+)/?$ books/index.php [L]
RewriteRule ^books/years/(\d{4})/?$ books/years/index.html [L] ### redirects from books
RewriteRule ^books/?$ books/books.html [L] RedirectMatch 301 ^/books/years/(\d{4})/?$ /reading/years/$1
RedirectMatch 301 ^/books/years/?$ /reading/years
RedirectMatch 301 ^/books/((97[89][-]?\d{1,5}[-]?\d{1,7}[-]?\d{1,7}[-]?[\dXx]))/?$ /reading/books/$1
RedirectMatch 301 ^/books/?$ /reading
### routing
RewriteRule ^reading/?$ reading/index.html [L]
RewriteRule ^reading/years/(\d{4})/?$ reading/years/$1.html [L]
RewriteRule ^reading/books/([\dXx-]+)/?$ reading/books/index.php [L]
## movies ## movies
RewriteRule ^watching/movies/([^/]+)/?$ watching/movies/index.php [L] RewriteRule ^watching/movies/([^/]+)/?$ watching/movies/index.php [L]

View file

@ -1,9 +1,9 @@
--- ---
permalink: /books/index.php permalink: /reading/books/index.php
type: dynamic type: dynamic
schema: book schema: book
--- ---
<a class="back-link" href="/books" title="Go back to the books index page">{% tablericon "arrow-left" %} Back to books</a> <a class="back-link" href="/reading" title="Go back to the reading index page">{% tablericon "arrow-left" %} Back to reading</a>
<article class="book-focus"> <article class="book-focus">
<div class="book-display"> <div class="book-display">
<img <img

View file

@ -1,7 +1,7 @@
--- ---
title: Books title: Books
description: Here's what I'm reading at the moment. description: Here's what I'm reading at the moment.
permalink: "/books/index.html" permalink: "/reading/index.html"
schema: books schema: books
updated: "now" updated: "now"
--- ---

View file

@ -3,8 +3,8 @@ pagination:
data: books.years data: books.years
size: 1 size: 1
alias: year alias: year
permalink: "/books/years/{{ year.value }}/index.html" permalink: "/reading/years/{{ year.value }}/index.html"
schema: books-year schema: reading-year
--- ---
{%- assign bookData = year.data | filterBooksByStatus: 'finished' -%} {%- assign bookData = year.data | filterBooksByStatus: 'finished' -%}
{%- assign bookDataFavorites = bookData | findFavoriteBooks -%} {%- assign bookDataFavorites = bookData | findFavoriteBooks -%}
@ -12,7 +12,7 @@ schema: books-year
{%- assign currentYear = 'now' | date: "%Y" -%} {%- assign currentYear = 'now' | date: "%Y" -%}
{%- assign yearString = year.value | append: '' -%} {%- assign yearString = year.value | append: '' -%}
{%- assign currentYearString = currentYear | append: '' -%} {%- assign currentYearString = currentYear | append: '' -%}
<a href="/books" class="back-link">{% tablericon "arrow-left" %} Back to books</a> <a href="/reading" class="back-link">{% tablericon "arrow-left" %} Back to reading</a>
<h2 class="page-title">{{ year.value }} • Books</h2> <h2 class="page-title">{{ year.value }} • Books</h2>
{% if yearString == currentYearString %} {% if yearString == currentYearString %}
<p>I've finished <mark>{{ bookData.size }} book{% unless bookData.size == 1 %}s{% endunless %}</mark> this year.{%- if favoriteBooks %} Among my favorites are {{ favoriteBooks }}.{%- endif -%}</p> <p>I've finished <mark>{{ bookData.size }} book{% unless bookData.size == 1 %}s{% endunless %}</mark> this year.{%- if favoriteBooks %} Among my favorites are {{ favoriteBooks }}.{%- endif -%}</p>

View file

@ -5,7 +5,7 @@ description: Search through posts and other content on my site.
--- ---
<h2 class="page-title">Search</h2> <h2 class="page-title">Search</h2>
<p>You can find <a href="/posts">posts</a>, <a href="/links">links</a>, <a href="/music/#artists">artists</a>, genres, <a href="/watching#movies">movies</a>, <a href="/watching#tv">shows</a> and <a href="/books">books</a> via the field below (though it only surfaces movies and shows I've watched and books I've written something about). <a href="/tags">You can also browse my tags list</a>.</p> <p>You can find <a href="/posts">posts</a>, <a href="/links">links</a>, <a href="/music/#artists">artists</a>, genres, <a href="/watching#movies">movies</a>, <a href="/watching#tv">shows</a> and <a href="/reading">books</a> via the field below (though it only surfaces movies and shows I've watched and books I've written something about). <a href="/tags">You can also browse my tags list</a>.</p>
{% render "blocks/top-tags.liquid" {% render "blocks/top-tags.liquid"
label:"Top tags" label:"Top tags"
tags:topTags.tags tags:topTags.tags

View file

@ -5,7 +5,7 @@ description: Some basic stats about my activity on this site.
updated: "now" updated: "now"
--- ---
<h2 class="page-title">Stats</h2> <h2 class="page-title">Stats</h2>
<p>I share the <a href="/music" class="music">music I listen to</a>, <a href="/music/concerts" class="concerts">concerts I attend</a>, <a href="/watching" class="tv">shows and movies I watch</a>, <a href="/books" class="books">books I read</a>, <a href="/posts" class="article">posts I write</a>, and <a href="/links" class="link">links I enjoy</a> on this site. I have some basic counts of each below.</p> <p>I share the <a href="/music" class="music">music I listen to</a>, <a href="/music/concerts" class="concerts">concerts I attend</a>, <a href="/watching" class="tv">shows and movies I watch</a>, <a href="/reading" class="books">books I read</a>, <a href="/posts" class="article">posts I write</a>, and <a href="/links" class="link">links I enjoy</a> on this site. I have some basic counts of each below.</p>
<hr /> <hr />
<p class="music">I've listened to <mark>{{ stats.listen_count }} {{ stats.listen_count | pluralize: "track" }}</mark> by <mark>{{ stats.artist_count }} {{ stats.artist_count | pluralize: "artist" }}</mark> across <mark>{{ stats.genre_count }} {{ stats.genre_count | pluralize: "genre" }}</mark>.</p> <p class="music">I've listened to <mark>{{ stats.listen_count }} {{ stats.listen_count | pluralize: "track" }}</mark> by <mark>{{ stats.artist_count }} {{ stats.artist_count | pluralize: "artist" }}</mark> across <mark>{{ stats.genre_count }} {{ stats.genre_count | pluralize: "genre" }}</mark>.</p>
<p class="concerts">I've been to <mark>{{ stats.concert_count }} {{ stats.concert_count | pluralize: "concert" }}</mark> at <mark>{{ stats.venue_count }} {{ stats.venue_count | pluralize: "venue" }}</mark>.</p> <p class="concerts">I've been to <mark>{{ stats.concert_count }} {{ stats.concert_count | pluralize: "concert" }}</mark> at <mark>{{ stats.venue_count }} {{ stats.venue_count | pluralize: "venue" }}</mark>.</p>