maidraw 0.9.5 → 0.10.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 (167) hide show
  1. package/assets/themes/chunithm/best/luminousLandscape/new/manifest.json +58 -32
  2. package/assets/themes/chunithm/best/luminousLandscape/recents/manifest.json +57 -31
  3. package/assets/themes/chunithm/best/luminousPlusLandscape/new/manifest.json +57 -31
  4. package/assets/themes/chunithm/best/luminousPlusLandscape/recents/manifest.json +57 -31
  5. package/assets/themes/chunithm/best/verseLandscape/new/manifest.json +57 -31
  6. package/assets/themes/chunithm/best/verseLandscape/recents/manifest.json +57 -31
  7. package/assets/themes/chunithm/chart/jp/verse/manifest.json +73 -71
  8. package/assets/themes/maimai/best50/cn/2024Landscape/manifest.json +90 -54
  9. package/assets/themes/maimai/best50/cn/2024Portrait/manifest.json +89 -53
  10. package/assets/themes/maimai/best50/cn/2025Landscape/manifest.json +90 -54
  11. package/assets/themes/maimai/best50/cn/2025Portrait/manifest.json +89 -53
  12. package/assets/themes/maimai/best50/common/prism/plus/background.png +0 -0
  13. package/assets/themes/maimai/best50/jp/buddiesLandscape/manifest.json +89 -53
  14. package/assets/themes/maimai/best50/jp/buddiesPlusLandscape/manifest.json +89 -53
  15. package/assets/themes/maimai/best50/jp/buddiesPlusPortrait/manifest.json +89 -53
  16. package/assets/themes/maimai/best50/jp/buddiesPortrait/manifest.json +89 -53
  17. package/assets/themes/maimai/best50/jp/finaleLandscape/manifest.json +89 -53
  18. package/assets/themes/maimai/best50/jp/finalePortrait/manifest.json +89 -53
  19. package/assets/themes/maimai/best50/jp/prismLandscape/manifest.json +90 -54
  20. package/assets/themes/maimai/best50/jp/prismPlusLandscape/manifest.json +90 -54
  21. package/assets/themes/maimai/best50/jp/prismPlusPortrait/manifest.json +92 -55
  22. package/assets/themes/maimai/best50/jp/prismPortrait/manifest.json +89 -53
  23. package/assets/themes/maimai/best50/salt/2026landscape/manifest.json +89 -53
  24. package/assets/themes/maimai/chart/jp/prism/manifest.json +100 -96
  25. package/assets/themes/ongeki/jp/brightMemoryLandscape/classic/manifest.json +101 -30
  26. package/assets/themes/ongeki/jp/brightMemoryLandscape/refresh/manifest.json +78 -30
  27. package/assets/themes/ongeki/jp/refreshLandscape/classic/manifest.json +101 -2
  28. package/assets/themes/ongeki/jp/refreshLandscape/refresh/manifest.json +78 -30
  29. package/dist/chu/index.d.ts +14 -4
  30. package/dist/chu/index.js +16 -4
  31. package/dist/chu/index.js.map +1 -1
  32. package/dist/chu/lib/{index.d.ts → adapter/index.d.ts} +1 -1
  33. package/dist/chu/lib/{index.js → adapter/index.js} +1 -1
  34. package/dist/chu/lib/adapter/index.js.map +1 -0
  35. package/dist/chu/lib/{kamaiTachi → adapter/kamaiTachi}/index.d.ts +1 -1
  36. package/dist/chu/lib/{kamaiTachi → adapter/kamaiTachi}/index.js +5 -5
  37. package/dist/chu/lib/adapter/kamaiTachi/index.js.map +1 -0
  38. package/dist/chu/lib/{lxns → adapter/lxns}/index.d.ts +1 -1
  39. package/dist/chu/lib/{lxns → adapter/lxns}/index.js +4 -4
  40. package/dist/chu/lib/adapter/lxns/index.js.map +1 -0
  41. package/dist/chu/{chart → lib}/database.d.ts +3 -3
  42. package/dist/chu/{chart → lib}/database.js +2 -2
  43. package/dist/chu/lib/database.js.map +1 -0
  44. package/dist/chu/lib/util.d.ts +149 -0
  45. package/dist/chu/lib/util.js +270 -0
  46. package/dist/chu/lib/util.js.map +1 -0
  47. package/dist/chu/painter/best50/index.d.ts +120 -0
  48. package/dist/chu/painter/best50/index.js +158 -0
  49. package/dist/chu/painter/best50/index.js.map +1 -0
  50. package/dist/chu/painter/chart/index.d.ts +170 -0
  51. package/dist/chu/painter/chart/index.js +116 -0
  52. package/dist/chu/painter/chart/index.js.map +1 -0
  53. package/dist/chu/painter/index.d.ts +194 -0
  54. package/dist/chu/painter/index.js +1105 -0
  55. package/dist/chu/painter/index.js.map +1 -0
  56. package/dist/geki/index.d.ts +10 -4
  57. package/dist/geki/index.js +12 -4
  58. package/dist/geki/index.js.map +1 -1
  59. package/dist/geki/lib/adapter/index.js.map +1 -0
  60. package/dist/geki/lib/adapter/kamaiTachi/index.js.map +1 -0
  61. package/dist/geki/{chart → lib}/database.d.ts +1 -1
  62. package/dist/geki/{chart → lib}/database.js +2 -2
  63. package/dist/geki/lib/database.js.map +1 -0
  64. package/dist/geki/painter/best50/index.d.ts +122 -0
  65. package/dist/geki/painter/best50/index.js +197 -0
  66. package/dist/geki/painter/best50/index.js.map +1 -0
  67. package/dist/geki/painter/index.d.ts +88 -0
  68. package/dist/geki/painter/index.js +448 -0
  69. package/dist/geki/painter/index.js.map +1 -0
  70. package/dist/lib/cache.d.ts +1 -0
  71. package/dist/lib/cache.js +6 -1
  72. package/dist/lib/cache.js.map +1 -1
  73. package/dist/lib/painter.d.ts +100 -0
  74. package/dist/lib/painter.js +216 -0
  75. package/dist/lib/painter.js.map +1 -0
  76. package/dist/lib/util.d.ts +6 -282
  77. package/dist/lib/util.js +50 -540
  78. package/dist/lib/util.js.map +1 -1
  79. package/dist/mai/index.d.ts +22 -6
  80. package/dist/mai/index.js +24 -6
  81. package/dist/mai/index.js.map +1 -1
  82. package/dist/mai/lib/{divingFish → adapter/divingFish}/index.d.ts +6 -6
  83. package/dist/mai/lib/{divingFish → adapter/divingFish}/index.js +29 -30
  84. package/dist/mai/lib/adapter/divingFish/index.js.map +1 -0
  85. package/dist/mai/lib/{index.d.ts → adapter/index.d.ts} +11 -11
  86. package/dist/mai/lib/{index.js → adapter/index.js} +2 -2
  87. package/dist/{geki/bests/lib → mai/lib/adapter}/index.js.map +1 -1
  88. package/dist/mai/lib/{kamaiTachi → adapter/kamaiTachi}/index.d.ts +84 -42
  89. package/dist/mai/lib/{kamaiTachi → adapter/kamaiTachi}/index.js +36 -29
  90. package/dist/mai/lib/adapter/kamaiTachi/index.js.map +1 -0
  91. package/dist/mai/lib/{lxns → adapter/lxns}/index.d.ts +12 -12
  92. package/dist/mai/lib/{lxns → adapter/lxns}/index.js +29 -30
  93. package/dist/mai/lib/adapter/lxns/index.js.map +1 -0
  94. package/dist/mai/lib/{maishift → adapter/maishift}/index.d.ts +4 -4
  95. package/dist/mai/lib/{maishift → adapter/maishift}/index.js +20 -20
  96. package/dist/mai/lib/adapter/maishift/index.js.map +1 -0
  97. package/dist/mai/{chart → lib}/database.d.ts +3 -3
  98. package/dist/mai/{chart → lib}/database.js +2 -2
  99. package/dist/mai/lib/database.js.map +1 -0
  100. package/dist/mai/lib/util.d.ts +134 -0
  101. package/dist/mai/lib/util.js +264 -0
  102. package/dist/mai/lib/util.js.map +1 -0
  103. package/dist/mai/painter/best50/index.d.ts +140 -0
  104. package/dist/mai/painter/best50/index.js +176 -0
  105. package/dist/mai/painter/best50/index.js.map +1 -0
  106. package/dist/mai/painter/chart/index.d.ts +195 -0
  107. package/dist/mai/painter/chart/index.js +115 -0
  108. package/dist/mai/painter/chart/index.js.map +1 -0
  109. package/dist/mai/painter/index.d.ts +237 -0
  110. package/dist/mai/painter/index.js +1431 -0
  111. package/dist/mai/painter/index.js.map +1 -0
  112. package/dist/mai/painter/level50/index.d.ts +28 -0
  113. package/dist/mai/painter/level50/index.js +129 -0
  114. package/dist/mai/painter/level50/index.js.map +1 -0
  115. package/dist/mai/type.d.ts +110 -0
  116. package/dist/mai/type.js +73 -1
  117. package/dist/mai/type.js.map +1 -1
  118. package/package.json +56 -55
  119. package/dist/chu/bests/best50.d.ts +0 -37
  120. package/dist/chu/bests/best50.js +0 -742
  121. package/dist/chu/bests/best50.js.map +0 -1
  122. package/dist/chu/bests/index.d.ts +0 -1
  123. package/dist/chu/bests/index.js +0 -6
  124. package/dist/chu/bests/index.js.map +0 -1
  125. package/dist/chu/bests/type.d.ts +0 -122
  126. package/dist/chu/bests/type.js +0 -3
  127. package/dist/chu/bests/type.js.map +0 -1
  128. package/dist/chu/chart/database.js.map +0 -1
  129. package/dist/chu/chart/index.d.ts +0 -212
  130. package/dist/chu/chart/index.js +0 -1064
  131. package/dist/chu/chart/index.js.map +0 -1
  132. package/dist/chu/lib/index.js.map +0 -1
  133. package/dist/chu/lib/kamaiTachi/index.js.map +0 -1
  134. package/dist/chu/lib/lxns/index.js.map +0 -1
  135. package/dist/geki/bests/best50.d.ts +0 -35
  136. package/dist/geki/bests/best50.js +0 -821
  137. package/dist/geki/bests/best50.js.map +0 -1
  138. package/dist/geki/bests/index.d.ts +0 -1
  139. package/dist/geki/bests/index.js +0 -6
  140. package/dist/geki/bests/index.js.map +0 -1
  141. package/dist/geki/bests/lib/kamaiTachi/index.js.map +0 -1
  142. package/dist/geki/bests/type.d.ts +0 -122
  143. package/dist/geki/bests/type.js +0 -3
  144. package/dist/geki/bests/type.js.map +0 -1
  145. package/dist/geki/chart/database.js.map +0 -1
  146. package/dist/geki/chart/index.d.ts +0 -4
  147. package/dist/geki/chart/index.js +0 -32
  148. package/dist/geki/chart/index.js.map +0 -1
  149. package/dist/mai/best50/index.d.ts +0 -271
  150. package/dist/mai/best50/index.js +0 -915
  151. package/dist/mai/best50/index.js.map +0 -1
  152. package/dist/mai/chart/database.js.map +0 -1
  153. package/dist/mai/chart/index.d.ts +0 -238
  154. package/dist/mai/chart/index.js +0 -1281
  155. package/dist/mai/chart/index.js.map +0 -1
  156. package/dist/mai/level50/index.d.ts +0 -28
  157. package/dist/mai/level50/index.js +0 -774
  158. package/dist/mai/level50/index.js.map +0 -1
  159. package/dist/mai/lib/divingFish/index.js.map +0 -1
  160. package/dist/mai/lib/index.js.map +0 -1
  161. package/dist/mai/lib/kamaiTachi/index.js.map +0 -1
  162. package/dist/mai/lib/lxns/index.js.map +0 -1
  163. package/dist/mai/lib/maishift/index.js.map +0 -1
  164. /package/dist/geki/{bests/lib → lib/adapter}/index.d.ts +0 -0
  165. /package/dist/geki/{bests/lib → lib/adapter}/index.js +0 -0
  166. /package/dist/geki/{bests/lib → lib/adapter}/kamaiTachi/index.d.ts +0 -0
  167. /package/dist/geki/{bests/lib → lib/adapter}/kamaiTachi/index.js +0 -0
