5 // You can either provide them as environment variables
6 // or hard-code them in the empty strings below.
7 $baseUrl = getenv('BS_URL') ?: '';
8 $clientId = getenv('BS_TOKEN_ID') ?: '';
9 $clientSecret = getenv('BS_TOKEN_SECRET') ?: '';
12 // Can be provided as a arguments when calling the script
13 // or be hard-coded as strings below.
14 $outputFile = $argv[1] ?? './sitemap.xml';
19 // Check we have required options
20 if (empty($outputFile)) {
21 errorOut("An output file needs to be provided");
24 // Create the output folder if it does not exist
25 $outDir = dirname($outputFile);
26 if (!is_dir($outDir)) {
27 mkdir($outDir, 0777, true);
30 // Clean up the base path
31 $baseUrl = rtrim($baseUrl, '/');
33 // Additional endpoints not fetched via API entities
34 $nowDate = date_format(new DateTime(), 'Y-m-d');
35 $additionalEndpoints = [
36 ['endpoint' => '/', 'updated' => $nowDate],
37 ['endpoint' => '/books', 'updated' => $nowDate],
38 ['endpoint' => '/search', 'updated' => $nowDate],
39 ['endpoint' => '/login', 'updated' => $nowDate],
43 $shelves = getAllOfAtListEndpoint("api/shelves", []);
44 $shelfEndpoints = array_map(function ($shelf) {
45 return ['endpoint' => '/shelves/' . $shelf['slug'], 'updated' => $shelf['updated_at']];
48 // Get all book URLs and map for chapters & pages
49 $books = getAllOfAtListEndpoint("api/books", []);
51 $bookEndpoints = array_map(function ($book) use (&$bookSlugsById) {
52 $bookSlugsById[$book['id']] = $book['slug'];
53 return ['endpoint' => '/books/' . $book['slug'], 'updated' => $book['updated_at']];
56 // Get all chapter URLs and map for pages
57 $chapters = getAllOfAtListEndpoint("api/chapters", []);
58 $chapterEndpoints = array_map(function ($chapter) use ($bookSlugsById) {
59 $bookSlug = $bookSlugsById[$chapter['book_id']];
60 return ['endpoint' => '/books/' . $bookSlug . '/chapter/' . $chapter['slug'], 'updated' => $chapter['updated_at']];
64 $pages = getAllOfAtListEndpoint("api/pages", []);
65 $pageEndpoints = array_map(function ($page) use ($bookSlugsById) {
66 $bookSlug = $bookSlugsById[$page['book_id']];
67 return ['endpoint' => '/books/' . $bookSlug . '/page/' . $page['slug'], 'updated' => $page['updated_at']];
70 // Gather all our endpoints
71 $allEndpoints = $additionalEndpoints
77 // Fetch our sitemap XML
78 $xmlSitemap = generateSitemapXml($allEndpoints);
79 // Write to the output file
80 file_put_contents($outputFile, $xmlSitemap);
83 * Generate out the XML content for a sitemap
86 function generateSitemapXml(array $endpoints): string
89 $doc = new DOMDocument("1.0", "UTF-8");
90 $urlset = $doc->createElement('urlset');
91 $urlset->setAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
93 $doc->appendChild($urlset);
94 foreach ($endpoints as $endpointInfo) {
95 $date = (new DateTime($endpointInfo['updated']))->format('Y-m-d');
96 $url = $doc->createElement('url');
97 $loc = $url->appendChild($doc->createElement('loc'));
98 $urlText = $doc->createTextNode($baseUrl . $endpointInfo['endpoint']);
99 $loc->appendChild($urlText);
100 $url->appendChild($doc->createElement('lastmod', $date));
101 $url->appendChild($doc->createElement('changefreq', 'monthly'));
102 $url->appendChild($doc->createElement('priority', '0.8'));
103 $urlset->appendChild($url);
106 return $doc->saveXML();
110 * Consume all items from the given API listing endpoint.
112 function getAllOfAtListEndpoint(string $endpoint, array $params): array
119 $endpoint = $endpoint . '?' . http_build_query(array_merge($params, ['count' => $count, 'offset' => $offset]));
120 $resp = apiGetJson($endpoint);
122 $total = $resp['total'] ?? 0;
123 $new = $resp['data'] ?? [];
124 array_push($all, ...$new);
126 } while ($offset < $total);
132 * Make a simple GET HTTP request to the API.
134 function apiGet(string $endpoint): string
136 global $baseUrl, $clientId, $clientSecret;
137 $url = rtrim($baseUrl, '/') . '/' . ltrim($endpoint, '/');
138 $opts = ['http' => ['header' => "Authorization: Token {$clientId}:{$clientSecret}"]];
139 $context = stream_context_create($opts);
140 return @file_get_contents($url, false, $context);
144 * Make a simple GET HTTP request to the API &
145 * decode the JSON response to an array.
147 function apiGetJson(string $endpoint): array
149 $data = apiGet($endpoint);
150 return json_decode($data, true);
154 * DEBUG: Dump out the given variables and exit.
156 function dd(...$args)
158 foreach ($args as $arg) {
165 * Alert of an error then exit the script.
167 function errorOut(string $text)
169 echo "ERROR: " . $text;