diff --git a/api/Classes/ArtistFetcher.php b/api/Classes/ArtistFetcher.php new file mode 100644 index 0000000..08b6c14 --- /dev/null +++ b/api/Classes/ArtistFetcher.php @@ -0,0 +1,19 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $artist = $this->fetchSingleFromApi("optimized_artists", $url); + if (!$artist) return null; + + $this->cacheSet($cacheKey, $artist); + return $artist; + } +} diff --git a/api/Classes/BookFetcher.php b/api/Classes/BookFetcher.php new file mode 100644 index 0000000..1891967 --- /dev/null +++ b/api/Classes/BookFetcher.php @@ -0,0 +1,19 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $book = $this->fetchSingleFromApi("optimized_books", $url); + if (!$book) return null; + + $this->cacheSet($cacheKey, $book); + return $book; + } +} diff --git a/api/Classes/GenreFetcher.php b/api/Classes/GenreFetcher.php new file mode 100644 index 0000000..820741a --- /dev/null +++ b/api/Classes/GenreFetcher.php @@ -0,0 +1,19 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $genre = $this->fetchSingleFromApi("optimized_genres", $url); + if (!$genre) return null; + + $this->cacheSet($cacheKey, $genre); + return $genre; + } +} diff --git a/api/Classes/MovieFetcher.php b/api/Classes/MovieFetcher.php new file mode 100644 index 0000000..8a5814b --- /dev/null +++ b/api/Classes/MovieFetcher.php @@ -0,0 +1,19 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $movie = $this->fetchSingleFromApi("optimized_movies", $url); + if (!$movie) return null; + + $this->cacheSet($cacheKey, $movie); + return $movie; + } +} diff --git a/api/Classes/PageFetcher.php b/api/Classes/PageFetcher.php new file mode 100644 index 0000000..b94fc51 --- /dev/null +++ b/api/Classes/PageFetcher.php @@ -0,0 +1,29 @@ +cache && $this->cache->exists($key) ? json_decode($this->cache->get($key), true) : null; + } + + protected function cacheSet(string $key, mixed $value, int $ttl = 3600): void + { + if ($this->cache) $this->cache->setex($key, $ttl, json_encode($value)); + } + + protected function fetchSingleFromApi(string $endpoint, string $url): ?array + { + $data = $this->fetchFromApi($endpoint, "url=eq./{$url}"); + return $data[0] ?? null; + } + + protected function fetchPostRpc(string $endpoint, array $body): ?array + { + return $this->makeRequest("POST", $endpoint, ['json' => $body]); + } +} diff --git a/api/Classes/ShowFetcher.php b/api/Classes/ShowFetcher.php new file mode 100644 index 0000000..4fb0f80 --- /dev/null +++ b/api/Classes/ShowFetcher.php @@ -0,0 +1,19 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $show = $this->fetchSingleFromApi("optimized_shows", $url); + if (!$show) return null; + + $this->cacheSet($cacheKey, $show); + return $show; + } +} diff --git a/api/Classes/TagFetcher.php b/api/Classes/TagFetcher.php new file mode 100644 index 0000000..f0fce05 --- /dev/null +++ b/api/Classes/TagFetcher.php @@ -0,0 +1,26 @@ +cacheGet($cacheKey); + if ($cached) return $cached; + + $results = $this->fetchPostRpc("rpc/get_tagged_content", [ + "tag_query" => $tag, + "page_size" => $pageSize, + "page_offset" => $offset + ]); + + if (!$results || count($results) === 0) return null; + + $this->cacheSet($cacheKey, $results); + return $results; + } +} diff --git a/api/artist-import.php b/api/artist-import.php index 70a5934..d7b3b4d 100644 --- a/api/artist-import.php +++ b/api/artist-import.php @@ -1,6 +1,6 @@ connect('127.0.0.1', 6379); + + if ($redis->exists($cacheKey)) $js = $redis->get($cacheKey); + } + } catch (Exception $e) { + error_log("Redis unavailable: " . $e->getMessage()); + } + + if (!is_string($js)) { + $ch = curl_init($remoteUrl); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); + + $js = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + + curl_close($ch); + + if ($redis && $code === 200 && $js) $redis->setex($cacheKey, $ttl, $js); + } + + if (!is_string($js) || trim($js) === '') { + $js = '// Failed to fetch remote script'; + $code = 502; + } + + http_response_code($code); + header('Content-Type: application/javascript; charset=UTF-8'); + header('Cache-Control: public, max-age=60'); + echo $js; diff --git a/api/watching-import.php b/api/watching-import.php index 66ab1ba..7741c24 100644 --- a/api/watching-import.php +++ b/api/watching-import.php @@ -1,6 +1,6 @@ fetch($url); - try { - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1', 6379); - $useRedis = true; - } - } catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); - } - - if ($useRedis && $redis->exists($cacheKey)) { - $artist = json_decode($redis->get($cacheKey), true); - } else { - $apiUrl = "$postgrestUrl/optimized_artists?url=eq./" . $url; - $client = new Client(); - - try { - $response = $client->request("GET", $apiUrl, [ - "headers" => [ - "Accept" => "application/json", - "Authorization" => "Bearer {$postgrestApiKey}", - ], - ]); - - $artistData = json_decode($response->getBody(), true); - - if (!$artistData) { - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } - - $artist = $artistData[0]; - - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($artist)); - } - } catch (Exception $e) { - error_log($e->getMessage()); - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } + if (!$artist) { + echo file_get_contents(__DIR__ . "/../../404/index.html"); + exit(); } $artist["description"] = parseMarkdown($artist["description"]); - $pageTitle = htmlspecialchars( - "Artists • " . $artist["name"], - ENT_QUOTES, - "UTF-8" - ); - $pageDescription = truncateText(htmlspecialchars( - strip_tags($artist["description"]), - ENT_QUOTES, - "UTF-8" - ), 250); + $pageTitle = htmlspecialchars("Artists • " . $artist["name"], ENT_QUOTES, "UTF-8"); + $pageDescription = truncateText(htmlspecialchars(strip_tags($artist["description"]), ENT_QUOTES, "UTF-8"), 250); $ogImage = htmlspecialchars($artist["image"], ENT_QUOTES, "UTF-8"); $fullUrl = "https://www.coryd.dev" . $requestUri; $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; ob_start(); - header("Cache-Control: public, max-age=3600"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/includes/fetchers/book.php.liquid b/src/includes/fetchers/book.php.liquid index 3818280..e72c94e 100644 --- a/src/includes/fetchers/book.php.liquid +++ b/src/includes/fetchers/book.php.liquid @@ -1,14 +1,13 @@ fetch($url); - $book = null; - $useRedis = false; - try { - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1', 6379); - $useRedis = true; - } - } catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); - } - - if ($useRedis && $redis->exists($cacheKey)) { - $book = json_decode($redis->get($cacheKey), true); - } else { - $apiUrl = "$postgrestUrl/optimized_books?url=eq./" . $url; - $client = new Client(); - - try { - $response = $client->request("GET", $apiUrl, [ - "headers" => [ - "Accept" => "application/json", - "Authorization" => "Bearer {$postgrestApiKey}", - ], - ]); - - $bookData = json_decode($response->getBody(), true); - - if (!$bookData) { - echo file_get_contents(__DIR__ . "/../404/index.html"); - exit(); - } - - $book = $bookData[0]; - - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($book)); - } - } catch (Exception $e) { - error_log($e->getMessage()); - echo file_get_contents(__DIR__ . "/../404/index.html"); - exit(); - } + if (!$book) { + echo file_get_contents(__DIR__ . "/../404/index.html"); + exit(); } $book["description"] = parseMarkdown($book["description"]); - $pageTitle = htmlspecialchars( - "Books • " . $book["title"] . " by " . $book["author"], - ENT_QUOTES, - "UTF-8" - ); - $pageDescription = truncateText(htmlspecialchars( - strip_tags($book["description"]), - ENT_QUOTES, - "UTF-8" - ), 250); + $pageTitle = htmlspecialchars("Books • {$book["title"]} by {$book["author"]}", ENT_QUOTES, "UTF-8"); + $pageDescription = truncateText(htmlspecialchars(strip_tags($book["description"]), ENT_QUOTES, "UTF-8"), 250); $ogImage = htmlspecialchars($book["image"], ENT_QUOTES, "UTF-8"); $fullUrl = "https://www.coryd.dev" . $requestUri; $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; ob_start(); - header("Cache-Control: public, max-age=3600"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/includes/fetchers/genre.php.liquid b/src/includes/fetchers/genre.php.liquid index 3f0c5ad..8816c65 100644 --- a/src/includes/fetchers/genre.php.liquid +++ b/src/includes/fetchers/genre.php.liquid @@ -1,75 +1,37 @@ fetch($url); - try { - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1', 6379); - $useRedis = true; - } - } catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); - } - - if ($useRedis && $redis->exists($cacheKey)) { - $genre = json_decode($redis->get($cacheKey), true); - } else { - $apiUrl = "$postgrestUrl/optimized_genres?url=eq./" . $url; - $client = new Client(); - - try { - $response = $client->request("GET", $apiUrl, [ - "headers" => [ - "Accept" => "application/json", - "Authorization" => "Bearer {$postgrestApiKey}", - ], - ]); - - $genreData = json_decode($response->getBody(), true); - - if (!$genreData) { - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } - - $genre = $genreData[0]; - - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($genre)); - } - } catch (Exception $e) { - error_log($e->getMessage()); - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } + if (!$genre) { + echo file_get_contents(__DIR__ . "/../../404/index.html"); + exit(); } $pageTitle = htmlspecialchars("Genres • " . $genre["name"], ENT_QUOTES, "UTF-8"); - $pageDescription = truncateText(htmlspecialchars(strip_tags($genre["description"]), ENT_QUOTES, "UTF-8"), 250); - $ogImage = htmlspecialchars($genre["artists"][0]["image"], ENT_QUOTES, "UTF-8"); + $pageDescription = truncateText( + htmlspecialchars(strip_tags($genre["description"]), ENT_QUOTES, "UTF-8"), + 250 + ); + $ogImage = htmlspecialchars($genre["artists"][0]["image"] ?? "", ENT_QUOTES, "UTF-8"); $fullUrl = "https://www.coryd.dev" . $requestUri; $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; ob_start(); - header("Cache-Control: public, max-age=3600"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/includes/fetchers/movie.php.liquid b/src/includes/fetchers/movie.php.liquid index 02dd36b..53a3812 100644 --- a/src/includes/fetchers/movie.php.liquid +++ b/src/includes/fetchers/movie.php.liquid @@ -1,84 +1,35 @@ fetch($url); - try { - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1', 6379); - $useRedis = true; - } - } catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); - } - - if ($useRedis && $redis->exists($cacheKey)) { - $movie = json_decode($redis->get($cacheKey), true); - } else { - $apiUrl = "$postgrestUrl/optimized_movies?url=eq./" . $url; - $client = new Client(); - - try { - $response = $client->request("GET", $apiUrl, [ - "headers" => [ - "Accept" => "application/json", - "Authorization" => "Bearer {$postgrestApiKey}", - ], - ]); - - $movieData = json_decode($response->getBody(), true); - - if (!$movieData) { - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } - - $movie = $movieData[0]; - - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($movie)); - } - } catch (Exception $e) { - error_log($e->getMessage()); - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } + if (!$movie) { + echo file_get_contents(__DIR__ . "/../../404/index.html"); + exit(); } $movie["description"] = parseMarkdown($movie["description"]); - $pageTitle = htmlspecialchars( - "Movies • " . $movie["title"], - ENT_QUOTES, - "UTF-8" - ); - $pageDescription = truncateText(htmlspecialchars( - strip_tags($movie["description"]), - ENT_QUOTES, - "UTF-8" - ), 250); + $pageTitle = htmlspecialchars("Movies • " . $movie["title"], ENT_QUOTES, "UTF-8"); + $pageDescription = truncateText(htmlspecialchars(strip_tags($movie["description"]), ENT_QUOTES, "UTF-8"), 250); $ogImage = htmlspecialchars($movie["backdrop"], ENT_QUOTES, "UTF-8"); $fullUrl = "https://www.coryd.dev" . $requestUri; $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; ob_start(); - header("Cache-Control: public, max-age=3600"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/includes/fetchers/show.php.liquid b/src/includes/fetchers/show.php.liquid index 1466f4a..2e38f1b 100644 --- a/src/includes/fetchers/show.php.liquid +++ b/src/includes/fetchers/show.php.liquid @@ -1,75 +1,37 @@ fetch($url); - try { - if (extension_loaded('redis')) { - $redis = new Redis(); - $redis->connect('127.0.0.1', 6379); - $useRedis = true; - } - } catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); - } - - if ($useRedis && $redis->exists($cacheKey)) { - $show = json_decode($redis->get($cacheKey), true); - } else { - $apiUrl = "$postgrestUrl/optimized_shows?url=eq./" . $url; - $client = new Client(); - - try { - $response = $client->request("GET", $apiUrl, [ - "headers" => [ - "Accept" => "application/json", - "Authorization" => "Bearer {$postgrestApiKey}", - ], - ]); - - $showData = json_decode($response->getBody(), true); - - if (!$showData) { - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } - - $show = $showData[0]; - - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($show)); - } - } catch (Exception $e) { - error_log($e->getMessage()); - echo file_get_contents(__DIR__ . "/../../404/index.html"); - exit(); - } + if (!$show) { + echo file_get_contents(__DIR__ . "/../../404/index.html"); + exit(); } $pageTitle = htmlspecialchars("Show • " . $show["title"], ENT_QUOTES, "UTF-8"); - $pageDescription = truncateText(htmlspecialchars(strip_tags($show["description"]), ENT_QUOTES, "UTF-8"), 250); + $pageDescription = truncateText( + htmlspecialchars(strip_tags($show["description"]), ENT_QUOTES, "UTF-8"), + 250 + ); $ogImage = htmlspecialchars($show["image"], ENT_QUOTES, "UTF-8"); $fullUrl = "https://www.coryd.dev" . $requestUri; $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; ob_start(); - header("Cache-Control: public, max-age=3600"); header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/includes/fetchers/tags.php.liquid b/src/includes/fetchers/tags.php.liquid index 3eba3d2..2919d02 100644 --- a/src/includes/fetchers/tags.php.liquid +++ b/src/includes/fetchers/tags.php.liquid @@ -1,109 +1,64 @@ connect('127.0.0.1', 6379); - $useRedis = true; + if ($url === "tags") { + readfile("index.html"); + exit(); } -} catch (Exception $e) { - error_log("Redis not available: " . $e->getMessage()); -} -if ($useRedis && $redis->exists($cacheKey)) { - $tagged = json_decode($redis->get($cacheKey), true); -} else { - $client = new Client(); - try { - $response = $client->post($postgrestUrl . '/rpc/get_tagged_content', [ - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer {$postgrestApiKey}", - ], - 'json' => [ - 'tag_query' => $tag, - 'page_size' => $pageSize, - 'page_offset' => $offset - ] - ]); + if (!preg_match('/^tags\/(.+?)(?:\/(\d+))?$/', $url, $matches)) { + echo file_get_contents(__DIR__ . "/../404/index.html"); + exit(); + } - $tagged = json_decode($response->getBody(), true); - if ($useRedis) { - $redis->setex($cacheKey, 3600, json_encode($tagged)); - } - } catch (Exception $e) { - error_log($e->getMessage()); + if (isset($matches[2]) && (int)$matches[2] === 1) { + header("Location: /tags/{$matches[1]}", true, 301); + exit(); + } + + $tag = strtolower(urldecode($matches[1])); + + if (!preg_match('/^[\p{L}\p{N} _\.\-\&]+$/u', $tag)) { + echo file_get_contents(__DIR__ . "/../404/index.html"); + exit(); + } + + $page = isset($matches[2]) ? max(1, (int)$matches[2]) : 1; + $pageSize = 20; + $fetcher = new TagFetcher(); + $tagged = $fetcher->fetch($tag, $page, $pageSize); + + if (!$tagged || count($tagged) === 0) { echo file_get_contents(__DIR__ . '/../404/index.html'); exit(); } -} -if (!$tagged || count($tagged) === 0) { - echo file_get_contents(__DIR__ . '/../404/index.html'); - exit(); -} + $totalCount = $tagged[0]['total_count'] ?? 0; + $totalPages = max(ceil($totalCount / $pageSize), 1); + $pagination = [ + 'pageNumber' => $page, + 'pages' => range(1, $totalPages), + 'href' => [ + 'previous' => $page > 1 ? "/tags/{$tag}/" . ($page - 1) : null, + 'next' => $page < $totalPages ? "/tags/{$tag}/" . ($page + 1) : null + ], + 'links' => range(1, $totalPages) + ]; -$totalCount = $tagged[0]['total_count'] ?? 0; -$totalPages = max(ceil($totalCount / $pageSize), 1); -$pagination = [ - 'pageNumber' => $page, - 'pages' => range(1, $totalPages), - 'href' => [ - 'previous' => $page > 1 ? "/tags/{$tag}/" . ($page - 1) : null, - 'next' => $page < $totalPages ? "/tags/{$tag}/" . ($page + 1) : null - ], - 'links' => range(1, $totalPages) -]; - -$pageTitle = "#" . strtolower(ucfirst($tag)) . ""; -$pageDescription = "All content tagged with #" . strtolower(ucfirst($tag)) . "."; -$fullUrl = "https://www.coryd.dev" . $requestUri; -$oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; - -ob_start(); - -header("Cache-Control: public, max-age=3600"); -header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); + $pageTitle = "#" . strtolower(ucfirst($tag)); + $pageDescription = "All content tagged with #" . strtolower(ucfirst($tag)) . "."; + $fullUrl = "https://www.coryd.dev" . $requestUri; + $oembedUrl = "https://www.coryd.dev/oembed" . $requestUri; + ob_start(); + header("Cache-Control: public, max-age=3600"); + header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT"); ?> diff --git a/src/layouts/base.liquid b/src/layouts/base.liquid index 72331a4..a739fb9 100644 --- a/src/layouts/base.liquid +++ b/src/layouts/base.liquid @@ -28,7 +28,7 @@ eleventy:eleventy %} - +