@@ -1,1281 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.Chart = void 0;
30
- const sharp_1 = __importDefault(require("sharp"));
31
- const type_1 = require("../type");
32
- const database = __importStar(require("./database"));
33
- const util_1 = require("../../lib/util");
34
- const canvas_1 = require("canvas");
35
- const color_1 = __importDefault(require("color"));
36
- const glob_1 = require("glob");
37
- const upath_1 = __importDefault(require("upath"));
38
- const fs_1 = __importDefault(require("fs"));
39
- const best50_1 = require("../best50");
40
- const string_template_1 = __importDefault(require("string-template"));
41
- const lodash_1 = __importDefault(require("lodash"));
42
- class Chart {
43
- static DX_LATEST = 55;
44
- static EX_LATEST = 50;
45
- static CN_LATEST = 50;
46
- static MAIMAI_VERSIONS = [
47
- 99, 95, 90, 85, 80, 70, 60, 50, 40, 30, 20, 10, 0,
48
- ];
49
- static MAIMAIDX_VERSIONS = [
50
- 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0,
51
- ];
52
- static WUMENGDX_VERSIONS = [50, 40, 30, 20, 10, 0];
53
- static findVersion(v, isDX, isCN) {
54
- const target = isDX
55
- ? isCN
56
- ? this.WUMENGDX_VERSIONS
57
- : this.MAIMAIDX_VERSIONS
58
- : this.MAIMAI_VERSIONS;
59
- for (const version of target) {
60
- if (v >= version)
61
- return version;
62
- }
63
- return -1;
64
- }
65
- static DEFAULT_THEME = "jp-prism";
66
- static primaryTheme = null;
67
- static get assetsPath() {
68
- return upath_1.default.join(__dirname, "..", "..", "..", "assets");
69
- }
70
- static themes = {};
71
- static hasTheme(name) {
72
- return !!this.themes[name];
73
- }
74
- static {
75
- const manifests = (0, glob_1.globSync)(upath_1.default.join(this.assetsPath, "themes", "maimai", "chart", "**", "manifest.json"));
76
- for (const manifestPath of manifests) {
77
- const manifest = JSON.parse(fs_1.default.readFileSync(manifestPath, "utf-8"));
78
- if (this.validateManifest(manifest, upath_1.default.dirname(manifestPath))) {
79
- this.themes[manifest.name] = upath_1.default.dirname(manifestPath);
80
- }
81
- }
82
- const loadThemeResult = this.loadTheme(this.DEFAULT_THEME);
83
- if (!loadThemeResult) {
84
- console.error("Failed to load default theme.");
85
- }
86
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "gen-jyuu-gothic", "GenJyuuGothic-Bold.ttf"), {
87
- family: "standard-font-title-jp",
88
- });
89
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "comfortaa", "Comfortaa-Bold.ttf"), {
90
- family: "standard-font-title-latin",
91
- weight: "regular",
92
- });
93
- (0, canvas_1.registerFont)(upath_1.default.join(this.assetsPath, "fonts", "seurat-db", "FOT-Seurat Pro DB.otf"), {
94
- family: "standard-font-username",
95
- weight: "regular",
96
- });
97
- }
98
- static validateManifest(payload, path) {
99
- function isFileExist(p) {
100
- if (isString(p))
101
- return fs_1.default.existsSync(upath_1.default.join(path, p));
102
- else
103
- return false;
104
- }
105
- function isOneOf(p, ...args) {
106
- return args.includes(p);
107
- }
108
- function isString(p) {
109
- return typeof p == "string";
110
- }
111
- function isNumber(p) {
112
- return typeof p == "number";
113
- }
114
- function isArray(p) {
115
- return Array.isArray(p);
116
- }
117
- function isObject(p) {
118
- return typeof p == "object";
119
- }
120
- function isHexColor(p) {
121
- if (isString(p))
122
- return /^(?:#[0-9A-F]{6}|#[0-9A-F]{8})$/i.test(p);
123
- else
124
- return false;
125
- }
126
- function isUndefined(p) {
127
- return typeof p == "undefined";
128
- }
129
- function isBoolean(p) {
130
- return typeof p == "boolean";
131
- }
132
- if (isString(payload.displayName) &&
133
- isString(payload.name) &&
134
- isNumber(payload.width) &&
135
- isNumber(payload.height) &&
136
- isObject(payload.sprites) &&
137
- isObject(payload.sprites.achievement) &&
138
- isFileExist(payload.sprites.achievement.d) &&
139
- isFileExist(payload.sprites.achievement.c) &&
140
- isFileExist(payload.sprites.achievement.b) &&
141
- isFileExist(payload.sprites.achievement.bb) &&
142
- isFileExist(payload.sprites.achievement.bbb) &&
143
- isFileExist(payload.sprites.achievement.a) &&
144
- isFileExist(payload.sprites.achievement.aa) &&
145
- isFileExist(payload.sprites.achievement.aaa) &&
146
- isFileExist(payload.sprites.achievement.s) &&
147
- isFileExist(payload.sprites.achievement.sp) &&
148
- isFileExist(payload.sprites.achievement.ss) &&
149
- isFileExist(payload.sprites.achievement.ssp) &&
150
- isFileExist(payload.sprites.achievement.sss) &&
151
- isFileExist(payload.sprites.achievement.sssp) &&
152
- isObject(payload.sprites.mode) &&
153
- isFileExist(payload.sprites.mode.standard) &&
154
- isFileExist(payload.sprites.mode.dx) &&
155
- isObject(payload.sprites.milestone) &&
156
- isFileExist(payload.sprites.milestone.ap) &&
157
- isFileExist(payload.sprites.milestone.app) &&
158
- isFileExist(payload.sprites.milestone.fc) &&
159
- isFileExist(payload.sprites.milestone.fcp) &&
160
- isFileExist(payload.sprites.milestone.fdx) &&
161
- isFileExist(payload.sprites.milestone.fdxp) &&
162
- isFileExist(payload.sprites.milestone.fs) &&
163
- isFileExist(payload.sprites.milestone.fsp) &&
164
- isFileExist(payload.sprites.milestone.sync) &&
165
- isFileExist(payload.sprites.milestone.none) &&
166
- isObject(payload.sprites.dxRating) &&
167
- isFileExist(payload.sprites.dxRating.white) &&
168
- isFileExist(payload.sprites.dxRating.blue) &&
169
- isFileExist(payload.sprites.dxRating.green) &&
170
- isFileExist(payload.sprites.dxRating.yellow) &&
171
- isFileExist(payload.sprites.dxRating.red) &&
172
- isFileExist(payload.sprites.dxRating.purple) &&
173
- isFileExist(payload.sprites.dxRating.bronze) &&
174
- isFileExist(payload.sprites.dxRating.silver) &&
175
- isFileExist(payload.sprites.dxRating.gold) &&
176
- isFileExist(payload.sprites.dxRating.platinum) &&
177
- isFileExist(payload.sprites.dxRating.rainbow) &&
178
- isObject(payload.sprites.profile) &&
179
- isFileExist(payload.sprites.profile.icon) &&
180
- isFileExist(payload.sprites.profile.nameplate) &&
181
- isFileExist(payload.sprites.dxRatingNumberMap) &&
182
- isObject(payload.sprites.versions) &&
183
- isObject(payload.sprites.versions.OLD) &&
184
- isFileExist(payload.sprites.versions.OLD[0]) &&
185
- isFileExist(payload.sprites.versions.OLD[10]) &&
186
- isFileExist(payload.sprites.versions.OLD[20]) &&
187
- isFileExist(payload.sprites.versions.OLD[30]) &&
188
- isFileExist(payload.sprites.versions.OLD[40]) &&
189
- isFileExist(payload.sprites.versions.OLD[50]) &&
190
- isFileExist(payload.sprites.versions.OLD[60]) &&
191
- isFileExist(payload.sprites.versions.OLD[70]) &&
192
- isFileExist(payload.sprites.versions.OLD[80]) &&
193
- isFileExist(payload.sprites.versions.OLD[85]) &&
194
- isFileExist(payload.sprites.versions.OLD[90]) &&
195
- isFileExist(payload.sprites.versions.OLD[95]) &&
196
- isFileExist(payload.sprites.versions.OLD[99]) &&
197
- isObject(payload.sprites.versions.DX) &&
198
- isFileExist(payload.sprites.versions.DX[0]) &&
199
- isFileExist(payload.sprites.versions.DX[5]) &&
200
- isFileExist(payload.sprites.versions.DX[10]) &&
201
- isFileExist(payload.sprites.versions.DX[15]) &&
202
- isFileExist(payload.sprites.versions.DX[20]) &&
203
- isFileExist(payload.sprites.versions.DX[25]) &&
204
- isFileExist(payload.sprites.versions.DX[30]) &&
205
- isFileExist(payload.sprites.versions.DX[35]) &&
206
- isFileExist(payload.sprites.versions.DX[40]) &&
207
- isFileExist(payload.sprites.versions.DX[45]) &&
208
- isFileExist(payload.sprites.versions.DX[50]) &&
209
- isFileExist(payload.sprites.versions.DX[55]) &&
210
- isObject(payload.sprites.versions.EX) &&
211
- isFileExist(payload.sprites.versions.DX[10]) &&
212
- isFileExist(payload.sprites.versions.DX[15]) &&
213
- isObject(payload.sprites.versions.CN) &&
214
- isFileExist(payload.sprites.versions.DX[0]) &&
215
- isFileExist(payload.sprites.versions.DX[10]) &&
216
- isFileExist(payload.sprites.versions.DX[20]) &&
217
- isFileExist(payload.sprites.versions.DX[30]) &&
218
- isFileExist(payload.sprites.versions.DX[40]) &&
219
- isFileExist(payload.sprites.versions.DX[50]) &&
220
- isArray(payload.elements)) {
221
- for (const element of payload.elements) {
222
- if (isNumber(element.x) && isNumber(element.y)) {
223
- switch (element.type) {
224
- case "image": {
225
- if (isNumber(element.width) &&
226
- isNumber(element.height) &&
227
- isFileExist(element.path)) {
228
- continue;
229
- }
230
- else
231
- return false;
232
- }
233
- case "chart-grid": {
234
- if (isNumber(element.width) &&
235
- isNumber(element.height) &&
236
- isNumber(element.margin) &&
237
- isNumber(element.gap) &&
238
- isObject(element.bubble) &&
239
- isHexColor(element.bubble.color.basic) &&
240
- isHexColor(element.bubble.color.advanced) &&
241
- isHexColor(element.bubble.color.expert) &&
242
- isHexColor(element.bubble.color.master) &&
243
- isHexColor(element.bubble.color.remaster) &&
244
- isHexColor(element.bubble.color.utage) &&
245
- isObject(element.color) &&
246
- isHexColor(element.color.card)) {
247
- continue;
248
- }
249
- else
250
- return false;
251
- }
252
- case "profile": {
253
- if (isNumber(element.height)) {
254
- continue;
255
- }
256
- else
257
- return false;
258
- }
259
- case "detail-info": {
260
- if (isNumber(element.width) &&
261
- isNumber(element.height) &&
262
- isNumber(element.margin) &&
263
- isObject(element.color) &&
264
- isHexColor(element.color.card) &&
265
- (isUndefined(element.font) ||
266
- isString(element.font))) {
267
- continue;
268
- }
269
- else
270
- return false;
271
- }
272
- case "text": {
273
- if (isNumber(element.size) &&
274
- isString(element.content) &&
275
- (isUndefined(element.width) ||
276
- isNumber(element.width)) &&
277
- (isUndefined(element.height) ||
278
- isNumber(element.height)) &&
279
- (isUndefined(element.linebreak) ||
280
- isBoolean(element.linebreak)) &&
281
- (isUndefined(element.align) ||
282
- isOneOf(element.align, "left", "center", "right")) &&
283
- (isUndefined(element.color) ||
284
- isString(element.color)) &&
285
- (isUndefined(element.borderColor) ||
286
- isString(element.borderColor)) &&
287
- (isUndefined(element.font) ||
288
- isString(element.font))) {
289
- continue;
290
- }
291
- else
292
- return false;
293
- }
294
- default:
295
- return false;
296
- }
297
- }
298
- }
299
- return true;
300
- }
301
- else
302
- return false;
303
- }
304
- static loadTheme(path) {
305
- const theme = this.getTheme(path);
306
- if (theme) {
307
- this.primaryTheme = theme;
308
- return true;
309
- }
310
- else
311
- return false;
312
- }
313
- static getTheme(path) {
314
- if (!fs_1.default.existsSync(upath_1.default.join(path, "manifest.json"))) {
315
- path = this.themes[path] ?? "";
316
- }
317
- else
318
- path = upath_1.default.join(this.assetsPath, path);
319
- if (fs_1.default.existsSync(upath_1.default.join(path, "manifest.json"))) {
320
- const manifest = JSON.parse(fs_1.default.readFileSync(upath_1.default.join(path, "manifest.json"), "utf-8"));
321
- if (this.validateManifest(manifest, path)) {
322
- return { manifest, path };
323
- }
324
- }
325
- return null;
326
- }
327
- static getThemeFile(path, themePath) {
328
- if (typeof path == "string" &&
329
- fs_1.default.existsSync(upath_1.default.join(themePath ?? this.primaryTheme?.path ?? "", path)))
330
- return fs_1.default.readFileSync(upath_1.default.join(themePath ?? this.primaryTheme?.path, path));
331
- else
332
- return Buffer.from([]);
333
- }
334
- /* Begin Draw Tools*/
335
- static async drawImageModule(ctx, theme, element) {
336
- const img = new canvas_1.Image();
337
- img.src = this.getThemeFile(element.path, theme.path);
338
- ctx.drawImage(img, element.x, element.y, element.width, element.height);
339
- }
340
- static async drawChartGridCard(ctx, theme, element, chart, difficulty, x, y, width, height, isShort, targetRegion = "DX", score) {
341
- let curColor = "#FFFFFF";
342
- switch (difficulty) {
343
- case type_1.EDifficulty.BASIC:
344
- curColor = element.bubble.color.basic;
345
- break;
346
- case type_1.EDifficulty.ADVANCED:
347
- curColor = element.bubble.color.advanced;
348
- break;
349
- case type_1.EDifficulty.EXPERT:
350
- curColor = element.bubble.color.expert;
351
- break;
352
- case type_1.EDifficulty.MASTER:
353
- curColor = element.bubble.color.master;
354
- break;
355
- case type_1.EDifficulty.REMASTER:
356
- curColor = element.bubble.color.remaster;
357
- break;
358
- case type_1.EDifficulty.UTAGE:
359
- curColor = element.bubble.color.utage;
360
- break;
361
- }
362
- /** Begin Card Draw */
363
- ctx.save();
364
- ctx.fillStyle = new color_1.default(curColor).lighten(0.4).hexa();
365
- ctx.beginPath();
366
- ctx.roundRect(x, y, width, height, (height * 0.806) / 7);
367
- ctx.strokeStyle = new color_1.default(curColor).darken(0.3).hexa();
368
- ctx.lineWidth = element.bubble.margin / 4;
369
- ctx.stroke();
370
- ctx.fill();
371
- ctx.beginPath();
372
- ctx.roundRect(x, y, width, height, (height * 0.806) / 7);
373
- ctx.clip();
374
- /** Begin Main Content Draw */
375
- {
376
- ctx.save();
377
- ctx.beginPath();
378
- ctx.rect(x, y, width, height);
379
- ctx.clip();
380
- ctx.fillStyle = curColor;
381
- ctx.fill();
382
- const titleSize = height * (47 / 256);
383
- /** Begin Difficulty Text & Separation Line Draw */
384
- {
385
- let difficultiy = "";
386
- switch (chart.difficulty) {
387
- case type_1.EDifficulty.BASIC:
388
- difficultiy = "BASIC";
389
- break;
390
- case type_1.EDifficulty.ADVANCED:
391
- difficultiy = "ADVANCED";
392
- break;
393
- case type_1.EDifficulty.EXPERT:
394
- difficultiy = "EXPERT";
395
- break;
396
- case type_1.EDifficulty.MASTER:
397
- difficultiy = "MASTER";
398
- break;
399
- case type_1.EDifficulty.REMASTER:
400
- difficultiy = "Re:MASTER";
401
- break;
402
- case type_1.EDifficulty.UTAGE:
403
- difficultiy = "U·TA·GE";
404
- break;
405
- }
406
- const levelTextSize = titleSize * (5 / 8);
407
- util_1.Util.drawText(ctx, difficultiy, x + element.bubble.margin, y +
408
- element.bubble.margin +
409
- titleSize -
410
- element.bubble.margin * (1 / 4), titleSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
411
- const difficultyTextWidth = util_1.Util.measureText(ctx, difficultiy, titleSize, Infinity).width;
412
- util_1.Util.drawText(ctx, `Lv. ${util_1.Util.truncate(chart.level, 1)}${score ? ` ↑${util_1.Util.truncate(score.dxRating, 0)}` : ""}`, x + element.bubble.margin * 2 + difficultyTextWidth, y +
413
- element.bubble.margin +
414
- titleSize -
415
- element.bubble.margin * (1 / 4), levelTextSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
416
- ctx.beginPath();
417
- ctx.roundRect(x + element.bubble.margin, y +
418
- element.bubble.margin +
419
- titleSize +
420
- element.bubble.margin * (1 / 4), height * 2 - element.bubble.margin * 2, height * 0.806 * 0.02, height * 0.806 * 0.16);
421
- ctx.fillStyle = new color_1.default(curColor).darken(0.3).hex();
422
- ctx.fill();
423
- }
424
- /** End Difficulty Text & Separation Line Draw */
425
- /** Begin Achievement Rate Draw */
426
- {
427
- const scoreSize = height * 0.806 * 0.208;
428
- util_1.Util.drawText(ctx, score
429
- ? `${util_1.Util.truncate(score.achievement, 4)}%`
430
- : "NO RECORD", x +
431
- height * 2 -
432
- element.bubble.margin -
433
- height * 0.806 * 0.02, y +
434
- element.bubble.margin +
435
- titleSize +
436
- element.bubble.margin * (5 / 8) +
437
- scoreSize, scoreSize, height * 0.806 * 0.04, Infinity, "right", "white", new color_1.default(curColor).darken(0.3).hexa());
438
- }
439
- /** End Achievement Rate Draw */
440
- /** Begin Achievement Rank Draw */
441
- {
442
- if (score) {
443
- let rankImg;
444
- switch (score.achievementRank) {
445
- case best50_1.Best50.EAchievementTypes.D:
446
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.d, theme.path);
447
- break;
448
- case best50_1.Best50.EAchievementTypes.C:
449
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.c, theme.path);
450
- break;
451
- case best50_1.Best50.EAchievementTypes.B:
452
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.b, theme.path);
453
- break;
454
- case best50_1.Best50.EAchievementTypes.BB:
455
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.bb, theme.path);
456
- break;
457
- case best50_1.Best50.EAchievementTypes.BBB:
458
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.bbb, theme.path);
459
- break;
460
- case best50_1.Best50.EAchievementTypes.A:
461
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.a, theme.path);
462
- break;
463
- case best50_1.Best50.EAchievementTypes.AA:
464
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.aa, theme.path);
465
- break;
466
- case best50_1.Best50.EAchievementTypes.AAA:
467
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.aaa, theme.path);
468
- break;
469
- case best50_1.Best50.EAchievementTypes.S:
470
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.s, theme.path);
471
- break;
472
- case best50_1.Best50.EAchievementTypes.SP:
473
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.sp, theme.path);
474
- break;
475
- case best50_1.Best50.EAchievementTypes.SS:
476
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.ss, theme.path);
477
- break;
478
- case best50_1.Best50.EAchievementTypes.SSP:
479
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.ssp, theme.path);
480
- break;
481
- case best50_1.Best50.EAchievementTypes.SSS:
482
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.sss, theme.path);
483
- break;
484
- default:
485
- rankImg = this.getThemeFile(theme.manifest.sprites.achievement.sssp, theme.path);
486
- }
487
- const img = new canvas_1.Image();
488
- img.src = rankImg;
489
- ctx.drawImage(img, x + element.bubble.margin * (1 / 4), y +
490
- element.bubble.margin +
491
- titleSize +
492
- element.bubble.margin * (1 / 2), height * 0.806 * 0.3 * 2.133, height * 0.806 * 0.3);
493
- }
494
- }
495
- /** End Achievement Rank Draw */
496
- /** Begin Milestone Draw */
497
- {
498
- if (score) {
499
- let comboImg, syncImg;
500
- switch (score.combo) {
501
- case best50_1.Best50.EComboTypes.NONE:
502
- comboImg = this.getThemeFile(theme.manifest.sprites.milestone.none, theme.path);
503
- break;
504
- case best50_1.Best50.EComboTypes.FULL_COMBO:
505
- comboImg = this.getThemeFile(theme.manifest.sprites.milestone.fc, theme.path);
506
- break;
507
- case best50_1.Best50.EComboTypes.FULL_COMBO_PLUS:
508
- comboImg = this.getThemeFile(theme.manifest.sprites.milestone.fcp, theme.path);
509
- break;
510
- case best50_1.Best50.EComboTypes.ALL_PERFECT:
511
- comboImg = this.getThemeFile(theme.manifest.sprites.milestone.ap, theme.path);
512
- break;
513
- case best50_1.Best50.EComboTypes.ALL_PERFECT_PLUS:
514
- comboImg = this.getThemeFile(theme.manifest.sprites.milestone.app, theme.path);
515
- break;
516
- }
517
- switch (score.sync) {
518
- case best50_1.Best50.ESyncTypes.NONE:
519
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.none, theme.path);
520
- break;
521
- case best50_1.Best50.ESyncTypes.SYNC_PLAY:
522
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.sync, theme.path);
523
- break;
524
- case best50_1.Best50.ESyncTypes.FULL_SYNC:
525
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.fs, theme.path);
526
- break;
527
- case best50_1.Best50.ESyncTypes.FULL_SYNC_PLUS:
528
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.fsp, theme.path);
529
- break;
530
- case best50_1.Best50.ESyncTypes.FULL_SYNC_DX:
531
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.fdx, theme.path);
532
- break;
533
- case best50_1.Best50.ESyncTypes.FULL_SYNC_DX_PLUS:
534
- syncImg = this.getThemeFile(theme.manifest.sprites.milestone.fdxp, theme.path);
535
- break;
536
- }
537
- const combo = new canvas_1.Image();
538
- combo.src = comboImg;
539
- ctx.drawImage(combo, x + height * 0.806 * (0.32 * 2.133 + 0.06 - 0.1), y +
540
- element.bubble.margin +
541
- titleSize +
542
- element.bubble.margin * (1 / 2), height * 0.806 * 0.32, height * 0.806 * 0.32);
543
- const sync = new canvas_1.Image();
544
- sync.src = syncImg;
545
- ctx.drawImage(sync, x + height * 0.806 * (0.32 * 2.133 + 0.04 + 0.32 - 0.1), y +
546
- element.bubble.margin +
547
- titleSize +
548
- element.bubble.margin * (1 / 2), height * 0.806 * 0.32, height * 0.806 * 0.32);
549
- }
550
- }
551
- /** End Milestone Draw */
552
- /** Begin Version Draw */
553
- {
554
- let versions = [];
555
- for (let i = 0; i < 3; ++i) {
556
- versions[i] = {
557
- region: "DX",
558
- version: undefined,
559
- EXAppend: false,
560
- };
561
- }
562
- const VER_DX = chart.difficulty == type_1.EDifficulty.REMASTER
563
- ? chart.events.find((v) => v.type == "existence" &&
564
- v.version.region == "DX")?.version
565
- : chart.addVersion.DX;
566
- const VER_EX = chart.difficulty == type_1.EDifficulty.REMASTER
567
- ? chart.events.find((v) => v.type == "existence" &&
568
- v.version.region == "EX")?.version
569
- : chart.addVersion.EX;
570
- const VER_CN = chart.difficulty == type_1.EDifficulty.REMASTER
571
- ? chart.events.find((v) => v.type == "existence" &&
572
- v.version.region == "CN")?.version
573
- : chart.addVersion.CN;
574
- if (VER_DX) {
575
- const version = versions[0];
576
- version.version = VER_DX;
577
- version.region = "DX";
578
- }
579
- if (VER_EX) {
580
- for (let i = 0; i < 3; ++i) {
581
- const version = versions[i];
582
- if (version.version) {
583
- if (!(version.version.gameVersion.isDX &&
584
- version.version.gameVersion.minor >= 10 &&
585
- version.version.gameVersion.minor < 20) &&
586
- lodash_1.default.isEqual(versions[i].version?.gameVersion, VER_EX.gameVersion)) {
587
- versions[i].EXAppend = true;
588
- break;
589
- }
590
- }
591
- else {
592
- version.version = VER_EX;
593
- version.region = "EX";
594
- break;
595
- }
596
- }
597
- }
598
- if (VER_CN) {
599
- for (let i = 0; i < 3; ++i) {
600
- const version = versions[i];
601
- if (version.version) {
602
- if (!version.version.gameVersion.isDX &&
603
- lodash_1.default.isEqual(versions[i].version?.gameVersion, VER_CN.gameVersion)) {
604
- break;
605
- }
606
- }
607
- else {
608
- version.version = VER_CN;
609
- version.region = "CN";
610
- break;
611
- }
612
- }
613
- }
614
- let counter = 0;
615
- for (const version of versions) {
616
- if (version.version) {
617
- counter++;
618
- if (!version.version.gameVersion.isDX)
619
- version.region = "OLD";
620
- }
621
- }
622
- const versionImageHeight = (height - element.bubble.margin * 2) *
623
- (isShort ? 1 / 3 : 3 / 8);
624
- const versionImageWidth = (versionImageHeight / 160) * 332;
625
- const regionTextSize = versionImageHeight * (5 / 8);
626
- for (let i = 0, curx = x + width - element.bubble.margin, cury = y + element.bubble.margin; i < versions.length; ++i,
627
- cury =
628
- isShort ||
629
- curx - versionImageWidth - regionTextSize <
630
- x + height * 2
631
- ? cury + versionImageHeight
632
- : cury,
633
- curx =
634
- isShort ||
635
- curx - versionImageWidth - regionTextSize <
636
- x + height * 2
637
- ? x + width - element.bubble.margin
638
- : curx) {
639
- const version = versions[i];
640
- if (version.version) {
641
- let region = version.region;
642
- if (version.region == "EX" &&
643
- !(version.version.gameVersion.minor >= 10 &&
644
- version.version.gameVersion.minor < 20)) {
645
- region = "DX";
646
- }
647
- const rawVersion = this.findVersion(version.version.gameVersion.minor, version.version.gameVersion.isDX, region == "CN");
648
- const versionImage = this.getThemeFile(theme.manifest.sprites.versions[region][rawVersion]);
649
- try {
650
- (0, sharp_1.default)(versionImage);
651
- if (versionImage) {
652
- const versionImg = new canvas_1.Image();
653
- versionImg.src = versionImage;
654
- let text;
655
- switch (version.region) {
656
- case "DX":
657
- if (version.EXAppend)
658
- text = "🇯🇵🌏";
659
- else
660
- text = "🇯🇵";
661
- break;
662
- case "EX":
663
- text = "🌏";
664
- break;
665
- case "CN":
666
- text = "🇨🇳";
667
- break;
668
- default:
669
- text = "";
670
- }
671
- ctx.drawImage(versionImg, (curx -= versionImageWidth), cury, versionImageWidth, versionImageHeight);
672
- if (version.region != "OLD") {
673
- await util_1.Util.drawEmojiOrGlyph(ctx, text, curx, cury +
674
- regionTextSize +
675
- (versionImageHeight -
676
- regionTextSize) /
677
- 2, regionTextSize, Infinity, "right");
678
- curx -=
679
- util_1.Util.visibleLength(text) *
680
- regionTextSize +
681
- element.bubble.margin;
682
- }
683
- }
684
- }
685
- catch { }
686
- }
687
- }
688
- /** End Version Draw */
689
- /** Begin Note Count Draw */
690
- const noteCountTexts = Object.entries(chart.meta.notes).map(([k, v]) => `${util_1.Util.capitalize(k)}: ${v}`);
691
- const noteCountTextSize = (height - element.bubble.margin * 4) /
692
- noteCountTexts.length;
693
- let noteCountLength = 0;
694
- noteCountTexts.forEach((v, i) => {
695
- util_1.Util.drawText(ctx, v, x + element.bubble.margin * (3 / 2) + height * 2, y +
696
- element.bubble.margin +
697
- noteCountTextSize +
698
- (noteCountTextSize + element.bubble.margin / 2) * i, noteCountTextSize, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
699
- const length = util_1.Util.measureText(ctx, v, noteCountTextSize, Infinity).width;
700
- if (length > noteCountLength)
701
- noteCountLength = length;
702
- });
703
- /** End Note Count Draw */
704
- /** Begin Internal Level Trend Draw */
705
- if (!isShort) {
706
- const CURRENT_MINOR = (() => {
707
- switch (targetRegion) {
708
- case "EX":
709
- return this.EX_LATEST;
710
- case "CN":
711
- return this.CN_LATEST;
712
- case "DX":
713
- default:
714
- return this.DX_LATEST;
715
- }
716
- })();
717
- const maxWidth = width -
718
- height * 2 -
719
- element.bubble.margin * 4 -
720
- noteCountLength;
721
- const maxFitTrendCount = Math.trunc(maxWidth / versionImageWidth);
722
- const trendEvents = chart.events.filter((v) => v.type == "existence" &&
723
- v.version.region == targetRegion);
724
- let actualEvents = lodash_1.default.uniqWith(trendEvents, (a, b) => {
725
- return lodash_1.default.isEqual(a.data.level, b.data.level);
726
- });
727
- if (actualEvents.length == maxFitTrendCount) {
728
- }
729
- else if (actualEvents.length > maxFitTrendCount) {
730
- while (actualEvents.length > maxFitTrendCount)
731
- actualEvents.shift();
732
- actualEvents.shift();
733
- actualEvents.shift();
734
- actualEvents.unshift(trendEvents[0]);
735
- actualEvents.push(trendEvents[trendEvents.length - 1]);
736
- }
737
- else if (trendEvents.length > maxFitTrendCount) {
738
- actualEvents = lodash_1.default.filter(actualEvents, (v) => !(lodash_1.default.isEqual(v.version.gameVersion, trendEvents[0].version.gameVersion) ||
739
- lodash_1.default.isEqual(v.version.gameVersion, trendEvents[trendEvents.length - 1]
740
- .version.gameVersion)));
741
- for (let i = trendEvents.length - 2; i > 0 && actualEvents.length < maxFitTrendCount - 2; --i) {
742
- const event = trendEvents[i];
743
- if (event)
744
- actualEvents.push(event);
745
- actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
746
- return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
747
- lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor));
748
- });
749
- }
750
- actualEvents.unshift(trendEvents[0]);
751
- actualEvents.push(trendEvents[trendEvents.length - 1]);
752
- actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
753
- return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
754
- lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor));
755
- });
756
- actualEvents = lodash_1.default.sortBy(actualEvents, (v) => v.version.gameVersion.minor);
757
- if (trendEvents.length > 1) {
758
- if (actualEvents.length >= maxFitTrendCount)
759
- actualEvents.pop();
760
- actualEvents.push(trendEvents[trendEvents.length - 1]);
761
- }
762
- const removalEvent = chart.events.find((v) => v.type == "removal" &&
763
- v.version.region == targetRegion);
764
- if (removalEvent) {
765
- actualEvents.pop();
766
- actualEvents.push(removalEvent);
767
- }
768
- }
769
- else {
770
- actualEvents = [...trendEvents];
771
- }
772
- if (actualEvents[actualEvents.length - 1]?.version
773
- .gameVersion.minor < CURRENT_MINOR) {
774
- while (actualEvents.length >= maxFitTrendCount)
775
- actualEvents.pop();
776
- actualEvents.push({
777
- type: "removal",
778
- version: util_1.Util.Maimai.Version.toEventVersion(util_1.Util.Maimai.Version.getNextVersion(trendEvents[trendEvents.length - 1].version)),
779
- });
780
- }
781
- actualEvents = lodash_1.default.uniqWith(actualEvents, (a, b) => {
782
- return (lodash_1.default.isEqual(a.version.gameVersion.major, b.version.gameVersion.major) &&
783
- lodash_1.default.isEqual(a.version.gameVersion.minor, b.version.gameVersion.minor) &&
784
- lodash_1.default.isEqual(a.type, b.type));
785
- });
786
- let positionAdjustment = 0;
787
- let addGap = (maxWidth - actualEvents.length * versionImageWidth) /
788
- (actualEvents.length - 1);
789
- if (addGap > maxWidth / 5) {
790
- addGap = maxWidth / 5;
791
- positionAdjustment =
792
- (maxWidth -
793
- (addGap * (actualEvents.length - 1) +
794
- versionImageWidth * actualEvents.length)) /
795
- 2;
796
- }
797
- for (let i = 0, curx = x +
798
- positionAdjustment +
799
- height * 2 +
800
- element.bubble.margin * (5 / 2) +
801
- noteCountLength, cury = y +
802
- element.bubble.margin * (3 / 2) +
803
- versionImageHeight; i < actualEvents.length; ++i) {
804
- const event = actualEvents[i];
805
- if (!event)
806
- continue;
807
- let logoRegion = event
808
- .version.gameVersion.isDX
809
- ? targetRegion
810
- : "OLD";
811
- if (logoRegion == "EX") {
812
- if (!(10 <= event.version.gameVersion.minor &&
813
- event.version.gameVersion.minor < 20)) {
814
- logoRegion = "DX";
815
- }
816
- }
817
- const rawVersion = this.findVersion(event.version.gameVersion.minor, event.version.gameVersion.isDX, logoRegion == "CN");
818
- const versionImage = this.getThemeFile(theme.manifest.sprites.versions[logoRegion][rawVersion]);
819
- try {
820
- (0, sharp_1.default)(versionImage);
821
- if (versionImage) {
822
- const versionImg = new canvas_1.Image();
823
- versionImg.src = versionImage;
824
- ctx.drawImage(versionImg, curx, cury, versionImageWidth, versionImageHeight);
825
- if (event.type == "existence") {
826
- let symbol = "";
827
- if (i != 0) {
828
- const lastEvent = actualEvents[i - 1];
829
- if (lastEvent.type == "existence") {
830
- if (lastEvent.data.level <
831
- event.data.level)
832
- symbol = "↑";
833
- else if (lastEvent.data.level >
834
- event.data.level)
835
- symbol = "↓";
836
- else if (lastEvent.data.level ==
837
- event.data.level)
838
- symbol = "→";
839
- }
840
- }
841
- util_1.Util.drawText(ctx, `${symbol}${util_1.Util.truncate(event.data.level, 1)}`, curx + versionImageWidth / 2, cury +
842
- versionImageHeight +
843
- noteCountTextSize, noteCountTextSize, height * 0.806 * 0.04, Infinity, "center", "white", new color_1.default(curColor).darken(0.3).hexa());
844
- }
845
- else if (event.type == "removal") {
846
- util_1.Util.drawText(ctx, `❌`, curx + versionImageWidth / 2, cury +
847
- versionImageHeight +
848
- noteCountTextSize, noteCountTextSize, height * 0.806 * 0.04, Infinity, "center", "white", new color_1.default(curColor).darken(0.3).hexa());
849
- }
850
- curx += versionImageWidth + addGap;
851
- }
852
- }
853
- catch { }
854
- }
855
- }
856
- }
857
- /** End Internal Level Trend Draw */
858
- ctx.restore();
859
- }
860
- /** End Main Content Draw */
861
- ctx.fillStyle = new color_1.default(curColor).lighten(0.4).hexa();
862
- ctx.beginPath();
863
- ctx.roundRect(x, y + height * 0.742, height * 2, height * (1 - 0.742), [
864
- 0,
865
- (height * 0.806) / 7,
866
- 0,
867
- (height * 0.806) / 7,
868
- ]);
869
- ctx.fill();
870
- /** Begin Difficulty & DX Rating Draw */
871
- {
872
- ctx.save();
873
- ctx.clip();
874
- util_1.Util.drawText(ctx, chart.designer.name || "-", x + element.bubble.margin, y + height * (0.806 + (1 - 0.806) / 2), height * 0.806 * 0.128, height * 0.806 * 0.04, Infinity, "left", "white", new color_1.default(curColor).darken(0.3).hexa());
875
- ctx.restore();
876
- util_1.Util.drawText(ctx, `${score ? `${score.dxScore}/` : "MAX DX SCR: "}${chart.meta.maxDXScore}`, x + height * 2 - element.bubble.margin, y + height - element.bubble.margin * 3.1, height * 0.806 * 0.128, height * 0.806 * 0.04, Infinity, "right", "white", new color_1.default(curColor).darken(0.3).hexa());
877
- }
878
- /** End Difficulty & DX Rating Draw */
879
- ctx.restore();
880
- /** End Card Draw */
881
- }
882
- static async drawDetailInfoModule(ctx, theme, element, chartId) {
883
- const jacketMargin = element.margin;
884
- const textMargin = element.margin;
885
- const chart = Chart.Database.getLocalChart(chartId, type_1.EDifficulty.BASIC);
886
- const jacket = await Chart.Database.fecthJacket(chartId);
887
- /* Begin Background Draw */
888
- ctx.beginPath();
889
- ctx.roundRect(element.x, element.y, element.width, element.height, Math.min(theme.manifest.width, theme.manifest.height) * (3 / 128));
890
- ctx.fillStyle = element.color.card;
891
- ctx.strokeStyle = new color_1.default(element.color.card).darken(0.6).hex();
892
- ctx.lineWidth =
893
- Math.min(theme.manifest.width, theme.manifest.height) * (3 / 512);
894
- ctx.stroke();
895
- ctx.fill();
896
- /* End Background Draw */
897
- /* Begin jacket draw */
898
- if (jacket) {
899
- const jacketImage = new canvas_1.Image();
900
- const roundRadius = Math.min(theme.manifest.width, theme.manifest.height) *
901
- (3 / 128);
902
- jacketImage.src = jacket;
903
- ctx.beginPath();
904
- ctx.roundRect(element.x + jacketMargin, element.y + jacketMargin, element.width - jacketMargin * 2, element.width - jacketMargin * 2, [roundRadius, roundRadius, 0, 0]);
905
- ctx.save();
906
- ctx.clip();
907
- ctx.drawImage(jacketImage, element.x + jacketMargin, element.y + jacketMargin, element.width - jacketMargin * 2, element.width - jacketMargin * 2);
908
- ctx.restore();
909
- }
910
- /* End jacket draw */
911
- /* Begin Detail Draw */
912
- if (chart) {
913
- const textSizeTitle = element.width * (1 / 16);
914
- const textSizeSecondary = element.width * (1 / 24);
915
- const { actualBoundingBoxAscent: ascent, actualBoundingBoxDescent: decent, } = util_1.Util.measureText(ctx, chart.name, textSizeTitle, Infinity);
916
- const titleActualHeight = Math.abs(ascent - decent);
917
- const mode = new canvas_1.Image();
918
- const chartModeBadgeImg = this.getThemeFile(chart.id > 10000
919
- ? theme.manifest.sprites.mode.dx
920
- : theme.manifest.sprites.mode.standard, theme.path);
921
- const { width: modeWidth, height: modeHeight } = await (0, sharp_1.default)(chartModeBadgeImg).metadata();
922
- const aspectRatio = (modeWidth ?? 0) / (modeHeight ?? 1) || 3;
923
- const textLineWidth = element.width * (7 / 512);
924
- const textColor = new color_1.default(element.color.card).darken(0.5).hex();
925
- const textTitleMaxWidth = element.width - textMargin * 2 - textSizeTitle * aspectRatio;
926
- const titleMetrics = util_1.Util.measureText(ctx, chart.name, textSizeTitle, textTitleMaxWidth);
927
- util_1.Util.drawText(ctx, chart.name, element.x + textMargin, element.y +
928
- jacketMargin +
929
- textMargin * (1 / 2) +
930
- (element.width - jacketMargin * 2) +
931
- textSizeTitle, textSizeTitle, textLineWidth, textTitleMaxWidth, "left", "white", textColor);
932
- util_1.Util.drawText(ctx, chart.artist, element.x + textMargin, element.y +
933
- jacketMargin +
934
- textMargin * (1 / 2) +
935
- (element.width - jacketMargin * 2) +
936
- textSizeTitle * 2, textSizeSecondary, textLineWidth, element.width - textMargin * 2, "left", "white", textColor);
937
- util_1.Util.drawText(ctx, `#${chart.id} BPM: ${chart.bpm}`, element.x + textMargin, element.y +
938
- jacketMargin +
939
- textMargin * (1 / 2) +
940
- (element.width - jacketMargin * 2) +
941
- textSizeTitle * 3, textSizeSecondary, textLineWidth, element.width - textMargin * 2, "left", "white", textColor);
942
- const EVENT_DX = chart.events
943
- .filter((v) => v.version.region == "DX" &&
944
- v.version.gameVersion.minor >= Chart.DX_LATEST)
945
- .map((v) => v.type);
946
- const EVENT_EX = chart.events
947
- .filter((v) => v.version.region == "EX" &&
948
- v.version.gameVersion.minor >= Chart.EX_LATEST)
949
- .map((v) => v.type);
950
- const EVENT_CN = chart.events
951
- .filter((v) => v.version.region == "CN" &&
952
- v.version.gameVersion.minor >= Chart.CN_LATEST)
953
- .map((v) => v.type);
954
- const EXIST_DX = EVENT_DX.includes("existence") && !EVENT_DX.includes("removal")
955
- ? "🇯🇵"
956
- : "";
957
- const EXIST_EX = EVENT_EX.includes("existence") && !EVENT_EX.includes("removal")
958
- ? "🌏"
959
- : "";
960
- const EXIST_CN = EVENT_CN.includes("existence") && !EVENT_CN.includes("removal")
961
- ? "🇨🇳"
962
- : "";
963
- const title = [];
964
- if (EXIST_DX)
965
- title.push(EXIST_DX);
966
- if (EXIST_EX)
967
- title.push(EXIST_EX);
968
- if (EXIST_CN)
969
- title.push(EXIST_CN);
970
- await util_1.Util.drawEmojiOrGlyph(ctx, title.join(" "), element.x + element.width - textMargin, element.y +
971
- jacketMargin +
972
- textMargin * (1 / 2) +
973
- (element.width - jacketMargin * 2) +
974
- textSizeTitle * 3, textSizeSecondary * (9 / 8), element.width - textMargin * 2, "right", "white", textColor);
975
- /** Begin Chart Mode Draw */
976
- {
977
- mode.src = chartModeBadgeImg;
978
- ctx.drawImage(mode, element.x + textMargin * (3 / 2) + titleMetrics.width, element.y +
979
- jacketMargin +
980
- textMargin * (1 / 2) +
981
- (element.width - jacketMargin * 2) -
982
- titleActualHeight / 2 +
983
- textSizeTitle / 2, textSizeTitle * aspectRatio, textSizeTitle);
984
- }
985
- /** End Chart Mode Draw */
986
- }
987
- /* End Detail Draw */
988
- }
989
- static async drawChartGridModule(ctx, theme, element, chartId, scores, region = "DX") {
990
- /* Begin Background Draw */
991
- ctx.roundRect(element.x, element.y, element.width, element.height, Math.min(theme.manifest.width, theme.manifest.height) * (3 / 128));
992
- ctx.fillStyle = element.color.card;
993
- ctx.strokeStyle = new color_1.default(element.color.card).darken(0.6).hex();
994
- ctx.lineWidth =
995
- Math.min(theme.manifest.width, theme.manifest.height) * (3 / 512);
996
- ctx.stroke();
997
- ctx.fill();
998
- /* End Background Draw */
999
- const difficulties = [];
1000
- for (let i = type_1.EDifficulty.BASIC; i <= type_1.EDifficulty.REMASTER; ++i) {
1001
- const chart = Chart.Database.getLocalChart(chartId, i);
1002
- if (chart)
1003
- difficulties.push(chart);
1004
- }
1005
- const cardWidth = element.width - element.margin * 2;
1006
- const cardHeight = (element.height - element.margin * 2 - element.gap * 3) / 4;
1007
- for (let y = element.y + element.margin, i = 0; i < difficulties.length; ++i, y += cardHeight + element.gap) {
1008
- const chart = difficulties[i];
1009
- if (chart)
1010
- if (difficulties.length > 4 && i == 0) {
1011
- await this.drawChartGridCard(ctx, theme, element, chart, i, element.x + element.margin, y, (cardWidth - element.margin) / 2, cardHeight, true, region, scores[i]);
1012
- i++;
1013
- const chartA = difficulties[i];
1014
- if (chartA)
1015
- await this.drawChartGridCard(ctx, theme, element, chartA, i, element.x +
1016
- element.margin +
1017
- (cardWidth + element.margin) / 2, y, (cardWidth - element.margin) / 2, cardHeight, true, region, scores[i]);
1018
- }
1019
- else {
1020
- await this.drawChartGridCard(ctx, theme, element, chart, i, element.x + element.margin, y, cardWidth, cardHeight, false, region, scores[i]);
1021
- }
1022
- }
1023
- }
1024
- static async drawProfileModule(ctx, theme, element, username, rating, profilePicture) {
1025
- const nameplate = new canvas_1.Image();
1026
- nameplate.src = this.getThemeFile(theme.manifest.sprites.profile.nameplate, theme.path);
1027
- ctx.drawImage(nameplate, element.x, element.y, element.height * 6.207, element.height);
1028
- /* Begin Profile Picture Draw */
1029
- {
1030
- ctx.save();
1031
- ctx.beginPath();
1032
- ctx.roundRect(element.x + element.height * 0.064, element.y + element.height * 0.064, element.height * 0.872, element.height * 0.872, (element.height * 0.872) / 16);
1033
- ctx.clip();
1034
- ctx.fillStyle = "white";
1035
- ctx.fill();
1036
- const icon = new canvas_1.Image();
1037
- try {
1038
- (0, sharp_1.default)(profilePicture);
1039
- }
1040
- catch {
1041
- // Unknown profile picture binary
1042
- profilePicture = undefined;
1043
- }
1044
- const pfp = profilePicture ||
1045
- this.getThemeFile(theme.manifest.sprites.profile.icon, theme.path);
1046
- const { dominant } = await (0, sharp_1.default)(pfp).stats();
1047
- icon.src = await (0, sharp_1.default)(pfp).png().toBuffer();
1048
- const cropSize = Math.min(icon.width, icon.height);
1049
- ctx.drawImage(icon, (icon.width - cropSize) / 2, (icon.height - cropSize) / 2, cropSize, cropSize, element.x + element.height * 0.064, element.y + element.height * 0.064, element.height * 0.872, element.height * 0.872);
1050
- if (profilePicture) {
1051
- ctx.beginPath();
1052
- ctx.roundRect(element.x + element.height * 0.064, element.y + element.height * 0.064, element.height * 0.872, element.height * 0.872, (element.height * 0.872) / 16);
1053
- ctx.strokeStyle = color_1.default.rgb(dominant).darken(0.3).hex();
1054
- ctx.lineWidth = element.height / 30;
1055
- ctx.stroke();
1056
- }
1057
- ctx.restore();
1058
- }
1059
- /* End Profile Picture Draw */
1060
- /* Begin DX Rating Draw */
1061
- {
1062
- const dxRating = new canvas_1.Image();
1063
- let dxRatingImg;
1064
- switch (true) {
1065
- case rating >= 15000: {
1066
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.rainbow, theme.path);
1067
- break;
1068
- }
1069
- case rating >= 14500: {
1070
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.platinum, theme.path);
1071
- break;
1072
- }
1073
- case rating >= 14000: {
1074
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.gold, theme.path);
1075
- break;
1076
- }
1077
- case rating >= 13000: {
1078
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.silver, theme.path);
1079
- break;
1080
- }
1081
- case rating >= 12000: {
1082
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.bronze, theme.path);
1083
- break;
1084
- }
1085
- case rating >= 10000: {
1086
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.purple, theme.path);
1087
- break;
1088
- }
1089
- case rating >= 8000: {
1090
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.red, theme.path);
1091
- break;
1092
- }
1093
- case rating >= 6000: {
1094
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.yellow, theme.path);
1095
- break;
1096
- }
1097
- case rating >= 4000: {
1098
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.green, theme.path);
1099
- break;
1100
- }
1101
- case rating >= 2000: {
1102
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.blue, theme.path);
1103
- break;
1104
- }
1105
- default: {
1106
- dxRatingImg = this.getThemeFile(theme.manifest.sprites.dxRating.white, theme.path);
1107
- break;
1108
- }
1109
- }
1110
- dxRating.src = dxRatingImg;
1111
- ctx.drawImage(dxRating, element.x + element.height, element.y + element.height * 0.064, (element.height / 3) * 5.108, element.height / 3);
1112
- }
1113
- /* End DX Rating Draw */
1114
- /* Begin Username Draw */
1115
- {
1116
- ctx.beginPath();
1117
- ctx.roundRect(element.x + element.height * (1 + 1 / 32), element.y + element.height * (0.064 + 0.333 + 1 / 32), ((element.height / 3) * 5.108 * 6) / 5, (element.height * 7) / 24, element.height / 20);
1118
- ctx.fillStyle = "white";
1119
- ctx.strokeStyle = color_1.default.rgb(180, 180, 180).hex();
1120
- ctx.lineWidth = element.height / 32;
1121
- ctx.stroke();
1122
- ctx.fill();
1123
- const ratingImgBuffer = await this.getRatingNumber(rating, theme);
1124
- if (ratingImgBuffer) {
1125
- const { width, height } = await (0, sharp_1.default)(ratingImgBuffer).metadata();
1126
- if (width && height) {
1127
- const aspectRatio = width / height;
1128
- const image = new canvas_1.Image();
1129
- image.src = ratingImgBuffer;
1130
- const drawHeight = (element.height * 7) / 32;
1131
- ctx.drawImage(image, element.x + element.height * 1.785, element.y + element.height * 0.12, drawHeight * aspectRatio * 0.8, drawHeight);
1132
- }
1133
- }
1134
- util_1.Util.drawText(ctx, util_1.Util.HalfFullWidthConvert.toFullWidth(username), element.x + element.height * (1 + 1 / 16), element.y + 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");
1135
- }
1136
- /* End Username Draw*/
1137
- }
1138
- static async drawTextModule(ctx, theme, element, variables = {}) {
1139
- let naiveLines = (0, string_template_1.default)(element.content, variables).split("\n");
1140
- let lines = [];
1141
- if (element.linebreak) {
1142
- for (let originalContent of naiveLines) {
1143
- while (originalContent.length) {
1144
- const line = util_1.Util.findMaxFitString(ctx, originalContent, element.width || Infinity, "");
1145
- originalContent = originalContent.replace(line, "").trim();
1146
- lines.push(line.trim());
1147
- }
1148
- }
1149
- }
1150
- else {
1151
- for (const originalContent of naiveLines) {
1152
- lines.push(util_1.Util.findMaxFitString(ctx, originalContent, element.width || Infinity));
1153
- }
1154
- }
1155
- for (let i = 0; i < lines.length; ++i) {
1156
- const line = lines[i];
1157
- util_1.Util.drawText(ctx, line, element.x, element.y + i * element.size * 1.3, element.size, element.size / 3.5, element.width || Infinity, element.align, element.color || "#FFFFFF", element.borderColor
1158
- ? element.borderColor
1159
- : color_1.default.rgb(element.color || "#FFFFFF")
1160
- .darken(0.3)
1161
- .hex(), element.font, element.linebreak ? "" : "...");
1162
- }
1163
- }
1164
- /* End Draw Tools*/
1165
- static async draw(name, rating, chartId, scores, options) {
1166
- let currentTheme = this.primaryTheme;
1167
- if (options?.theme) {
1168
- const theme = this.getTheme(options.theme);
1169
- if (theme) {
1170
- currentTheme = theme;
1171
- }
1172
- }
1173
- const chart = Chart.Database.getLocalChart(chartId, type_1.EDifficulty.BASIC);
1174
- if (!chart)
1175
- return null;
1176
- if (currentTheme) {
1177
- await Chart.Database.cacheJackets([chartId]);
1178
- const canvas = new canvas_1.Canvas(currentTheme.manifest.width * (options?.scale ?? 1), currentTheme.manifest.height * (options?.scale ?? 1));
1179
- const ctx = canvas.getContext("2d");
1180
- if (options?.scale)
1181
- ctx.scale(options.scale, options.scale);
1182
- ctx.imageSmoothingEnabled = true;
1183
- for (const element of currentTheme.manifest.elements) {
1184
- switch (element.type) {
1185
- case "image": {
1186
- await this.drawImageModule(ctx, currentTheme, element);
1187
- break;
1188
- }
1189
- case "chart-grid": {
1190
- await this.drawChartGridModule(ctx, currentTheme, element, chartId, scores, options?.region);
1191
- break;
1192
- }
1193
- case "detail-info": {
1194
- await this.drawDetailInfoModule(ctx, currentTheme, element, chartId);
1195
- break;
1196
- }
1197
- case "profile": {
1198
- await this.drawProfileModule(ctx, currentTheme, element, name, rating, options?.profilePicture);
1199
- break;
1200
- }
1201
- case "text": {
1202
- await this.drawTextModule(ctx, currentTheme, element, {
1203
- username: util_1.Util.HalfFullWidthConvert.toFullWidth(name),
1204
- rating: util_1.Util.truncate(rating, 0),
1205
- });
1206
- break;
1207
- }
1208
- }
1209
- }
1210
- return canvas.toBuffer();
1211
- }
1212
- else
1213
- return null;
1214
- }
1215
- static async drawWithScoreSource(source, username, chartId, options) {
1216
- const profile = await source.getPlayerInfo(username);
1217
- const score = await source.getPlayerScore(username, chartId);
1218
- if (!profile || !score)
1219
- return null;
1220
- return this.draw(profile.name, profile.rating, chartId, [
1221
- score.basic,
1222
- score.advanced,
1223
- score.expert,
1224
- score.master,
1225
- score.remaster,
1226
- score.utage,
1227
- ], {
1228
- ...options,
1229
- profilePicture: options?.profilePicture === null
1230
- ? undefined
1231
- : options?.profilePicture ||
1232
- (await source.getPlayerProfilePicture(username)) ||
1233
- undefined,
1234
- });
1235
- }
1236
- static async getRatingNumber(num, theme) {
1237
- async function getRaingDigit(map, digit, unitWidth, unitHeight) {
1238
- digit = Math.trunc(digit % 10);
1239
- return await (0, sharp_1.default)(map)
1240
- .extract({
1241
- left: (digit % 4) * unitWidth,
1242
- top: Math.trunc(digit / 4) * unitHeight,
1243
- width: unitWidth,
1244
- height: unitHeight,
1245
- })
1246
- .toBuffer();
1247
- }
1248
- if (theme.manifest) {
1249
- const map = this.getThemeFile(theme.manifest.sprites.dxRatingNumberMap, theme.path);
1250
- const { width, height } = await (0, sharp_1.default)(map).metadata();
1251
- if (!(width && height))
1252
- return null;
1253
- const unitWidth = width / 4, unitHeight = height / 4;
1254
- let digits = [];
1255
- while (num > 0) {
1256
- digits.push(await getRaingDigit(map, num % 10, unitWidth, unitHeight));
1257
- num = Math.trunc(num / 10);
1258
- }
1259
- while (digits.length < 5)
1260
- digits.push(null);
1261
- digits = digits.reverse();
1262
- const canvas = new canvas_1.Canvas(unitWidth * digits.length, unitHeight);
1263
- const ctx = canvas.getContext("2d");
1264
- for (let i = 0; i < digits.length; ++i) {
1265
- const curDigit = digits[i];
1266
- if (!curDigit)
1267
- continue;
1268
- const img = new canvas_1.Image();
1269
- img.src = curDigit;
1270
- ctx.drawImage(img, unitWidth * i * 0.88, 0);
1271
- }
1272
- return canvas.toBuffer();
1273
- }
1274
- return null;
1275
- }
1276
- }
1277
- exports.Chart = Chart;
1278
- (function (Chart) {
1279
- Chart.Database = database.Database;
1280
- })(Chart || (exports.Chart = Chart = {}));
1281
- //# sourceMappingURL=index.js.map