maidraw 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/assets/themes/common/finale/achievement/a.png +0 -0
  2. package/assets/themes/common/finale/achievement/aa.png +0 -0
  3. package/assets/themes/common/finale/achievement/aaa.png +0 -0
  4. package/assets/themes/common/finale/achievement/b.png +0 -0
  5. package/assets/themes/common/finale/achievement/c.png +0 -0
  6. package/assets/themes/common/finale/achievement/d.png +0 -0
  7. package/assets/themes/common/finale/achievement/e.png +0 -0
  8. package/assets/themes/common/finale/achievement/f.png +0 -0
  9. package/assets/themes/common/finale/achievement/s.png +0 -0
  10. package/assets/themes/common/finale/achievement/sp.png +0 -0
  11. package/assets/themes/common/finale/achievement/ss.png +0 -0
  12. package/assets/themes/common/finale/achievement/ssp.png +0 -0
  13. package/assets/themes/common/finale/achievement/sss.png +0 -0
  14. package/assets/themes/common/finale/achievement/sssp.png +0 -0
  15. package/assets/themes/common/finale/background.png +0 -0
  16. package/assets/themes/common/finale/background2.png +0 -0
  17. package/assets/themes/common/finale/logo.png +0 -0
  18. package/assets/themes/common/finale/milestone/ap.png +0 -0
  19. package/assets/themes/common/finale/milestone/app.png +0 -0
  20. package/assets/themes/common/finale/milestone/fc.png +0 -0
  21. package/assets/themes/common/finale/milestone/fcp.png +0 -0
  22. package/assets/themes/common/finale/milestone/fdx.png +0 -0
  23. package/assets/themes/common/finale/milestone/fdxp.png +0 -0
  24. package/assets/themes/common/finale/milestone/fsp.png +0 -0
  25. package/assets/themes/common/finale/milestone/sync.png +0 -0
  26. package/assets/themes/common/versionless/void.png +0 -0
  27. package/assets/themes/jp/finaleLandscape/manifest.json +128 -0
  28. package/assets/themes/jp/finalePortrait/manifest.json +128 -0
  29. package/dist/index.d.ts +2 -31
  30. package/dist/index.js +3 -895
  31. package/dist/index.js.map +1 -1
  32. package/dist/mai/best50/index.d.ts +32 -0
  33. package/dist/mai/best50/index.js +858 -0
  34. package/dist/mai/best50/index.js.map +1 -0
  35. package/dist/{lib → mai/best50/lib}/divingFish/index.d.ts +40 -9
  36. package/dist/{lib → mai/best50/lib}/divingFish/index.js +46 -13
  37. package/dist/mai/best50/lib/divingFish/index.js.map +1 -0
  38. package/dist/{lib → mai/best50/lib}/index.d.ts +2 -3
  39. package/dist/{lib → mai/best50/lib}/index.js +1 -1
  40. package/dist/mai/best50/lib/index.js.map +1 -0
  41. package/dist/{lib → mai/best50/lib}/kamaiTachi/index.d.ts +85 -29
  42. package/dist/{lib → mai/best50/lib}/kamaiTachi/index.js +152 -13
  43. package/dist/mai/best50/lib/kamaiTachi/index.js.map +1 -0
  44. package/dist/{lib → mai/best50/lib}/lxns/index.d.ts +2 -4
  45. package/dist/{lib → mai/best50/lib}/lxns/index.js +5 -7
  46. package/dist/mai/best50/lib/lxns/index.js.map +1 -0
  47. package/dist/mai/chart/database.d.ts +11 -0
  48. package/dist/mai/chart/database.js +63 -0
  49. package/dist/mai/chart/database.js.map +1 -0
  50. package/dist/mai/chart/index.d.ts +4 -0
  51. package/dist/mai/chart/index.js +9 -0
  52. package/dist/mai/chart/index.js.map +1 -0
  53. package/dist/mai/index.d.ts +6 -0
  54. package/dist/mai/index.js +11 -0
  55. package/dist/mai/index.js.map +1 -0
  56. package/package.json +1 -1
  57. package/test/jp-finale-landscape.webp +0 -0
  58. package/test/jp-finale-portrait.webp +0 -0
  59. package/test/testDraw.js +17 -8
  60. package/dist/lib/divingFish/index.js.map +0 -1
  61. package/dist/lib/index.js.map +0 -1
  62. package/dist/lib/kamaiTachi/index.js.map +0 -1
  63. package/dist/lib/lxns/index.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,901 +1,9 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.MaiDraw = exports.DivingFish = exports.KamaiTachi = exports.LXNS = void 0;
