Commit 7b3d802f authored by nanahira's avatar nanahira

move deck print to frontend

parent 8bb310da
Pipeline #43465 passed with stages
in 57 seconds
......@@ -19,10 +19,11 @@ module.exports = {
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
extensions: ['.js', '.vue', '.json', '.mjs'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
'@': resolve('src'),
'ygopro-deck-encode': resolve('node_modules/ygopro-deck-encode/dist/index.cjs')
}
},
module: {
......@@ -37,6 +38,19 @@ module.exports = {
loader: 'babel-loader',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(m?js|cjs)$/,
loader: 'babel-loader',
include: [
resolve('node_modules/ygopro-deck-encode'),
resolve('node_modules/fonteditor-core')
],
options: {
babelrc: false,
presets: [['env', { modules: 'commonjs' }], 'stage-2'],
plugins: ['transform-runtime']
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
......@@ -52,6 +66,13 @@ module.exports = {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
},
{
test: /\.pdf$/,
loader: 'file-loader',
options: {
name: utils.assetsPath('pdf/[name].[hash:7].[ext]')
}
}
]
}
......
......@@ -8,6 +8,7 @@
"name": "ygopro-arena-web",
"version": "1.0.0",
"dependencies": {
"@pdf-lib/fontkit": "^1.1.1",
"bootstrap": "5.1.3",
"chokidar": "^3.5.2",
"datatables.net": "1.11.3",
......@@ -16,12 +17,14 @@
"echarts": "3.7.2",
"element-ui": "2.15.7",
"follow-redirects": "^1.14.7",
"fonteditor-core": "^2.6.3",
"glob-parent": "^6.0.2",
"is-svg": "^4.3.2",
"js-yaml": "2.1.3",
"moment": "^2.29.1",
"normalize-wheel": "^1.0.1",
"parse-asn1": "^5.1.6",
"pdf-lib": "^1.17.1",
"resize-observer-polyfill": "^1.5.1",
"shelljs": "0.7.7",
"swiper": "^7.3.1",
......@@ -33,7 +36,8 @@
"vue-router": "2.2.0",
"vuex": "2.4.0",
"watchpack": "2.3.1",
"watchpack-chokidar2": "2.0.1"
"watchpack-chokidar2": "2.0.1",
"ygopro-deck-encode": "^1.0.15"
},
"devDependencies": {
"autoprefixer": "6.7.2",
......@@ -232,6 +236,33 @@
"dev": true,
"license": "MIT"
},
"node_modules/@pdf-lib/fontkit": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@pdf-lib/fontkit/-/fontkit-1.1.1.tgz",
"integrity": "sha512-KjMd7grNapIWS/Dm0gvfHEilSyAmeLvrEGVcqLGi0VYebuqqzTbgF29efCx7tvx+IEbG3zQciRSWl3GkUSvjZg==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.6"
}
},
"node_modules/@pdf-lib/standard-fonts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz",
"integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.6"
}
},
"node_modules/@pdf-lib/upng": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@pdf-lib/upng/-/upng-1.0.1.tgz",
"integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==",
"license": "MIT",
"dependencies": {
"pako": "^1.0.10"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
......@@ -324,6 +355,15 @@
"node": ">=0.10.0"
}
},
"node_modules/@xmldom/xmldom": {
"version": "0.8.11",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
"integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/abbrev": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
......@@ -378,6 +418,7 @@
"integrity": "sha512-I/bSHSNEcFFqXLf91nchoNB9D1Kie3QKcWdchYUaoIg1+1bdWDkdfdlvdIOJbi9U8xR0y+MWc5D+won9v95WlQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"co": "^4.6.0",
"json-stable-stringify": "^1.0.1"
......@@ -670,6 +711,7 @@
"integrity": "sha512-Rrtz+eCX9d+sOkHEOFV3HfQ+ZF9w7caIOrKR8niL/0590dvzpTY/k3nmPz+31qQO2+i61j9+WB92MDANU4Gt3g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"babel-code-frame": "^6.22.0",
"babel-generator": "^6.22.0",
......@@ -2640,6 +2682,7 @@
"integrity": "sha512-wXYZA7VTtjeX2V/TnLAq5OENu5aZ0jpPd0bN3YaVUT2rxtflbIIzq+Afsc/jS0kC4i94E8XhVysG99M6n4wPlw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"babel-code-frame": "^6.11.0",
"css-selector-tokenizer": "^0.7.0",
......@@ -3643,6 +3686,7 @@
"integrity": "sha512-Ro8ieblJ0knrXQckM/GmO7xJtS4faazrjlpp1K9tJnFqFuY55A+6tZNxinhmUlTMpyx2zsXOFyDsNlMj6iH0Ig==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"loader-utils": "~0.2.5"
}
......@@ -3752,6 +3796,14 @@
}
}
},
"node_modules/fonteditor-core": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/fonteditor-core/-/fonteditor-core-2.6.3.tgz",
"integrity": "sha512-YUryIKjkenjZ41E7JvM3V+02Ak4mTHDDTwBWgs9KBzypzHqLZHuua1UDRevZNTKawmnq1dbBAa70Jddl2+F4FQ==",
"dependencies": {
"@xmldom/xmldom": "^0.8.3"
}
},
"node_modules/for-each": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz",
......@@ -6112,7 +6164,6 @@
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
"dev": true,
"license": "(MIT AND Zlib)"
},
"node_modules/param-case": {
......@@ -6359,6 +6410,18 @@
],
"license": "MIT"
},
"node_modules/pdf-lib": {
"version": "1.17.1",
"resolved": "https://registry.npmjs.org/pdf-lib/-/pdf-lib-1.17.1.tgz",
"integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==",
"license": "MIT",
"dependencies": {
"@pdf-lib/standard-fonts": "^1.0.0",
"@pdf-lib/upng": "^1.0.1",
"pako": "^1.0.11",
"tslib": "^1.11.1"
}
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
......@@ -8944,6 +9007,12 @@
"node": ">=0.10.0"
}
},
"node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
......@@ -9334,6 +9403,7 @@
"integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
"deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-sfc": "2.7.16",
"csstype": "^3.1.0"
......@@ -9467,6 +9537,7 @@
"integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"de-indent": "^1.0.2",
"he": "^1.2.0"
......@@ -9790,6 +9861,7 @@
"integrity": "sha512-zCuIqwJL7rC+Y4drtgNY2UizDAic1nRq+8m9LzOwB3s/jQWB++GxRWcZHja0ZzYiTLAwOFBHLDUmxD8ScbzKNg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"acorn": "^4.0.4",
"acorn-dynamic-import": "^2.0.0",
......@@ -10264,6 +10336,12 @@
"camelcase": "^3.0.0"
}
},
"node_modules/ygopro-deck-encode": {
"version": "1.0.15",
"resolved": "https://registry.npmjs.org/ygopro-deck-encode/-/ygopro-deck-encode-1.0.15.tgz",
"integrity": "sha512-NMvgWuC3SKant50RDu0bHa3QIRlwBhdTR3bNDrMpNthTTQmCCq8i2HZaWFiCmYIBi9fR3W9CkFIgK6hI4d+PzQ==",
"license": "MIT"
},
"node_modules/zrender": {
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/zrender/-/zrender-3.7.4.tgz",
......
......@@ -10,6 +10,7 @@
"replace": "sed -r -i 's/href=\\.\\//href=https:\\/\\/cdntx.moecube.com\\/ygopro\\//g' ./dist/index.html"
},
"dependencies": {
"@pdf-lib/fontkit": "^1.1.1",
"bootstrap": "5.1.3",
"chokidar": "^3.5.2",
"datatables.net": "1.11.3",
......@@ -18,12 +19,14 @@
"echarts": "3.7.2",
"element-ui": "2.15.7",
"follow-redirects": "^1.14.7",
"fonteditor-core": "^2.6.3",
"glob-parent": "^6.0.2",
"is-svg": "^4.3.2",
"js-yaml": "2.1.3",
"moment": "^2.29.1",
"normalize-wheel": "^1.0.1",
"parse-asn1": "^5.1.6",
"pdf-lib": "^1.17.1",
"resize-observer-polyfill": "^1.5.1",
"shelljs": "0.7.7",
"swiper": "^7.3.1",
......@@ -35,7 +38,8 @@
"vue-router": "2.2.0",
"vuex": "2.4.0",
"watchpack": "2.3.1",
"watchpack-chokidar2": "2.0.1"
"watchpack-chokidar2": "2.0.1",
"ygopro-deck-encode": "^1.0.15"
},
"devDependencies": {
"autoprefixer": "6.7.2",
......
......@@ -55,6 +55,7 @@
<!-- 只选择文件,不走旧的自动上传。保留 before/after 钩子最小侵入 -->
<el-upload
class="upload-demo"
action=""
:on-change="handleChange"
:auto-upload="false"
:file-list="fileList3">
......@@ -78,13 +79,9 @@
</template>
<script>
// 移除失效 API 的使用(最小改动:删除 import API 并清空相关字段的用途)
import querystring from 'querystring';
import crypto from 'crypto';
import { mapGetters } from 'vuex'
import moment from 'moment'
import tb_language from './tb_lang.js'
import Footads from './Footads'
import fillDeckForm from '@/utils/deckform/fill-deck-form'
export default {
components: { Footads },
......@@ -97,7 +94,6 @@ export default {
],
value: '1',
// 新增:译名选项
langOptions: [
{ value: 'jp', label: '日文官方译名' },
{ value: 'sc', label: '简中官方译名' },
......@@ -111,23 +107,11 @@ export default {
name: '',
event: '',
date: '',
// gameid -> lastInitial
lastInitial: '',
// 新增:译名取值
lang: 'jp',
},
formLabelWidth: '80px',
isNew: true,
isClick: false,
todayCount: 0,
// 旧的 uploadUrl / imageUrl / downloadPath 废弃
imageUrl: "",
downloadPath: "",
demo_title: "",
demo_url: "",
demo1: [],
checked2: false,
demo2: []
}
},
......@@ -150,12 +134,6 @@ export default {
this.fileList3 = fileList.slice(-1);
},
// 保留但不再使用旧上传回调
handleAvatarSuccess(res, file) {
// 不再使用旧下载路径
},
// 选择文件阶段可选校验:保持原逻辑最小复用(现在不自动上传,所以在提交时再严格校验)
beforeAvatarUpload(file) {
var type = /\.[^\.]+/.exec(file.name);
const isYDK = type && type[0] === '.ydk';
......@@ -172,21 +150,15 @@ export default {
return true;
},
// 旧下载方法废弃
download: function () {},
isIEMethod: function (ver) {
var b = document.createElement('b')
b.innerHTML = '<!--[if IE ' + ver + ']><i></i><![endif]-->'
return b.getElementsByTagName('i').length === 1
},
// 改为直传 /api/fill
async onSubmit() {
// 取出表单字段
const { name, event, date, lastInitial, lang } = this.form;
// 文件检查
if (!this.fileList3.length || !this.fileList3[0].raw) {
this.$notify({
title: '警告',
......@@ -197,52 +169,27 @@ export default {
}
const file = this.fileList3[0].raw;
// 轻量校验(沿用原限制)
const ok = this.beforeAvatarUpload(file);
if (!ok) return;
// === 全局 Loading 遮罩 ===
const loading = this.$loading({
lock: true,
text: '正在生成...',
text: '正在生成卡组表...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.3)'
});
try {
const qs = new URLSearchParams({
const ydkString = await file.text();
const blob = await fillDeckForm(ydkString, {
name: name || '',
event: event || '',
date: date || '',
lastInitial: lastInitial || '',
// 新增:把译名带给后端
lang: lang || ''
}).toString();
const formData = new FormData();
formData.append('file', file); // multipart/form-data
const resp = await fetch(`https://deckform.yuzurisa.com:444/api/fill?${qs}`, {
method: 'POST',
body: formData
lang: lang || 'jp',
});
if (!resp.ok) {
let errText = '生成失败';
try {
const ct = resp.headers.get('content-type') || '';
if (ct.includes('application/json')) {
const j = await resp.json();
errText = (j && j.message) || errText;
} else {
errText = await resp.text();
}
} catch (e) {}
this.$notify({ title: '错误', message: errText, type: 'error' });
return;
}
const blob = await resp.blob();
const url = URL.createObjectURL(blob);
const win = window.open(url, "_blank");
......@@ -252,16 +199,16 @@ export default {
}, 800);
}
} catch (e) {
console.error(e);
this.$notify({
title: '错误',
message: '网络异常或服务器错误',
message: e.message || '生成卡组表失败',
type: 'error'
});
} finally {
loading.close();
}
},
},
}
</script>
......
var YGOCDB_API = 'https://ygocdb.com/api/v0/card/';
function parseCardData(card) {
if (!card || !card.id || !card.data || !card.data.type) return null;
return {
id: card.id,
sc_name: card.sc_name || '',
cn_name: card.cn_name || '',
en_name: card.en_name || '',
jp_name: card.jp_name || '',
type: card.data.type & 0x7
};
}
export function fetchCardData(id) {
return fetch(YGOCDB_API + id + '?show=all')
.then(function (resp) {
if (!resp.ok) throw new Error('Card ID ' + id + ' not found');
return resp.json();
})
.then(function (card) {
var data = parseCardData(card);
if (!data) throw new Error('Card ID ' + id + ' has invalid data');
return data;
});
}
export function fetchCardDatas(ids) {
if (!ids || !ids.length) return Promise.resolve([]);
var uniqueIds = [];
var seen = {};
for (var i = 0; i < ids.length; i++) {
if (!seen[ids[i]]) {
seen[ids[i]] = true;
uniqueIds.push(ids[i]);
}
}
return Promise.all(uniqueIds.map(function (id) { return fetchCardData(id); }))
.then(function (results) {
var byId = {};
for (var i = 0; i < uniqueIds.length; i++) {
byId[uniqueIds[i]] = results[i];
}
return ids.map(function (id) { return byId[id]; });
});
}
export var Coordinates = {
name: { x: 377, y: 1986, width: 480, height: 54, fontSize: 31 },
event: { x: 1107, y: 1986, width: 359, height: 54, fontSize: 31 },
lastInitial: { x: 1286, y: 2057, width: 183, height: 58, fontSize: 33 },
dateFirst: { x: 375, y: 1905, width: 60, height: 56, fontSize: 32 },
main: {
monsters: {
qty: { x: 191, y: 1800, width: 61, height: 39, fontSize: 22 },
name: { x: 251, y: 1800, width: 366, height: 39, fontSize: 23 }
},
spells: {
qty: { x: 617, y: 1800, width: 61, height: 39, fontSize: 23 },
name: { x: 677, y: 1800, width: 366, height: 39, fontSize: 23 }
},
traps: {
qty: { x: 1043, y: 1800, width: 61, height: 39, fontSize: 23 },
name: { x: 1103, y: 1800, width: 366, height: 39, fontSize: 23 }
}
},
extra: {
qty: { x: 191, y: 913, width: 61, height: 39, fontSize: 22 },
name: { x: 251, y: 913, width: 366, height: 39, fontSize: 22 }
},
side: {
qty: { x: 617, y: 913, width: 61, height: 39, fontSize: 22 },
name: { x: 677, y: 913, width: 366, height: 39, fontSize: 22 }
},
totalFirst: { x: 1106, y: 913, width: 122, height: 39, fontSize: 22 }
};
export function moveDown(o, n) {
if (n === undefined) n = 1;
return Object.assign({}, o, {
y: o.y - o.height * n
});
}
export function moveRight(o, n) {
if (n === undefined) n = 1;
return Object.assign({}, o, {
x: o.x + o.width * n
});
}
import { rgb } from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import { Font } from 'fonteditor-core';
export function createDrawTextService() {
var operations = [];
function drawTextInBox(doc, text, options, pageIndex) {
if (pageIndex === undefined) pageIndex = -1;
if (!text) return;
operations.push({
text: text,
options: options,
pageIndex: pageIndex
});
}
function subsetFont(fontBuffer, text) {
var chars = {};
for (var i = 0; i < text.length; i++) {
chars[text.codePointAt(i)] = true;
}
var subset = Object.keys(chars).map(Number);
var font = Font.create(fontBuffer, {
type: 'ttf',
subset: subset,
hinting: true
});
return font.write({ type: 'ttf', hinting: true });
}
function drawTextWithFont(doc, font, text, options, pageIndex) {
if (!text) return;
var x = options.x;
var y = options.y;
var width = options.width;
var height = options.height;
var size = options.fontSize;
var page = doc.getPage(pageIndex);
var textWidth = font.widthOfTextAtSize(text, size);
if (textWidth > width) {
size = (width / textWidth) * size;
textWidth = font.widthOfTextAtSize(text, size);
}
var textHeight = font.heightAtSize(size);
if (textHeight > height) {
size = (height / textHeight) * size;
}
var truncated = text;
while (font.widthOfTextAtSize(truncated, size) > width && truncated.length > 0) {
truncated = truncated.slice(0, -1);
}
if (truncated.length < text.length) {
truncated = truncated.slice(0, -1) + '\u2026';
}
var finalWidth = font.widthOfTextAtSize(truncated, size);
var finalHeight = font.heightAtSize(size);
var drawX = x + (width - finalWidth) / 2;
var drawY = y + (height - finalHeight) / 2;
page.drawText(truncated, {
x: drawX,
y: drawY,
size: size,
font: font,
color: rgb(0, 0, 0),
maxWidth: width,
lineHeight: size * 1.1
});
}
function runBatch(doc, fontArrayBuffer) {
if (operations.length === 0) return Promise.resolve();
var allText = operations.map(function (op) { return op.text; }).join('');
var uniqueChars = Array.from(new Set(Array.from(allText))).join('');
var subsetBuffer = subsetFont(fontArrayBuffer, uniqueChars);
doc.registerFontkit(fontkit);
return doc.embedFont(subsetBuffer).then(function (embeddedFont) {
for (var i = 0; i < operations.length; i++) {
var op = operations[i];
if (op.pageIndex === -1) {
var pageCount = doc.getPageCount();
for (var p = 0; p < pageCount; p++) {
drawTextWithFont(doc, embeddedFont, op.text, op.options, p);
}
} else {
drawTextWithFont(doc, embeddedFont, op.text, op.options, op.pageIndex);
}
}
operations = [];
});
}
return {
drawTextInBox: drawTextInBox,
runBatch: runBatch
};
}
import { PDFDocument } from 'pdf-lib';
import YGOProDeck from 'ygopro-deck-encode';
import moment from 'moment';
import { Coordinates } from './coordinates';
import { moveDown, moveRight } from './draw-text-options';
import { createDrawTextService } from './draw-text';
import { fetchCardDatas } from './card-data';
import pdfTemplateUrl from '@/assets/deckform/deck_cn.pdf';
import fontUrl from '@/assets/deckform/textFont.ttf';
function groupBy(arr, fn) {
var result = {};
for (var i = 0; i < arr.length; i++) {
var key = fn(arr[i]);
if (!result[key]) result[key] = [];
result[key].push(arr[i]);
}
return result;
}
function chunk(arr, size) {
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}
function keyBy(arr, key) {
var result = {};
for (var i = 0; i < arr.length; i++) {
result[arr[i][key]] = arr[i];
}
return result;
}
function fetchAsArrayBuffer(url) {
return fetch(url).then(function (resp) {
if (!resp.ok) throw new Error('Failed to fetch ' + url);
return resp.arrayBuffer();
});
}
/**
* @param {string} ydkString - YDK file content
* @param {{ name?: string, event?: string, date?: string, lastInitial?: string, lang?: string }} opts
* @returns {Promise<Blob>} PDF blob
*/
export default function fillDeckForm(ydkString, opts) {
if (!opts) opts = {};
var ydk = YGOProDeck.fromYdkString(ydkString);
return Promise.all([
fetchAsArrayBuffer(pdfTemplateUrl),
fetchAsArrayBuffer(fontUrl)
]).then(function (buffers) {
var pdfBuffer = buffers[0];
var fontBuffer = buffers[1];
var allCardIds = [].concat(ydk.main, ydk.extra, ydk.side);
var uniqueIds = Array.from(new Set(allCardIds));
return fetchCardDatas(uniqueIds).then(function (cardDatas) {
return { pdfBuffer: pdfBuffer, fontBuffer: fontBuffer, cardDatas: cardDatas, uniqueIds: uniqueIds };
});
}).then(function (ctx) {
return PDFDocument.load(ctx.pdfBuffer).then(function (doc) {
ctx.doc = doc;
return ctx;
});
}).then(function (ctx) {
var doc = ctx.doc;
var fontBuffer = ctx.fontBuffer;
var cardDatas = ctx.cardDatas;
var uniqueIds = ctx.uniqueIds;
var drawText = createDrawTextService();
var directDrawFields = ['name', 'event', 'lastInitial'];
for (var f = 0; f < directDrawFields.length; f++) {
var field = directDrawFields[f];
if (opts[field]) {
drawText.drawTextInBox(doc, opts[field], Coordinates[field]);
}
}
if (opts.date) {
var date = moment(opts.date);
if (date.isValid()) {
var dateStr = date.format('DDMMYYYY');
var dateChars = dateStr.split('');
var datePrintStr = [
dateChars[0], dateChars[1], '-',
dateChars[2], dateChars[3], '-',
dateChars[6], dateChars[7]
];
for (var i = 0; i < datePrintStr.length; i++) {
drawText.drawTextInBox(doc, datePrintStr[i], moveRight(Coordinates.dateFirst, i));
}
}
}
var totalCounts = [ydk.main.length, ydk.extra.length, ydk.side.length];
for (var t = 0; t < 3; t++) {
drawText.drawTextInBox(doc, totalCounts[t].toString(), moveRight(Coordinates.totalFirst, t));
}
var aliasMap = {};
for (var a = 0; a < uniqueIds.length; a++) {
if (uniqueIds[a] !== cardDatas[a].id) {
aliasMap[uniqueIds[a]] = cardDatas[a].id;
}
}
var decks = [ydk.main, ydk.extra, ydk.side];
for (var d = 0; d < decks.length; d++) {
for (var j = 0; j < decks[d].length; j++) {
if (aliasMap[decks[d][j]] !== undefined) {
decks[d][j] = aliasMap[decks[d][j]];
}
}
}
var cardDataMap = keyBy(cardDatas, 'id');
var filterType = function (type) {
return ydk.main.filter(function (id) {
if (!cardDataMap[id]) throw new Error('Card ID ' + id + ' has invalid data');
return cardDataMap[id].type === type;
});
};
var pageCount = 0;
var copyFirstPageToBottom = function () {
return doc.copyPages(doc, [0]).then(function (pages) {
doc.addPage(pages[0]);
});
};
var ensurePages = function (pc) {
if (pageCount >= pc) return Promise.resolve();
var promises = [];
var addCount = pc - pageCount;
var chain = Promise.resolve();
for (var i = 0; i < addCount; i++) {
chain = chain.then(function () { return copyFirstPageToBottom(); });
}
pageCount = pc;
return chain;
};
var lang = opts.lang || 'sc';
var drawCards = function (cards, cord, spaces) {
if (spaces === undefined) spaces = 20;
var grouped = Object.values(groupBy(cards, function (id) { return id; }));
var pages = chunk(grouped, spaces);
return ensurePages(pages.length - 1).then(function () {
for (var pi = 0; pi < pages.length; pi++) {
var currentPageCards = pages[pi];
for (var ci = 0; ci < currentPageCards.length; ci++) {
var entry = currentPageCards[ci];
var qty = entry.length;
var cardData = cardDataMap[entry[0]];
var cardName = cardData[lang + '_name'];
if (!cardName) throw new Error('Card ID ' + cardData.id + ' does not have name for language ' + lang.toUpperCase());
drawText.drawTextInBox(doc, qty.toString(), moveDown(cord.qty, ci), pi);
drawText.drawTextInBox(doc, cardName, moveDown(cord.name, ci), pi);
}
var subtotal = currentPageCards.reduce(function (sum, e) { return sum + e.length; }, 0);
drawText.drawTextInBox(doc, subtotal.toString(), moveDown(cord.qty, spaces), pi);
}
});
};
return drawCards(filterType(1), Coordinates.main.monsters)
.then(function () { return drawCards(filterType(2), Coordinates.main.spells); })
.then(function () { return drawCards(filterType(4), Coordinates.main.traps); })
.then(function () { return drawCards(ydk.extra, Coordinates.extra, 15); })
.then(function () { return drawCards(ydk.side, Coordinates.side, 15); })
.then(function () { return drawText.runBatch(doc, fontBuffer); })
.then(function () { return doc.save(); })
.then(function (pdfBytes) {
return new Blob([pdfBytes], { type: 'application/pdf' });
});
});
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment