From: Dan Brown Date: Sun, 3 Jan 2021 18:33:39 +0000 (+0000) Subject: Added static site script X-Git-Url: http://source.bookstackapp.com/api-scripts/commitdiff_plain/e45930b20a73c824755613706cf169577f090459 Added static site script --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..637d92c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea/ +node_modules/ \ No newline at end of file diff --git a/php-book-to-static-site/book-to-static.php b/php-book-to-static-site/book-to-static.php new file mode 100644 index 0000000..e41f330 --- /dev/null +++ b/php-book-to-static-site/book-to-static.php @@ -0,0 +1,217 @@ +#!/usr/bin/env php + $book['id']]); +$pages = getAllOfAtListEndpoint("api/pages", ['filter[book_id]' => $book['id']]); + +foreach ($pages as $index => $page) { + $pages[$index] = apiGetJson("api/pages/{$page['id']}"); +} + +if (!is_dir($outDir . "/images")) { + mkdir($outDir . "/images", 0777, true); +} + +$directBookPages = array_filter($pages, function($page) { + return empty($page['chapter_id']); +}); + +// Create book index file +$bookIndex = getBookContent($book, $chapters, $directBookPages); +file_put_contents($outDir . "/index.html", $bookIndex); + +foreach ($chapters as $chapter) { + $childPages = array_filter($pages, function($page) use ($chapter) { + return $page['chapter_id'] == $chapter['id']; + }); + $chapterPage = getChapterContent($chapter, $childPages); + file_put_contents($outDir . "/chapter-{$chapter['slug']}.html", $chapterPage); + + foreach ($childPages as $childPage) { + $childPageContent = getPageContent($childPage, $chapter); + $childPageContent = extractImagesFromHtml($childPageContent); + file_put_contents($outDir . "/page-{$childPage['slug']}.html", $childPageContent); + } +} + +foreach ($directBookPages as $directPage) { + $directPageContent = getPageContent($directPage, null); + $directPageContent = extractImagesFromHtml($directPageContent); + file_put_contents($outDir . "/page-{$directPage['slug']}.html", $directPageContent); +} + +function extractImagesFromHtml(string $html): string { + global $outDir; + $matches = []; + preg_match_all('//i', $html, $matches); + foreach (array_unique($matches[1] ?? []) as $url) { + $image = file_get_contents($url); + $name = basename($url); + $fileName = $name; + $count = 1; + while (file_exists($outDir . "/images/" . $fileName)) { + $fileName = $count . '-' . $name; + } + file_put_contents($outDir . "/images/" . $fileName, $image); + $html = str_replace($url, "./images/" . $fileName, $html); + } + return $html; +} + +function getImageFile($url): string { + global $apiUrl; + if (strpos(strtolower($url), strtolower($apiUrl)) === 0) { + $url = substr($url, strlen($apiUrl)); + return apiGet($url); + } + return file_get_contents($url); +} + +function getBookContent(array $book, array $chapters, array $pages): string { + $content = "

{$book['name']}

"; + $content .= "

{$book['description']}

"; + $content .= "
"; + if (count($chapters) > 0) { + $content .= "

Chapters

"; + } + if (count($pages) > 0) { + $content .= "

Pages

"; + } + return $content; +} + +function getChapterContent(array $chapter, array $pages): string { + $content = "

Back to book

"; + $content .= "

{$chapter['name']}

"; + $content .= "

{$chapter['description']}

"; + $content .= "
"; + if (count($pages) > 0) { + $content .= "

Pages

"; + } + return $content; +} + +function getPageContent(array $page, ?array $parentChapter): string { + if (is_null($parentChapter)) { + $content = "

Back to book

"; + } else { + $content = "

Back to chapter

"; + } + $content .= "

{$page['name']}

"; + $content .= "
{$page['html']}
"; + return $content; +} + +/** + * Get a single book by the slug or return null if not exists. + */ +function getBookBySlug(string $slug): ?array { + $endpoint = 'api/books?' . http_build_query(['filter[slug]' => $slug]); + $resp = apiGetJson($endpoint); + $book = $resp['data'][0] ?? null; + + if (!is_null($book)) { + $book = apiGetJson("api/books/{$book['id']}") ?? null; + } + return $book; +} + +/** + * Get all books from the system API. + */ +function getAllOfAtListEndpoint(string $endpoint, array $params): array { + $count = 100; + $offset = 0; + $total = 0; + $all = []; + + do { + $endpoint = $endpoint . '?' . http_build_query(array_merge($params, ['count' => $count, 'offset' => $offset])); + $resp = apiGetJson($endpoint); + + $total = $resp['total'] ?? 0; + $new = $resp['data'] ?? []; + array_push($all, ...$new); + $offset += $count; + } while ($offset < $total); + + return $all; +} + +/** + * Make a simple GET HTTP request to the API. + */ +function apiGet(string $endpoint): string { + global $apiUrl, $clientId, $clientSecret; + $url = rtrim($apiUrl, '/') . '/' . ltrim($endpoint, '/'); + $opts = ['http' => ['header' => "Authorization: Token {$clientId}:{$clientSecret}"]]; + $context = stream_context_create($opts); + return file_get_contents($url, false, $context); +} + +/** + * Make a simple GET HTTP request to the API & + * decode the JSON response to an array. + */ +function apiGetJson(string $endpoint): array { + $data = apiGet($endpoint); + return json_decode($data, true); +} + +/** + * DEBUG: Dump out the given variables and exit. + */ +function dd(...$args) { + foreach ($args as $arg) { + var_dump($arg); + } + exit(1); +} + +function errorOut(string $text) { + echo "ERROR: " . $text; + exit(1); +} \ No newline at end of file diff --git a/php-book-to-static-site/readme.md b/php-book-to-static-site/readme.md new file mode 100644 index 0000000..06f7560 --- /dev/null +++ b/php-book-to-static-site/readme.md @@ -0,0 +1,37 @@ +# Book to Static Site + +This script will export all chapters and pages within a given book to a folder +of basic HTML and image files which could act as a static site. + +Once ran, you should be able to open `index.html` within the output folder to start browsing. + +**This is a very simplistic single-script-file example of using the book, chapter and pages +API together**, the output lacks a lot of detail including styling and inter-content link transforming. + +## Requirements + +You will need php (~7.2+) installed on the machine you want to run this script on. +You will also need BookStack API credentials (TOKEN_ID & TOKEN_SECRET) at the ready. + +## Running + +```bash +# Downloading the script +curl https://raw.githubusercontent.com/BookStackApp/api-scripts/main/php-book-to-static-site/book-to-static.php > book-to-static.php + +# Setup +# ALTERNATIVELY: Open the script and edit the variables at the top. +export BS_URL=https://bookstack.example.com # Set to be your BookStack base URL +export BS_TOKEN_ID=abc123 # Set to be your API token_id +export BS_TOKEN_SECRET=123abc # Set to be your API token_secret + +# Running the script +php book-to-static.php +``` + +## Examples + +```bash +# Export a book with URL slug of my_book to an "out" directory +php book-to-static.php my_book ./out +``` \ No newline at end of file