summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Dockerfile6
-rw-r--r--Readme.md1
-rw-r--r--docker-compose.yml49
-rw-r--r--index.php105
-rw-r--r--mtg-pdf.php128
-rw-r--r--web.conf.template17
7 files changed, 207 insertions, 100 deletions
diff --git a/.gitignore b/.gitignore
index a4ea68a..1e29f20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
/output/
AllPrintings.sqlite
+.env
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..bbfce84
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,6 @@
+FROM php:fpm-alpine
+
+COPY index.php .
+COPY mtg-pdf.php .
+COPY vendor vendor
+COPY AllPrintings.sqlite .
diff --git a/Readme.md b/Readme.md
new file mode 100644
index 0000000..6508228
--- /dev/null
+++ b/Readme.md
@@ -0,0 +1 @@
+TODO: split into generic package and server service implementation
diff --git a/docker-compose.yml b/docker-compose.yml
index f2b177c..6c6add5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -3,14 +3,55 @@ version: "3"
services:
gotenberg:
image: "gotenberg/gotenberg:7"
+ networks:
+ - "internal"
- php:
- image: "php"
- links:
+ cli:
+ image: "php:cli-alpine"
+ depends_on:
- "gotenberg"
environment:
- "DECKLIST=${DECKLIST}"
volumes:
- "./:/usr/src/app"
+ networks:
+ - "internal"
working_dir: "/usr/src/app"
- command: ["php", "./index.php"]
+ command: ["php", "./mtg-pdf.php"]
+
+ php:
+ # image: php:fpm-alpine
+ build: .
+ depends_on:
+ - "gotenberg"
+ # volumes:
+ # - "./:/var/www/html"
+ networks:
+ - "internal"
+
+ web:
+ image: nginx:alpine
+ depends_on:
+ - "php"
+ environment:
+ - "DOMAIN=${DOMAIN}"
+ volumes:
+ - "./:/var/www/html"
+ - "./web.conf.template:/etc/nginx/templates/web.conf.template"
+ networks:
+ - "internal"
+ - "traefik"
+ labels:
+ - "traefik.enable=true"
+ - "traefik.docker.network=${TRAEFIK_NETWORK}"
+ - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`${DOMAIN}`)"
+ - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.entrypoints=websecure"
+ - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls=true"
+ - "traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.certresolver=letsencrypt"
+
+
+networks:
+ internal:
+ traefik:
+ name: "${TRAEFIK_NETWORK}"
+ external: true
diff --git a/index.php b/index.php
index 3132381..4f403a3 100644
--- a/index.php
+++ b/index.php
@@ -1,101 +1,14 @@
<?php
-use Gotenberg\Gotenberg;
-use Gotenberg\Stream;
-
-require_once __DIR__ . '/vendor/autoload.php';
-
-$decklist = $_ENV['DECKLIST'];
-
-/*
- * (\d+) ([\w\s]+) \(([\w\d]+)\) (\d+)
- * 2 Hall of Storm Giants (AFR) 257
- */
-
-preg_match_all("/(\d+) ([\w\s]+) \(([\w\d]+)\) (\d+)/", $decklist, $matches);
-$cards = [];
-for ($idx = 0; $idx < count($matches[0]); $idx++) {
- $cards[] = [
- 'quantity' => $matches[1][$idx],
- 'name' => $matches[2][$idx],
- 'set' => $matches[3][$idx],
- 'number' => $matches[4][$idx],
- ];
-}
-
-/*
- * SELECT scryfallId from cardIdentifiers
- * JOIN cards ON cardIdentifiers.uuid=cards.uuid
- * WHERE cards.setCode='$SETCODE' AND cards.number='$NUMBER';
- */
-
-$db = new \PDO('sqlite:AllPrintings.sqlite');
-
-$images = [];
-foreach ($cards as $card) {
- $query = 'SELECT scryfallId from cardIdentifiers JOIN cards on cardIdentifiers.uuid=cards.uuid WHERE cards.setCode=:setCode AND cards.number=:number';
- $statement = $db->prepare($query);
- $statement->execute(['setCode' => $card['set'], 'number' => $card['number']]);
-
- $id = $statement->fetchColumn()?: '';
-
- if (empty($id)) {
- continue;
- }
-
- // TODO: check double sided
-
- $images[] = [
- 'quantity' => $card['quantity'],
- 'src' => "https://cards.scryfall.io/png/front/" . substr($id, 0, 1) . "/" . substr($id, 1, 1) . "/$id.png",
- ];
+if (isset($_POST['decklist'])) {
+ $_ENV['DECKLIST'] = $_POST['decklist'];
+ include __DIR__ . '/mtg-pdf.php';
+ exit;
}
-// https://cards.scryfall.io/png/front/substr($scryfallId, 0, 1)/substr($scryfallId, 1, 1)/$scryfallId.png
-
-/*
- curl \
---request POST 'http://localhost:3000/forms/chromium/convert/html' \
---form 'files=@"./index.html"' \
--o my.pdf -F marginTop=0.0 -F marginBottom=0.0 -F marginRight=0.0 -F marginLeft=0.0
- */
-
-$template = <<<HTML
-<html>
- <head>
- <style>* { margin: 0; padding: 0; } html { } #bg { background-color: #fff; display: flex; flex-wrap: wrap; } img {display:block;}</style>
- <style>
- @media print {
- @page {
- }
- }
- html, body {
- padding: 0;
- margin: 0;
- }
- img {
- width: 2.49in;
- height: 3.48in;
- background-color: #16130e;
- background-color: #000;
- }
- </style>
- </head>
- <body>
- <div id="bg">{{imgs}}</div>
- </body>
-</html>
-HTML;
-
-$imgs = array_map(function ($image) {
- return str_repeat("<img src=\"$image[src]\">", $image['quantity']);
-}, $images);
-
-$html = str_replace('{{imgs}}', implode('', $imgs), $template);
-$request = Gotenberg::chromium('gotenberg:3000')
- ->paperSize(8.27, 11.7) # A4
- ->margins(0, 0, 0, 0)
- ->outputFilename(date("Ymd_His"))
- ->html(Stream::string('index.html', $html));
+?>
-Gotenberg::save($request, __DIR__ . '/output');
+<form action="" method="POST">
+ <textarea name="decklist"></textarea>
+ <button>Submit</button>
+</form>
diff --git a/mtg-pdf.php b/mtg-pdf.php
new file mode 100644
index 0000000..9b705b0
--- /dev/null
+++ b/mtg-pdf.php
@@ -0,0 +1,128 @@
+<?php
+
+use Gotenberg\Gotenberg;
+use Gotenberg\Stream;
+
+$decklist = $_ENV['DECKLIST'];
+if (empty($decklist)) {
+ die('No decklist provided.');
+}
+
+require_once __DIR__ . '/vendor/autoload.php';
+
+/*
+ * Match cards from input
+ */
+
+preg_match_all("/(\d+) (.+) \(([\w\d]+)\) (\d+\w*) ?([\*\w]*)/", $decklist, $matches);
+$cards = [];
+for ($idx = 0; $idx < count($matches[0]); $idx++) {
+ $cards[] = [
+ 'quantity' => $matches[1][$idx],
+ 'name' => $matches[2][$idx],
+ 'set' => $matches[3][$idx],
+ 'number' => $matches[4][$idx],
+ ];
+}
+
+/*
+ * Select data from DB
+ */
+
+$db = new \PDO('sqlite:AllPrintings.sqlite');
+
+$images = [];
+foreach ($cards as $card) {
+ $query = 'SELECT scryfallId,layout from cardIdentifiers JOIN cards on cardIdentifiers.uuid=cards.uuid WHERE cards.setCode=:setCode AND cards.number=:number';
+ $statement = $db->prepare($query);
+ $statement->execute(['setCode' => $card['set'], 'number' => $card['number']]);
+ $result = $statement->fetch();
+ $id = $result['scryfallId'] ?? '';
+
+ if (empty($id)) {
+ $query = 'SELECT scryfallId,layout from tokenIdentifiers JOIN tokens on tokenIdentifiers.uuid=tokens.uuid WHERE tokens.setCode=:setCode AND tokens.number=:number';
+ $statement = $db->prepare($query);
+ $statement->execute(['setCode' => $card['set'], 'number' => $card['number']]);
+ $result = $statement->fetch();
+ $id = $result['scryfallId'] ?? '';
+
+ if (empty($id)) {
+ echo "$card[name] ($card[set]) $card[number] not found.";
+ continue;
+ }
+ }
+
+ $images[] = [
+ 'quantity' => $card['quantity'],
+ 'src' => "https://cards.scryfall.io/png/front/" . substr($id, 0, 1) . "/" . substr($id, 1, 1) . "/$id.png",
+ 'alt' => $card['name'],
+ ];
+
+ if (in_array($result['layout'] ?? '', ['transform', 'double_faced_token'])) {
+ $images[] = [
+ 'quantity' => $card['quantity'],
+ 'src' => "https://cards.scryfall.io/png/back/" . substr($id, 0, 1) . "/" . substr($id, 1, 1) . "/$id.png",
+ 'alt' => $card['name'],
+ ];
+ }
+}
+
+/*
+ * Build HTML
+ */
+
+$template = <<<HTML
+<html>
+ <head>
+ <style>
+ html, body {
+ padding: 0;
+ margin: 0;
+ }
+
+ img {
+ width: 2.49in;
+ height: 3.48in;
+ display: block;
+ background-color: #16130e;
+ background-color: #000;
+ }
+
+ #bg {
+ display: flex;
+ flex-wrap: wrap;
+ }
+ </style>
+ </head>
+ <body>
+ <div id="bg">{{imgs}}</div>
+ </body>
+</html>
+HTML;
+
+$imgs = array_map(function ($image) {
+ return str_repeat("<img src=\"$image[src]\" alt=\"$image[alt]\">", $image['quantity']);
+}, $images);
+
+$html = str_replace('{{imgs}}', implode('', $imgs), $template);
+
+/*
+ * Build PDF
+ */
+
+$request = Gotenberg::chromium('gotenberg:3000')
+ ->paperSize(8.27, 11.7) # A4
+ ->margins(0, 0, 0, 0)
+ ->outputFilename(date("Ymd_His"))
+ ->html(Stream::string('index.html', $html));
+
+if (php_sapi_name() === 'cli') {
+ @mkdir(__DIR__ . '/output');
+ Gotenberg::save($request, __DIR__ . '/output');
+} else {
+ $response = Gotenberg::send($request);
+
+ header('Content-Type: application/pdf');
+ header('Content-Disposition: attachment; filename="' . date("Ymd_His") . '"');
+ echo $response->getBody();
+}
diff --git a/web.conf.template b/web.conf.template
new file mode 100644
index 0000000..36016fa
--- /dev/null
+++ b/web.conf.template
@@ -0,0 +1,17 @@
+server {
+ server_name ${DOMAIN};
+
+ root /var/www/html;
+ index index.php;
+
+ location / {
+ try_files $uri $uri/ /index.php$query_string;
+ }
+
+ location ~ \.php$ {
+ fastcgi_pass php:9000;
+ fastcgi_index index.php;
+ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
+ include fastcgi_params;
+ }
+}