7
- const fs_1 = __importDefault(require("fs"));
8
- const upath_1 = __importDefault(require("upath"));
9
- const type_1 = require("./type");
10
- const canvas_1 = require("canvas");
11
- const axios_1 = __importDefault(require("axios"));
12
- const color_1 = __importDefault(require("color"));
13
- const sharp_1 = __importDefault(require("sharp"));
14
- const memory_cache_1 = require("memory-cache");
15
- const glob_1 = require("glob");
16
- var lxns_1 = require("./lib/lxns");
17
- Object.defineProperty(exports, "LXNS", { enumerable: true, get: function () { return lxns_1.LXNS; } });
18
- var kamaiTachi_1 = require("./lib/kamaiTachi");
19
- Object.defineProperty(exports, "KamaiTachi", { enumerable: true, get: function () { return kamaiTachi_1.KamaiTachi; } });
20
- var divingFish_1 = require("./lib/divingFish");
21
- Object.defineProperty(exports, "DivingFish", { enumerable: true, get: function () { return divingFish_1.DivingFish; } });
22
- class HalfFullWidthConvert {
23
- static charsets = {
24
- latin: { halfRE: /[!-~]/g, fullRE: /[!-~]/g, delta: 0xfee0 },
25
- hangul1: { halfRE: /[ᄀ-ᄒ]/g, fullRE: /[ᆨ-ᇂ]/g, delta: -0xedf9 },
26
- hangul2: { halfRE: /[ᅡ-ᅵ]/g, fullRE: /[ᅡ-ᅵ]/g, delta: -0xee61 },
27
- kana: {
28
- delta: 0,
29
- half: "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚",
30
- full: "。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシ" +
31
- "スセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゛゜",
32
- },
33
- extras: {
34
- delta: 0,
35
- half: "¢£¬¯¦¥₩\u0020|←↑→↓■°",
36
- full: "¢£¬ ̄¦¥₩\u3000│←↑→↓■○",
37
- },
38
- };
39
- // @ts-ignore
40
- static toFull = (set) => (c) => set.delta
41
- ? String.fromCharCode(c.charCodeAt(0) + set.delta)
42
- : [...set.full][[...set.half].indexOf(c)];
43
- // @ts-ignore
44
- static toHalf = (set) => (c) => set.delta
45
- ? String.fromCharCode(c.charCodeAt(0) - set.delta)
46
- : [...set.half][[...set.full].indexOf(c)];
47
- // @ts-ignore
48
- static re = (set, way) => set[way + "RE"] || new RegExp("[" + set[way] + "]", "g");
49
- static sets = Object.values(this.charsets);
50
- // @ts-ignore
51
- static toFullWidth = (str0) => this.sets.reduce((str, set) => str.replace(this.re(set, "half"), this.toFull(set)), str0);
52
- // @ts-ignore
53
- static toHalfWidth = (str0) => this.sets.reduce((str, set) => str.replace(this.re(set, "full"), this.toHalf(set)), str0);
54
- }
3
+ exports.MaiDraw = void 0;
4
+ const mai_1 = require("./mai");
55
5
  class MaiDraw {
56
- localDatabasePath;
57
- get assetsPath() {
58
- return upath_1.default.join(__dirname, "..", "assets");
59
- }
60
- themes = {};
61
- hasTheme(name) {
62
- return !!this.themes[name];
63
- }
64
- constructor(localDatabasePath = "") {
65
- this.localDatabasePath = localDatabasePath;
66
- const manifests = (0, glob_1.globSync)(upath_1.default.join(this.assetsPath, "themes", "**", "manifest.json"));
67
- for (const manifestPath of manifests) {
68
- const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, "utf-8"));
69
- if (this.validateManifest(manifest, upath_1.default.dirname(manifestPath))) {
70
- this.themes[manifest.name] = upath_1.default.dirname(manifestPath);
71
- }
72
- }
73
- const loadThemeResult = this.loadTheme("cn-2024-landscape");
74
- // const loadThemeResult = this.loadTheme("jp-buddiesplus-portrait");
75
- // const loadThemeResult = this.loadTheme("jp-buddiesplus-landscape");
76
- // const loadThemeResult = this.loadTheme("jp-buddies-landscape");
77
- if (!loadThemeResult) {
78
- console.error("Failed to load theme.");
79
- }
80
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "gen-jyuu-gothic", "GenJyuuGothic-Bold.ttf"), {
81
- family: "standard-font-title-jp",
82
- });
83
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "comfortaa", "Comfortaa-Bold.ttf"), {
84
- family: "standard-font-title-latin",
85
- weight: "regular",
86
- });
87
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "seurat-db", "FOT-Seurat Pro DB.otf"), {
88
- family: "standard-font-username",
89
- weight: "regular",
90
- });
91
- }
92
- hasLocalDatabase() {
93
- return fs_1.default.existsSync(this.localDatabasePath);
94
- }
95
- validateManifest(payload, path) {
96
- function isFileExist(p) {
97
- if (isString(p))
98
- return fs_1.default.existsSync(upath_1.default.join(path, p));
99
- else
100
- return false;
101
- }
102
- function isOneOf(p, ...args) {
103
- return args.includes(p);
104
- }
105
- function isString(p) {
106
- return typeof p == "string";
107
- }
108
- function isNumber(p) {
109
- return typeof p == "number";
110
- }
111
- function isArray(p) {
112
- return Array.isArray(p);
113
- }
114
- function isObject(p) {
115
- return typeof p == "object";
116
- }
117
- function isHexColor(p) {
118
- if (isString(p))
119
- return /^(?:#[0-9A-F]{6}|#[0-9A-F]{8})$/i.test(p);
120
- else
121
- return false;
122
- }
123
- if (isString(payload.displayName) &&
124
- isString(payload.name) &&
125
- isNumber(payload.width) &&
126
- isNumber(payload.height) &&
127
- isObject(payload.sprites) &&
128
- isObject(payload.sprites.achievement) &&
129
- isFileExist(payload.sprites.achievement.d) &&
130
- isFileExist(payload.sprites.achievement.c) &&
131
- isFileExist(payload.sprites.achievement.b) &&
132
- isFileExist(payload.sprites.achievement.bb) &&
133
- isFileExist(payload.sprites.achievement.bbb) &&
134
- isFileExist(payload.sprites.achievement.a) &&
135
- isFileExist(payload.sprites.achievement.aa) &&
136
- isFileExist(payload.sprites.achievement.aaa) &&
137
- isFileExist(payload.sprites.achievement.s) &&
138
- isFileExist(payload.sprites.achievement.sp) &&
139
- isFileExist(payload.sprites.achievement.ss) &&
140
- isFileExist(payload.sprites.achievement.ssp) &&
141
- isFileExist(payload.sprites.achievement.sss) &&
142
- isFileExist(payload.sprites.achievement.sssp) &&
143
- isObject(payload.sprites.mode) &&
144
- isFileExist(payload.sprites.mode.standard) &&
145
- isFileExist(payload.sprites.mode.dx) &&
146
- isObject(payload.sprites.milestone) &&
147
- isFileExist(payload.sprites.milestone.ap) &&
148
- isFileExist(payload.sprites.milestone.app) &&
149
- isFileExist(payload.sprites.milestone.fc) &&
150
- isFileExist(payload.sprites.milestone.fcp) &&
151
- isFileExist(payload.sprites.milestone.fdx) &&
152
- isFileExist(payload.sprites.milestone.fdxp) &&
153
- isFileExist(payload.sprites.milestone.fs) &&
154
- isFileExist(payload.sprites.milestone.fsp) &&
155
- isFileExist(payload.sprites.milestone.sync) &&
156
- isFileExist(payload.sprites.milestone.none) &&
157
- isObject(payload.sprites.dxRating) &&
158
- isFileExist(payload.sprites.dxRating.white) &&
159
- isFileExist(payload.sprites.dxRating.blue) &&
160
- isFileExist(payload.sprites.dxRating.green) &&
161
- isFileExist(payload.sprites.dxRating.yellow) &&
162
- isFileExist(payload.sprites.dxRating.red) &&
163
- isFileExist(payload.sprites.dxRating.purple) &&
164
- isFileExist(payload.sprites.dxRating.bronze) &&
165
- isFileExist(payload.sprites.dxRating.silver) &&
166
- isFileExist(payload.sprites.dxRating.gold) &&
167
- isFileExist(payload.sprites.dxRating.platinum) &&
168
- isFileExist(payload.sprites.dxRating.rainbow) &&
169
- isObject(payload.sprites.profile) &&
170
- isFileExist(payload.sprites.profile.icon) &&
171
- isFileExist(payload.sprites.profile.nameplate) &&
172
- isFileExist(payload.sprites.dxRatingNumberMap) &&
173
- isArray(payload.elements)) {
174
- for (const element of payload.elements) {
175
- if (isNumber(element.x) && isNumber(element.y)) {
176
- switch (element.type) {
177
- case "image": {
178
- if (isNumber(element.width) &&
179
- isNumber(element.height) &&
180
- isFileExist(element.path)) {
181
- continue;
182
- }
183
- else
184
- return false;
185
- }
186
- case "score-grid": {
187
- if (isOneOf(element.region, "old", "new") &&
188
- isNumber(element.horizontalSize) &&
189
- isNumber(element.verticalSize) &&
190
- isNumber(element.index) &&
191
- isObject(element.scoreBubble) &&
192
- isNumber(element.scoreBubble.width) &&
193
- isNumber(element.scoreBubble.height) &&
194
- isNumber(element.scoreBubble.margin) &&
195
- isNumber(element.scoreBubble.gap) &&
196
- isObject(element.scoreBubble.color) &&
197
- isHexColor(element.scoreBubble.color.basic) &&
198
- isHexColor(element.scoreBubble.color.advanced) &&
199
- isHexColor(element.scoreBubble.color.expert) &&
200
- isHexColor(element.scoreBubble.color.master) &&
201
- isHexColor(element.scoreBubble.color.remaster) &&
202
- isHexColor(element.scoreBubble.color.utage)) {
203
- continue;
204
- }
205
- else
206
- return false;
207
- }
208
- case "profile": {
209
- if (isNumber(element.height)) {
210
- continue;
211
- }
212
- else
213
- return false;
214
- }
215
- default:
216
- return false;
217
- }
218
- }
219
- }
220
- return true;
221
- }
222
- else
223
- return false;
224
- }
225
- primaryTheme = null;
226
- primaryThemePath = null;
227
- loadTheme(path) {
228
- const theme = this.getTheme(path);
229
- if (theme) {
230
- this.primaryTheme = theme.manifest;
231
- this.primaryThemePath = theme.path;
232
- return true;
233
- }
234
- else
235
- return false;
236
- }
237
- getTheme(path) {
238
- if (!fs_1.default.existsSync(upath_1.default.join(this.assetsPath, path, "manifest.json"))) {
239
- path = this.themes[path] ?? "";
240
- }
241
- else
242
- path = upath_1.default.join(this.assetsPath, path);
243
- if (fs_1.default.existsSync(upath_1.default.join(path, "manifest.json"))) {
244
- const manifest = JSON.parse(fs_1.default.readFileSync(upath_1.default.join(path, "manifest.json"), "utf-8"));
245
- if (this.validateManifest(manifest, path)) {
246
- return { manifest, path };
247
- }
248
- }
249
- return null;
250
- }
251
- getThemeFile(path, themePath) {
252
- if (typeof path == "string" &&
253
- fs_1.default.existsSync(upath_1.default.join(themePath ?? this.primaryThemePath, path)))
254
- return fs_1.default.readFileSync(upath_1.default.join(themePath ?? this.primaryThemePath, path));
255
- else
256
- return Buffer.from([]);
257
- }
258
- async draw(name, rating, newScores, oldScores, options) {
259
- function drawText(ctx, str, x, y, fontSize, linewidth, maxWidth, textAlign = "left", mainColor = "white", borderColor = "black", font = `"standard-font-title-latin", "standard-font-title-jp"`) {
260
- function findMaxFitString(original) {
261
- const metrics = ctx.measureText(original);
262
- if (metrics.width <= maxWidth)
263
- return original;
264
- for (let i = 1; i < original.length; ++i) {
265
- let cur = original.slice(0, original.length - i);
266
- if (ctx.measureText(cur + "...").width <= maxWidth) {
267
- while (cur[cur.length - 1] == " ") {
268
- cur = cur.substring(0, cur.length - 1);
269
- }
270
- return cur.trim() + "...";
271
- }
272
- }
273
- return original;
274
- }
275
- ctx.font = `${fontSize}px ${font}`;
276
- str = findMaxFitString(str);
277
- if (linewidth > 0) {
278
- ctx.strokeStyle = borderColor;
279
- ctx.lineWidth = linewidth;
280
- ctx.lineCap = "round";
281
- ctx.lineJoin = "round";
282
- ctx.textAlign = textAlign;
283
- ctx.strokeText(str, x, y);
284
- }
285
- ctx.fillStyle = mainColor;
286
- ctx.font = `${fontSize}px ${font}`;
287
- ctx.textAlign = textAlign;
288
- ctx.fillText(str, x, y);
289
- if (linewidth > 0) {
290
- ctx.strokeStyle = mainColor;
291
- ctx.lineWidth = linewidth / 8;
292
- ctx.lineCap = "round";
293
- ctx.lineJoin = "round";
294
- ctx.font = `${fontSize}px ${font}`;
295
- ctx.textAlign = textAlign;
296
- ctx.strokeText(str, x, y);
297
- }
298
- }
299
- await this.cacheJackets([
300
- ...newScores.map((v) => v.chart.id),
301
- ...oldScores.map((v) => v.chart.id),
302
- ]);
303
- let currentTheme = this.primaryTheme, currentThemePath = this.primaryThemePath;
304
- if (options?.theme) {
305
- const theme = this.getTheme(options.theme);
306
- if (theme) {
307
- currentTheme = theme.manifest;
308
- currentThemePath = theme.path;
309
- }
310
- }
311
- if (currentTheme && currentThemePath) {
312
- const canvas = new canvas_1.Canvas(currentTheme.width * (options?.scale ?? 1), currentTheme.height * (options?.scale ?? 1));
313
- const ctx = canvas.getContext("2d");
314
- if (options?.scale)
315
- ctx.scale(options.scale, options.scale);
316
- ctx.imageSmoothingEnabled = true;
317
- for (const element of currentTheme.elements) {
318
- switch (element.type) {
319
- case "image": {
320
- const img = new canvas_1.Image();
321
- img.src = this.getThemeFile(element.path, currentThemePath);
322
- ctx.drawImage(img, element.x, element.y, element.width, element.height);
323
- break;
324
- }
325
- case "score-grid": {
326
- const promises = [];
327
- for (let cury = element.y, curindex = element.index, i = 0; i < element.verticalSize; ++i,
328
- cury +=
329
- element.scoreBubble.height +
330
- element.scoreBubble.gap) {
331
- for (let curx = element.x, j = 0; j < element.horizontalSize; ++j,
332
- ++curindex,
333
- curx +=
334
- element.scoreBubble.width +
335
- element.scoreBubble.gap) {
336
- let curScore;
337
- if (element.region == "new")
338
- curScore = newScores[curindex];
339
- else
340
- curScore = oldScores[curindex];
341
- if (curScore) {
342
- let curColor = "#FFFFFF";
343
- switch (curScore.chart.difficulty) {
344
- case type_1.EDifficulty.BASIC:
345
- curColor =
346
- element.scoreBubble.color.basic;
347
- break;
348
- case type_1.EDifficulty.ADVANCED:
349
- curColor =
350
- element.scoreBubble.color
351
- .advanced;
352
- break;
353
- case type_1.EDifficulty.EXPERT:
354
- curColor =
355
- element.scoreBubble.color
356
- .expert;
357
- break;
358
- case type_1.EDifficulty.MASTER:
359
- curColor =
360
- element.scoreBubble.color
361
- .master;
362
- break;
363
- case type_1.EDifficulty.REMASTER:
364
- curColor =
365
- element.scoreBubble.color
366
- .remaster;
367
- break;
368
- case type_1.EDifficulty.UTAGE:
369
- curColor =
370
- element.scoreBubble.color.utage;
371
- break;
372
- }
373
- /** Begin Card Draw */
374
- ctx.save();
375
- ctx.fillStyle = new color_1.default(curColor)
376
- .lighten(0.4)
377
- .hexa();
378
- ctx.beginPath();
379
- ctx.roundRect(curx, cury, element.scoreBubble.width, element.scoreBubble.height, (element.scoreBubble.height * 0.806) / 7);
380
- ctx.strokeStyle = new color_1.default(curColor)
381
- .darken(0.3)
382
- .hexa();
383
- ctx.lineWidth =
384
- element.scoreBubble.margin / 4;
385
- ctx.stroke();
386
- ctx.fill();
387
- ctx.beginPath();
388
- ctx.roundRect(curx, cury, element.scoreBubble.width, element.scoreBubble.height, (element.scoreBubble.height * 0.806) / 7);
389
- ctx.clip();
390
- /** Begin Main Content Draw */
391
- ctx.save();
392
- ctx.beginPath();
393
- ctx.roundRect(curx, cury, element.scoreBubble.width, element.scoreBubble.height * 0.742, (element.scoreBubble.height * 0.806) / 7);
394
- ctx.clip();
395
- ctx.fillStyle = curColor;
396
- ctx.fill();
397
- const jacketSize = Math.min(element.scoreBubble.width, element.scoreBubble.height * 0.742);
398
- const jacketMaskGrad = ctx.createLinearGradient(curx + jacketSize / 2, cury + jacketSize / 2, curx + jacketSize, cury + jacketSize / 2);
399
- jacketMaskGrad.addColorStop(0, new color_1.default(curColor).alpha(0).hexa());
400
- jacketMaskGrad.addColorStop(0.25, new color_1.default(curColor).alpha(0.2).hexa());
401
- jacketMaskGrad.addColorStop(1, new color_1.default(curColor).alpha(1).hexa());
402
- const jacketMaskGradDark = ctx.createLinearGradient(curx + jacketSize / 2, cury + jacketSize / 2, curx + jacketSize, cury + jacketSize / 2);
403
- jacketMaskGradDark.addColorStop(0, new color_1.default(curColor)
404
- .darken(0.3)
405
- .alpha(0)
406
- .hexa());
407
- jacketMaskGradDark.addColorStop(0.25, new color_1.default(curColor)
408
- .darken(0.3)
409
- .alpha(0.2)
410
- .hexa());
411
- jacketMaskGradDark.addColorStop(1, new color_1.default(curColor)
412
- .darken(0.3)
413
- .alpha(1)
414
- .hexa());
415
- /** Begin Jacket Draw*/
416
- let jacket = await this.fecthJacket(curScore.chart.id);
417
- if (!jacket)
418
- jacket = await this.fecthJacket(0);
419
- if (jacket) {
420
- const img = new canvas_1.Image();
421
- img.src = jacket;
422
- ctx.drawImage(img, curx, cury, jacketSize, jacketSize);
423
- }
424
- else {
425
- ctx.fillStyle = "#b6ffab";
426
- ctx.fillRect(curx, cury, jacketSize, jacketSize);
427
- }
428
- /** End Jacket Draw*/
429
- /** Begin Jacket Gradient Mask Draw*/ {
430
- ctx.fillStyle = jacketMaskGrad;
431
- ctx.fillRect(curx + jacketSize / 2, cury, (jacketSize * 3) / 4, jacketSize);
432
- } /** End Jacket Gradient Mask Draw*/
433
- ctx.beginPath();
434
- ctx.roundRect(curx + element.scoreBubble.margin, cury + element.scoreBubble.margin, element.scoreBubble.width -
435
- element.scoreBubble.margin * 2, element.scoreBubble.height * 0.806 -
436
- element.scoreBubble.margin * 2, (element.scoreBubble.height * 0.806 -
437
- element.scoreBubble.margin * 2) /
438
- 7);
439
- /** Begin Title Draw */ {
440
- drawText(ctx, curScore.chart.name, curx + (jacketSize * 7) / 8, cury +
441
- element.scoreBubble.margin +
442
- element.scoreBubble.height *
443
- 0.806 *
444
- 0.144, element.scoreBubble.height *
445
- 0.806 *
446
- 0.144, element.scoreBubble.height *
447
- 0.806 *
448
- 0.04, element.scoreBubble.width -
449
- (jacketSize * 7) / 8 -
450
- element.scoreBubble.margin, "left", "white", jacketMaskGradDark);
451
- } /** End Title Draw */
452
- /** Begin Separation Line Draw */ {
453
- ctx.beginPath();
454
- ctx.roundRect(curx + (jacketSize * 13) / 16, cury +
455
- element.scoreBubble.margin +
456
- element.scoreBubble.height *
457
- 0.806 *
458
- (0.144 + 0.072), element.scoreBubble.width -
459
- (jacketSize * 13) / 16 -
460
- element.scoreBubble.margin * 2, element.scoreBubble.height *
461
- 0.806 *
462
- 0.02, element.scoreBubble.height *
463
- 0.806 *
464
- 0.16);
465
- ctx.fillStyle = jacketMaskGradDark;
466
- ctx.fill();
467
- } /** End Separation Line Draw */
468
- /** Begin Achievement Rate Draw */
469
- drawText(ctx, `${curScore.achievement.toFixed(4)}%`, curx -
470
- element.scoreBubble.margin -
471
- element.scoreBubble.height *
472
- 0.806 *
473
- 0.02 +
474
- element.scoreBubble.width, cury +
475
- element.scoreBubble.margin +
476
- element.scoreBubble.height *
477
- 0.806 *
478
- (0.144 + 0.144 + 0.208 - 0.04), element.scoreBubble.height *
479
- 0.806 *
480
- 0.208, element.scoreBubble.height *
481
- 0.806 *
482
- 0.04, Infinity, "right", "white", new color_1.default(curColor).darken(0.3).hexa());
483
- /** End Achievement Rate Draw */
484
- /** Begin Achievement Rank Draw */
485
- {
486
- let rankImg;
487
- switch (curScore.achievementRank) {
488
- case type_1.EAchievementTypes.D:
489
- rankImg = this.getThemeFile(currentTheme.sprites
490
- .achievement.d, currentThemePath);
491
- break;
492
- case type_1.EAchievementTypes.C:
493
- rankImg = this.getThemeFile(currentTheme.sprites
494
- .achievement.c, currentThemePath);
495
- break;
496
- case type_1.EAchievementTypes.B:
497
- rankImg = this.getThemeFile(currentTheme.sprites
498
- .achievement.b, currentThemePath);
499
- break;
500
- case type_1.EAchievementTypes.BB:
501
- rankImg = this.getThemeFile(currentTheme.sprites
502
- .achievement.bb, currentThemePath);
503
- break;
504
- case type_1.EAchievementTypes.BBB:
505
- rankImg = this.getThemeFile(currentTheme.sprites
506
- .achievement.bbb, currentThemePath);
507
- break;
508
- case type_1.EAchievementTypes.A:
509
- rankImg = this.getThemeFile(currentTheme.sprites
510
- .achievement.a, currentThemePath);
511
- break;
512
- case type_1.EAchievementTypes.AA:
513
- rankImg = this.getThemeFile(currentTheme.sprites
514
- .achievement.aa, currentThemePath);
515
- break;
516
- case type_1.EAchievementTypes.AAA:
517
- rankImg = this.getThemeFile(currentTheme.sprites
518
- .achievement.aaa, currentThemePath);
519
- break;
520
- case type_1.EAchievementTypes.S:
521
- rankImg = this.getThemeFile(currentTheme.sprites
522
- .achievement.s, currentThemePath);
523
- break;
524
- case type_1.EAchievementTypes.SP:
525
- rankImg = this.getThemeFile(currentTheme.sprites
526
- .achievement.sp, currentThemePath);
527
- break;
528
- case type_1.EAchievementTypes.SS:
529
- rankImg = this.getThemeFile(currentTheme.sprites
530
- .achievement.ss, currentThemePath);
531
- break;
532
- case type_1.EAchievementTypes.SSP:
533
- rankImg = this.getThemeFile(currentTheme.sprites
534
- .achievement.ssp, currentThemePath);
535
- break;
536
- case type_1.EAchievementTypes.SSS:
537
- rankImg = this.getThemeFile(currentTheme.sprites
538
- .achievement.sss, currentThemePath);
539
- break;
540
- default:
541
- rankImg = this.getThemeFile(currentTheme.sprites
542
- .achievement.sssp, currentThemePath);
543
- }
544
- const img = new canvas_1.Image();
545
- img.src = rankImg;
546
- ctx.drawImage(img, curx + jacketSize, cury +
547
- element.scoreBubble.margin +
548
- element.scoreBubble.height *
549
- 0.806 *
550
- (0.144 +
551
- 0.144 +
552
- 0.208 +
553
- 0.02), element.scoreBubble.height *
554
- 0.806 *
555
- 0.3 *
556
- 2.133, element.scoreBubble.height *
557
- 0.806 *
558
- 0.3);
559
- }
560
- /** End Achievement Rank Draw */
561
- /** Begin Milestone Draw */
562
- {
563
- let comboImg, syncImg;
564
- switch (curScore.combo) {
565
- case type_1.EComboTypes.NONE:
566
- comboImg = this.getThemeFile(currentTheme.sprites
567
- .milestone.none, currentThemePath);
568
- break;
569
- case type_1.EComboTypes.FULL_COMBO:
570
- comboImg = this.getThemeFile(currentTheme.sprites
571
- .milestone.fc, currentThemePath);
572
- break;
573
- case type_1.EComboTypes.FULL_COMBO_PLUS:
574
- comboImg = this.getThemeFile(currentTheme.sprites
575
- .milestone.fcp, currentThemePath);
576
- break;
577
- case type_1.EComboTypes.ALL_PERFECT:
578
- comboImg = this.getThemeFile(currentTheme.sprites
579
- .milestone.ap, currentThemePath);
580
- break;
581
- case type_1.EComboTypes.ALL_PERFECT_PLUS:
582
- comboImg = this.getThemeFile(currentTheme.sprites
583
- .milestone.app, currentThemePath);
584
- break;
585
- }
586
- switch (curScore.sync) {
587
- case type_1.ESyncTypes.NONE:
588
- syncImg = this.getThemeFile(currentTheme.sprites
589
- .milestone.none, currentThemePath);
590
- break;
591
- case type_1.ESyncTypes.SYNC_PLAY:
592
- syncImg = this.getThemeFile(currentTheme.sprites
593
- .milestone.sync, currentThemePath);
594
- break;
595
- case type_1.ESyncTypes.FULL_SYNC:
596
- syncImg = this.getThemeFile(currentTheme.sprites
597
- .milestone.fs, currentThemePath);
598
- break;
599
- case type_1.ESyncTypes.FULL_SYNC_PLUS:
600
- syncImg = this.getThemeFile(currentTheme.sprites
601
- .milestone.fsp, currentThemePath);
602
- break;
603
- case type_1.ESyncTypes.FULL_SYNC_DX:
604
- syncImg = this.getThemeFile(currentTheme.sprites
605
- .milestone.fdx, currentThemePath);
606
- break;
607
- case type_1.ESyncTypes.FULL_SYNC_DX_PLUS:
608
- syncImg = this.getThemeFile(currentTheme.sprites
609
- .milestone.fdxp, currentThemePath);
610
- break;
611
- }
612
- const combo = new canvas_1.Image();
613
- combo.src = comboImg;
614
- ctx.drawImage(combo, curx +
615
- (jacketSize * 7) / 8 +
616
- element.scoreBubble.height *
617
- 0.806 *
618
- (0.32 * 2.133 + 0.06), cury +
619
- element.scoreBubble.margin +
620
- element.scoreBubble.height *
621
- 0.806 *
622
- (0.144 +
623
- 0.144 +
624
- 0.208 +
625
- 0.01), element.scoreBubble.height *
626
- 0.806 *
627
- 0.32, element.scoreBubble.height *
628
- 0.806 *
629
- 0.32);
630
- const sync = new canvas_1.Image();
631
- sync.src = syncImg;
632
- ctx.drawImage(sync, curx +
633
- (jacketSize * 7) / 8 +
634
- element.scoreBubble.height *
635
- 0.806 *
636
- (0.32 * 2.133 +
637
- 0.04 +
638
- 0.32), cury +
639
- element.scoreBubble.margin +
640
- element.scoreBubble.height *
641
- 0.806 *
642
- (0.144 +
643
- 0.144 +
644
- 0.208 +
645
- 0.01), element.scoreBubble.height *
646
- 0.806 *
647
- 0.32, element.scoreBubble.height *
648
- 0.806 *
649
- 0.32);
650
- }
651
- /** End Milestone Draw */
652
- /** Begin Chart Mode Draw */
653
- {
654
- const mode = new canvas_1.Image();
655
- const chartModeBadgeImg = this.getThemeFile(curScore.chart.id > 10000
656
- ? currentTheme.sprites.mode
657
- .dx
658
- : currentTheme.sprites.mode
659
- .standard, currentThemePath);
660
- const { width, height } = await (0, sharp_1.default)(chartModeBadgeImg).metadata();
661
- const aspectRatio = (width ?? 0) / (height ?? 1) || 3;
662
- mode.src = chartModeBadgeImg;
663
- const drawHeight = (jacketSize * 6) / 8;
664
- ctx.drawImage(mode, curx +
665
- ((jacketSize * 7) / 8 -
666
- drawHeight) /
667
- 2, cury +
668
- element.scoreBubble.margin +
669
- element.scoreBubble.height *
670
- 0.806 *
671
- 0.02, drawHeight, drawHeight / aspectRatio);
672
- }
673
- /** End Chart Mode Draw */
674
- /** Begin Bests Index Draw */ {
675
- drawText(ctx, `#${curindex + 1}`, curx +
676
- element.scoreBubble.margin * 2, cury +
677
- jacketSize -
678
- element.scoreBubble.margin * 2, element.scoreBubble.height *
679
- 0.806 *
680
- 0.128, element.scoreBubble.height *
681
- 0.806 *
682
- 0.04, Infinity, "left", "white", new color_1.default(curColor)
683
- .darken(0.3)
684
- .hexa());
685
- } /** End Bests Index Draw */
686
- ctx.restore();
687
- /** End Main Content Draw */
688
- /** Begin Difficulty & DX Rating Draw */ {
689
- drawText(ctx, `${curScore.chart.level.toFixed(1)} ↑${curScore.dxRating.toFixed(0)}`, curx +
690
- element.scoreBubble.margin * 2, cury +
691
- element.scoreBubble.height *
692
- (0.806 + (1 - 0.806) / 2), element.scoreBubble.height *
693
- 0.806 *
694
- 0.128, element.scoreBubble.height *
695
- 0.806 *
696
- 0.04, Infinity, "left", "white", new color_1.default(curColor)
697
- .darken(0.3)
698
- .hexa());
699
- if (curScore.chart.maxDxScore) {
700
- drawText(ctx, `${curScore.dxScore}/${curScore.chart.maxDxScore}`, curx +
701
- element.scoreBubble.width -
702
- element.scoreBubble.margin *
703
- 2, cury +
704
- element.scoreBubble.height *
705
- (0.806 +
706
- (1 - 0.806) / 2), element.scoreBubble.height *
707
- 0.806 *
708
- 0.128, element.scoreBubble.height *
709
- 0.806 *
710
- 0.04, Infinity, "right", "white", new color_1.default(curColor)
711
- .darken(0.3)
712
- .hexa());
713
- }
714
- } /** End Difficulty & DX Rating Draw */
715
- ctx.restore();
716
- }
717
- }
718
- }
719
- break;
720
- }
721
- case "profile": {
722
- const nameplate = new canvas_1.Image();
723
- nameplate.src = this.getThemeFile(currentTheme.sprites.profile.nameplate, currentThemePath);
724
- ctx.drawImage(nameplate, element.x, element.y, element.height * 6.207, element.height);
725
- const icon = new canvas_1.Image();
726
- icon.src = this.getThemeFile(currentTheme.sprites.profile.icon, currentThemePath);
727
- ctx.drawImage(icon, element.x + element.height * 0.064, element.y + element.height * 0.064, element.height * 0.872, element.height * 0.872);
728
- const dxRating = new canvas_1.Image();
729
- let dxRatingImg;
730
- switch (true) {
731
- case rating > 15000: {
732
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.rainbow, currentThemePath);
733
- break;
734
- }
735
- case rating > 14500: {
736
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.platinum, currentThemePath);
737
- break;
738
- }
739
- case rating > 14000: {
740
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.gold, currentThemePath);
741
- break;
742
- }
743
- case rating > 13000: {
744
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.silver, currentThemePath);
745
- break;
746
- }
747
- case rating > 12000: {
748
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.bronze, currentThemePath);
749
- break;
750
- }
751
- case rating > 10000: {
752
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.purple, currentThemePath);
753
- break;
754
- }
755
- case rating > 8000: {
756
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.red, currentThemePath);
757
- break;
758
- }
759
- case rating > 6000: {
760
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.yellow, currentThemePath);
761
- break;
762
- }
763
- case rating > 4000: {
764
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.green, currentThemePath);
765
- break;
766
- }
767
- case rating > 2000: {
768
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.blue, currentThemePath);
769
- break;
770
- }
771
- default: {
772
- dxRatingImg = this.getThemeFile(currentTheme.sprites.dxRating.white, currentThemePath);
773
- break;
774
- }
775
- }
776
- dxRating.src = dxRatingImg;
777
- ctx.drawImage(dxRating, element.x + element.height, element.y + element.height * 0.064, (element.height / 3) * 5.108, element.height / 3);
778
- ctx.roundRect(element.x + element.height * (1 + 1 / 32), element.y +
779
- element.height * (0.064 + 0.333 + 1 / 32), ((element.height / 3) * 5.108 * 6) / 5, (element.height * 7) / 24, element.height / 20);
780
- ctx.fillStyle = "white";
781
- ctx.strokeStyle = color_1.default.rgb(180, 180, 180).hex();
782
- ctx.lineWidth = element.height / 32;
783
- ctx.stroke();
784
- ctx.fill();
785
- const ratingImgBuffer = await this.getRatingNumber(rating, {
786
- manifest: currentTheme,
787
- path: currentThemePath,
788
- });
789
- if (ratingImgBuffer) {
790
- const { width, height } = await (0, sharp_1.default)(ratingImgBuffer).metadata();
791
- if (width && height) {
792
- const aspectRatio = width / height;
793
- const image = new canvas_1.Image();
794
- image.src = ratingImgBuffer;
795
- const drawHeight = (element.height * 7) / 32;
796
- ctx.drawImage(image, element.x + element.height * 1.785, element.y + element.height * 0.12, drawHeight * aspectRatio * 0.8, drawHeight);
797
- }
798
- }
799
- drawText(ctx, HalfFullWidthConvert.toFullWidth(name), element.x + element.height * (1 + 1 / 16), element.y +
800
- element.height * (0.064 + 0.333 + 1 / 4), (element.height * 1) / 6, 0, ((element.height / 3) * 5.108 * 6) / 5, "left", "black", "black", "standard-font-username");
801
- break;
802
- }
803
- }
804
- }
805
- return canvas.toBuffer();
806
- }
807
- else
808
- return null;
809
- }
810
- async drawWithScoreSource(source, username, options) {
811
- const profile = await source.getPlayerInfo(username);
812
- const score = await source.getPlayerBest50(username);
813
- if (!profile || !score)
814
- return null;
815
- return this.draw(profile.name, profile.rating, score.new, score.old, options);
816
- }
817
- async getRatingNumber(num, theme) {
818
- async function getRaingDigit(map, digit, unitWidth, unitHeight) {
819
- digit = Math.floor(digit % 10);
820
- return await (0, sharp_1.default)(map)
821
- .extract({
822
- left: (digit % 4) * unitWidth,
823
- top: Math.floor(digit / 4) * unitHeight,
824
- width: unitWidth,
825
- height: unitHeight,
826
- })
827
- .toBuffer();
828
- }
829
- if (theme.manifest) {
830
- const map = this.getThemeFile(theme.manifest.sprites.dxRatingNumberMap, theme.path);
831
- const { width, height } = await (0, sharp_1.default)(map).metadata();
832
- if (!(width && height))
833
- return null;
834
- const unitWidth = width / 4, unitHeight = height / 4;
835
- let digits = [];
836
- while (num > 0) {
837
- digits.push(await getRaingDigit(map, num % 10, unitWidth, unitHeight));
838
- num = Math.floor(num / 10);
839
- }
840
- while (digits.length < 5)
841
- digits.push(null);
842
- digits = digits.reverse();
843
- const canvas = new canvas_1.Canvas(unitWidth * digits.length, unitHeight);
844
- const ctx = canvas.getContext("2d");
845
- for (let i = 0; i < digits.length; ++i) {
846
- const curDigit = digits[i];
847
- if (!curDigit)
848
- continue;
849
- const img = new canvas_1.Image();
850
- img.src = curDigit;
851
- ctx.drawImage(img, unitWidth * i * 0.88, 0);
852
- }
853
- return canvas.toBuffer();
854
- }
855
- return null;
856
- }
857
- cache = new memory_cache_1.Cache();
858
- async cacheJackets(ids) {
859
- const promises = [];
860
- for (const id of ids) {
861
- promises.push(this.fecthJacket(id));
862
- }
863
- await Promise.all(promises);
864
- }
865
- async fecthJacket(id) {
866
- const cached = this.cache.get(`jacket-${id}`);
867
- if (cached)
868
- return cached;
869
- else {
870
- const jacket = await this.downloadJacket(id);
871
- if (jacket)
872
- this.cache.put(`jacket-${id}`, jacket, 1000 * 60 * 60);
873
- return jacket;
874
- }
875
- }
876
- async downloadJacket(id) {
877
- if (id > 10000)
878
- id -= 10000;
879
- const localFilePath = upath_1.default.join(this.localDatabasePath, "assets", "jackets", `${id.toString().padStart(6, "0")}.png`);
880
- if (fs_1.default.existsSync(localFilePath)) {
881
- return fs_1.default.readFileSync(localFilePath);
882
- }
883
- // return null;
884
- // console.log(`Downloading jacket ${id}`);
885
- return await axios_1.default
886
- .get(`https://assets2.lxns.net/maimai/jacket/${id}.png`, {
887
- responseType: "arraybuffer",
888
- })
889
- .then((res) => res.data)
890
- .catch((e) => null);
891
- }
892
- getLocalChart(id, difficulty) {
893
- const localFilePath = upath_1.default.join(this.localDatabasePath, "assets", "charts", `${id.toString().padStart(6, "0")}`, `${difficulty}.json`);
894
- if (fs_1.default.existsSync(localFilePath)) {
895
- return JSON.parse(fs_1.default.readFileSync(localFilePath, "utf-8"));
896
- }
897
- return null;
898
- }
6
+ static Maimai = mai_1.Maimai;
899
7
  }
900
8
  exports.MaiDraw = MaiDraw;
901
9
  //# sourceMappingURL=index.js.map