codeplay-common 4.6.7 → 4.6.9
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.
- package/.gitattributes +2 -2
- package/LICENSE +21 -21
- package/README.md +120 -120
- package/files/buildCodeplay/codeplayBeforeBuild-6.3.js +4006 -4006
- package/files/buildCodeplay/packageidBaseModification-1.4.js +445 -445
- package/files/buildCodeplay/setSplashAnimation-1.4.js +156 -156
- package/files/buildCodeplay/versions.json +23 -23
- package/files/finalrelease +966 -966
- package/files/generate-ai-promo-video.js +23 -23
- package/files/iap-install-2.js +145 -145
- package/files/ionic.config.json +6 -6
- package/files/scripts/setup-baseline-profile.js +262 -262
- package/files/take-screen-image.js +376 -20
- package/files/take-screen-video.js +644 -644
- package/package.json +15 -15
- package/scripts/sync-files.js +103 -103
- package/scripts/uninstall.js +109 -109
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
//node take-screen-image.js --delete 3
|
|
2
2
|
//node take-screen-image.js --delete 3,4,5
|
|
3
|
-
|
|
3
|
+
//node take-screen-image.js --profiles vivo-store //only taking screenshot for vivo-store - Not only vivo, we can do this to all of our store images.
|
|
4
|
+
//node take-screen-image.js --vivo-existing //Used if we already took the screenshot and those vivo screenshots are not there then execute this to resize the screenshot for vivo store.
|
|
5
|
+
//node take-screen-image.js --oppo-existing //Used if we already took the screenshot and those oppo screenshots are not there then execute this to resize the screenshot for Oppo store.
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
const fs = require('node:fs');
|
|
7
9
|
const path = require('node:path');
|
|
8
10
|
const readline = require('node:readline/promises');
|
|
9
11
|
const { spawn, spawnSync } = require('node:child_process');
|
|
12
|
+
const sharp = require('sharp');
|
|
10
13
|
|
|
11
14
|
const screenshotDirectory = path.join(__dirname, 'Auto-Screenshot', 'Store-image-Screenshot');
|
|
12
15
|
const inFrameDirectory = path.join(__dirname, 'Auto-Screenshot', 'Store-image-Frame');
|
|
@@ -53,6 +56,52 @@ const deviceProfiles = [
|
|
|
53
56
|
orientationSensitive: true,
|
|
54
57
|
mobile: true,
|
|
55
58
|
},
|
|
59
|
+
{
|
|
60
|
+
name: 'vivo-store',
|
|
61
|
+
label: 'Vivo Store portrait screenshot',
|
|
62
|
+
outputDirectory: 'Vivo-Store',
|
|
63
|
+
frameType: 'android-phone',
|
|
64
|
+
width: 360,
|
|
65
|
+
height: 720,
|
|
66
|
+
deviceScaleFactor: 3,
|
|
67
|
+
framedWidth: 1080,
|
|
68
|
+
framedHeight: 2160,
|
|
69
|
+
orientationSensitive: false,
|
|
70
|
+
mobile: true,
|
|
71
|
+
storeRequirements: {
|
|
72
|
+
maxFileSizeBytes: 5 * 1024 * 1024,
|
|
73
|
+
minPixels: 320,
|
|
74
|
+
maxPixels: 3840,
|
|
75
|
+
minAspectRatio: 0.5,
|
|
76
|
+
maxAspectRatio: 2,
|
|
77
|
+
minImages: 4,
|
|
78
|
+
maxImages: 8,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'oppo-store',
|
|
83
|
+
label: 'Oppo Store portrait screenshot',
|
|
84
|
+
outputDirectory: 'Oppo-Store',
|
|
85
|
+
frameType: 'android-phone',
|
|
86
|
+
width: 360,
|
|
87
|
+
height: 640,
|
|
88
|
+
deviceScaleFactor: 3,
|
|
89
|
+
framedWidth: 1080,
|
|
90
|
+
framedHeight: 1920,
|
|
91
|
+
orientationSensitive: false,
|
|
92
|
+
mobile: true,
|
|
93
|
+
outputFormat: 'jpeg',
|
|
94
|
+
outputExtension: 'jpg',
|
|
95
|
+
storeRequirements: {
|
|
96
|
+
maxFileSizeBytes: 1000 * 1000,
|
|
97
|
+
minPixels: 320,
|
|
98
|
+
maxPixels: 1920,
|
|
99
|
+
minAspectRatio: 0.5,
|
|
100
|
+
maxAspectRatio: 0.6,
|
|
101
|
+
minImages: 3,
|
|
102
|
+
maxImages: 5,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
56
105
|
{
|
|
57
106
|
name: 'android-tablet-7-inch',
|
|
58
107
|
aliases: ['android-tablet'],
|
|
@@ -353,31 +402,33 @@ function getSelectedOutputDirectories(selectedProfiles) {
|
|
|
353
402
|
}
|
|
354
403
|
|
|
355
404
|
function getNextNumberedFileName(selectedProfiles) {
|
|
405
|
+
const extension = selectedProfiles[0]?.outputExtension || 'png';
|
|
356
406
|
const highestNumber = getSelectedOutputDirectories(selectedProfiles)
|
|
357
407
|
.filter((directory) => fs.existsSync(directory))
|
|
358
408
|
.reduce((highestAcrossDirectories, directory) => {
|
|
359
409
|
const highestInDirectory = fs.readdirSync(directory, { withFileTypes: true })
|
|
360
410
|
.filter((entry) => entry.isFile())
|
|
361
411
|
.reduce((highest, entry) => {
|
|
362
|
-
const match = entry.name.match(
|
|
412
|
+
const match = entry.name.match(new RegExp(`^(\\d+)\\.${extension}$`, 'i'));
|
|
363
413
|
return match ? Math.max(highest, Number(match[1])) : highest;
|
|
364
414
|
}, 0);
|
|
365
415
|
|
|
366
416
|
return Math.max(highestAcrossDirectories, highestInDirectory);
|
|
367
417
|
}, 0);
|
|
368
418
|
|
|
369
|
-
return `${highestNumber + 1}
|
|
419
|
+
return `${highestNumber + 1}.${extension}`;
|
|
370
420
|
}
|
|
371
421
|
|
|
372
422
|
function getUniqueFileName(prefix, selectedProfiles) {
|
|
423
|
+
const extension = selectedProfiles[0]?.outputExtension || 'png';
|
|
373
424
|
const outputDirectories = getSelectedOutputDirectories(selectedProfiles);
|
|
374
|
-
let fileName = `${prefix}
|
|
425
|
+
let fileName = `${prefix}.${extension}`;
|
|
375
426
|
let duplicateNumber = 2;
|
|
376
427
|
|
|
377
428
|
while (outputDirectories.some((directory) => (
|
|
378
429
|
fs.existsSync(path.join(directory, fileName))
|
|
379
430
|
))) {
|
|
380
|
-
fileName = `${prefix}-${duplicateNumber}
|
|
431
|
+
fileName = `${prefix}-${duplicateNumber}.${extension}`;
|
|
381
432
|
duplicateNumber += 1;
|
|
382
433
|
}
|
|
383
434
|
|
|
@@ -385,7 +436,7 @@ function getUniqueFileName(prefix, selectedProfiles) {
|
|
|
385
436
|
}
|
|
386
437
|
|
|
387
438
|
function getScreenshotFileName(fileNameInput, selectedProfiles) {
|
|
388
|
-
const inputWithoutExtension = fileNameInput.trim().replace(/\.png$/i, '');
|
|
439
|
+
const inputWithoutExtension = fileNameInput.trim().replace(/\.(png|jpe?g)$/i, '');
|
|
389
440
|
|
|
390
441
|
if (!inputWithoutExtension) {
|
|
391
442
|
return getNextNumberedFileName(selectedProfiles);
|
|
@@ -411,6 +462,8 @@ function parseArguments() {
|
|
|
411
462
|
samsungAssets: false,
|
|
412
463
|
dryRun: false,
|
|
413
464
|
frameExisting: false,
|
|
465
|
+
vivoExisting: false,
|
|
466
|
+
oppoExisting: false,
|
|
414
467
|
help: false,
|
|
415
468
|
list: false,
|
|
416
469
|
deleteRequested: false,
|
|
@@ -430,6 +483,10 @@ function parseArguments() {
|
|
|
430
483
|
options.dryRun = true;
|
|
431
484
|
} else if (argument === '--frame-existing') {
|
|
432
485
|
options.frameExisting = true;
|
|
486
|
+
} else if (argument === '--vivo-existing') {
|
|
487
|
+
options.vivoExisting = true;
|
|
488
|
+
} else if (argument === '--oppo-existing') {
|
|
489
|
+
options.oppoExisting = true;
|
|
433
490
|
} else if (argument === '--help' || argument === '-h') {
|
|
434
491
|
options.help = true;
|
|
435
492
|
} else if (argument === '--list') {
|
|
@@ -460,13 +517,20 @@ function printProfiles() {
|
|
|
460
517
|
const outputWidth = profile.width * profile.deviceScaleFactor;
|
|
461
518
|
const outputHeight = profile.height * profile.deviceScaleFactor;
|
|
462
519
|
const framedSize = profile.framedWidth
|
|
463
|
-
? `, framed
|
|
520
|
+
? `, framed ${(profile.outputFormat || 'png').toUpperCase()} ${profile.framedWidth}x${profile.framedHeight}`
|
|
464
521
|
: '';
|
|
465
522
|
console.log(
|
|
466
523
|
`${profile.name.padEnd(15)} ${profile.label} `
|
|
467
524
|
+ `(folder ${profile.outputDirectory}, viewport ${profile.width}x${profile.height}, `
|
|
468
|
-
+
|
|
525
|
+
+ `${(profile.outputFormat || 'png').toUpperCase()} ${outputWidth}x${outputHeight}${framedSize})`,
|
|
469
526
|
);
|
|
527
|
+
if (profile.storeRequirements) {
|
|
528
|
+
console.log(
|
|
529
|
+
` Store limits: ${profile.storeRequirements.minImages}-${profile.storeRequirements.maxImages} images, `
|
|
530
|
+
+ `max ${profile.storeRequirements.maxFileSizeBytes / (1024 * 1024)} MB, `
|
|
531
|
+
+ `width/height ${profile.storeRequirements.minAspectRatio}-${profile.storeRequirements.maxAspectRatio}:1`,
|
|
532
|
+
);
|
|
533
|
+
}
|
|
470
534
|
}
|
|
471
535
|
}
|
|
472
536
|
|
|
@@ -478,6 +542,8 @@ function printHelp() {
|
|
|
478
542
|
console.log(' node take-screen-image.js --profiles iphone,ipad');
|
|
479
543
|
console.log(' node take-screen-image.js --prefix home --profiles android-phone,ipad');
|
|
480
544
|
console.log(' node take-screen-image.js --frame-existing');
|
|
545
|
+
console.log(' node take-screen-image.js --vivo-existing');
|
|
546
|
+
console.log(' node take-screen-image.js --oppo-existing');
|
|
481
547
|
console.log(' node take-screen-image.js --amazon-assets');
|
|
482
548
|
console.log(' node take-screen-image.js --samsung-assets');
|
|
483
549
|
console.log(' node take-screen-image.js --dry-run');
|
|
@@ -1154,9 +1220,84 @@ function getFrameAdornment(frameType) {
|
|
|
1154
1220
|
return '<div class="xr-status"></div>';
|
|
1155
1221
|
}
|
|
1156
1222
|
|
|
1157
|
-
function
|
|
1158
|
-
const screenshotDataUrl = `data:image
|
|
1159
|
-
const
|
|
1223
|
+
function createStoreDeviceFrameHtml(profile, screenshotBuffer, imageWidth, imageHeight, canvasWidth, canvasHeight, imageFormat) {
|
|
1224
|
+
const screenshotDataUrl = `data:image/${imageFormat === 'jpeg' ? 'jpeg' : 'png'};base64,${screenshotBuffer.toString('base64')}`;
|
|
1225
|
+
const screenWidth = Math.floor(Math.min(canvasWidth - 160, (canvasHeight - 180) * imageWidth / imageHeight));
|
|
1226
|
+
const accent = profile.name === 'oppo-store' ? '#76e4c2' : '#9daaff';
|
|
1227
|
+
|
|
1228
|
+
return `<!doctype html>
|
|
1229
|
+
<html>
|
|
1230
|
+
<head>
|
|
1231
|
+
<meta charset="utf-8" />
|
|
1232
|
+
<style>
|
|
1233
|
+
* { box-sizing: border-box; }
|
|
1234
|
+
html, body { width: 100%; height: 100%; margin: 0; overflow: hidden; }
|
|
1235
|
+
body {
|
|
1236
|
+
display: grid;
|
|
1237
|
+
place-items: center;
|
|
1238
|
+
background: radial-gradient(ellipse at 50% 43%, #24344d 0%, #101b2d 47%, #070e1a 100%);
|
|
1239
|
+
}
|
|
1240
|
+
body::before {
|
|
1241
|
+
content: '';
|
|
1242
|
+
position: absolute;
|
|
1243
|
+
width: 82%;
|
|
1244
|
+
height: 62%;
|
|
1245
|
+
border-radius: 50%;
|
|
1246
|
+
background: ${accent};
|
|
1247
|
+
opacity: 0.11;
|
|
1248
|
+
filter: blur(90px);
|
|
1249
|
+
}
|
|
1250
|
+
.device {
|
|
1251
|
+
position: relative;
|
|
1252
|
+
z-index: 1;
|
|
1253
|
+
width: ${screenWidth + 48}px;
|
|
1254
|
+
padding: 34px 18px 20px;
|
|
1255
|
+
border: 6px solid #8d99ac;
|
|
1256
|
+
border-radius: 48px;
|
|
1257
|
+
background: linear-gradient(135deg, #404c60, #111925 35%, #070c15 72%, #59657a);
|
|
1258
|
+
box-shadow: 0 38px 85px rgba(0, 0, 0, 0.58), 0 0 0 2px rgba(255, 255, 255, 0.19) inset;
|
|
1259
|
+
}
|
|
1260
|
+
.screen {
|
|
1261
|
+
width: ${screenWidth}px;
|
|
1262
|
+
background: #fff;
|
|
1263
|
+
box-shadow: 0 0 0 2px #03060c;
|
|
1264
|
+
}
|
|
1265
|
+
.screen img { display: block; width: 100%; height: auto; }
|
|
1266
|
+
.camera {
|
|
1267
|
+
position: absolute;
|
|
1268
|
+
top: 11px;
|
|
1269
|
+
left: 50%;
|
|
1270
|
+
width: 12px;
|
|
1271
|
+
height: 12px;
|
|
1272
|
+
transform: translateX(-50%);
|
|
1273
|
+
border-radius: 50%;
|
|
1274
|
+
background: radial-gradient(circle at 32% 30%, #547496, #070b12 48%, #000 80%);
|
|
1275
|
+
box-shadow: 0 0 0 3px #1b2534;
|
|
1276
|
+
}
|
|
1277
|
+
.side-button {
|
|
1278
|
+
position: absolute;
|
|
1279
|
+
top: 19%;
|
|
1280
|
+
right: -10px;
|
|
1281
|
+
width: 4px;
|
|
1282
|
+
height: 66px;
|
|
1283
|
+
border-radius: 0 3px 3px 0;
|
|
1284
|
+
background: #79869a;
|
|
1285
|
+
}
|
|
1286
|
+
</style>
|
|
1287
|
+
</head>
|
|
1288
|
+
<body>
|
|
1289
|
+
<main class="device">
|
|
1290
|
+
<div class="camera"></div>
|
|
1291
|
+
<div class="screen"><img src="${screenshotDataUrl}" /></div>
|
|
1292
|
+
<div class="side-button"></div>
|
|
1293
|
+
</main>
|
|
1294
|
+
</body>
|
|
1295
|
+
</html>`;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
function createDeviceFrameHtml(profile, screenshotBuffer, imageWidth = profile.width, imageHeight = profile.height, imageFormat = 'png') {
|
|
1299
|
+
const screenshotDataUrl = `data:image/${imageFormat === 'jpeg' ? 'jpeg' : 'png'};base64,${screenshotBuffer.toString('base64')}`;
|
|
1300
|
+
const aspectRatio = `${imageWidth} / ${imageHeight}`;
|
|
1160
1301
|
|
|
1161
1302
|
return `<!doctype html>
|
|
1162
1303
|
<html>
|
|
@@ -1200,20 +1341,21 @@ function createDeviceFrameHtml(profile, screenshotBuffer) {
|
|
|
1200
1341
|
.screen {
|
|
1201
1342
|
position: relative;
|
|
1202
1343
|
width: 100%;
|
|
1203
|
-
height:
|
|
1344
|
+
height: 87%;
|
|
1204
1345
|
overflow: hidden;
|
|
1205
|
-
background: #
|
|
1346
|
+
background: #f5f7fc;
|
|
1206
1347
|
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.95) inset;
|
|
1207
1348
|
}
|
|
1208
1349
|
.screen img {
|
|
1209
1350
|
display: block;
|
|
1210
1351
|
width: 100%;
|
|
1211
1352
|
height: 100%;
|
|
1212
|
-
object-fit:
|
|
1353
|
+
object-fit: contain;
|
|
1354
|
+
background: #f5f7fc;
|
|
1213
1355
|
}
|
|
1214
1356
|
.device.android-phone,
|
|
1215
1357
|
.device.iphone {
|
|
1216
|
-
height:
|
|
1358
|
+
height: 100%;
|
|
1217
1359
|
padding: 1.25%;
|
|
1218
1360
|
border-radius: clamp(24px, 8vw, 70px);
|
|
1219
1361
|
}
|
|
@@ -2040,6 +2182,9 @@ async function captureFramedScreenshot(
|
|
|
2040
2182
|
return false;
|
|
2041
2183
|
}
|
|
2042
2184
|
|
|
2185
|
+
const originalImageMetadata = profile.storeRequirements
|
|
2186
|
+
? await sharp(screenshotBuffer).metadata()
|
|
2187
|
+
: null;
|
|
2043
2188
|
const hasCustomFrameSize = Boolean(profile.framedWidth && profile.framedHeight);
|
|
2044
2189
|
const frameWidth = profile.framedWidth || profile.width;
|
|
2045
2190
|
const frameHeight = profile.framedHeight || profile.height;
|
|
@@ -2059,7 +2204,12 @@ async function captureFramedScreenshot(
|
|
|
2059
2204
|
const frameTree = await client.send('Page.getFrameTree');
|
|
2060
2205
|
await client.send('Page.setDocumentContent', {
|
|
2061
2206
|
frameId: frameTree.frameTree.frame.id,
|
|
2062
|
-
html:
|
|
2207
|
+
html: profile.name === 'vivo-store' || profile.name === 'oppo-store'
|
|
2208
|
+
? createStoreDeviceFrameHtml(
|
|
2209
|
+
profile, screenshotBuffer, originalImageMetadata.width, originalImageMetadata.height,
|
|
2210
|
+
frameWidth, frameHeight, originalImageMetadata.format,
|
|
2211
|
+
)
|
|
2212
|
+
: createDeviceFrameHtml(profile, screenshotBuffer, frameWidth, frameHeight),
|
|
2063
2213
|
});
|
|
2064
2214
|
await client.send('Runtime.evaluate', {
|
|
2065
2215
|
expression: `new Promise((resolve) => {
|
|
@@ -2076,21 +2226,50 @@ async function captureFramedScreenshot(
|
|
|
2076
2226
|
});
|
|
2077
2227
|
|
|
2078
2228
|
const framedScreenshot = await client.send('Page.captureScreenshot', {
|
|
2079
|
-
format: 'png',
|
|
2229
|
+
format: profile.outputFormat || 'png',
|
|
2230
|
+
quality: profile.outputFormat === 'jpeg' ? 90 : undefined,
|
|
2080
2231
|
fromSurface: true,
|
|
2081
2232
|
captureBeyondViewport: false,
|
|
2082
2233
|
});
|
|
2083
2234
|
|
|
2235
|
+
const framedScreenshotBuffer = Buffer.from(framedScreenshot.data, 'base64');
|
|
2236
|
+
validateStoreImage(profile, frameWidth, frameHeight, framedScreenshotBuffer);
|
|
2237
|
+
|
|
2084
2238
|
fs.mkdirSync(framedProfileDirectory, { recursive: true });
|
|
2085
2239
|
fs.writeFileSync(
|
|
2086
2240
|
framedScreenshotPath,
|
|
2087
|
-
|
|
2088
|
-
{ flag: 'wx' },
|
|
2241
|
+
framedScreenshotBuffer,
|
|
2242
|
+
{ flag: skipExisting ? 'wx' : 'w' },
|
|
2089
2243
|
);
|
|
2090
2244
|
console.log(`Saved framed ${profile.label}: ${framedScreenshotPath}`);
|
|
2091
2245
|
return true;
|
|
2092
2246
|
}
|
|
2093
2247
|
|
|
2248
|
+
function validateStoreImage(profile, width, height, imageBuffer) {
|
|
2249
|
+
if (!profile.storeRequirements) return;
|
|
2250
|
+
|
|
2251
|
+
const {
|
|
2252
|
+
maxFileSizeBytes, minPixels, maxPixels, minAspectRatio, maxAspectRatio,
|
|
2253
|
+
} = profile.storeRequirements;
|
|
2254
|
+
const aspectRatio = width / height;
|
|
2255
|
+
|
|
2256
|
+
if (
|
|
2257
|
+
width < minPixels || height < minPixels
|
|
2258
|
+
|| width > maxPixels || height > maxPixels
|
|
2259
|
+
|| aspectRatio < minAspectRatio || aspectRatio > maxAspectRatio
|
|
2260
|
+
) {
|
|
2261
|
+
throw new Error(
|
|
2262
|
+
`${profile.label} must be between ${minPixels}px and ${maxPixels}px with aspect ratio <= ${maxAspectRatio}:1; received ${width}x${height}.`,
|
|
2263
|
+
);
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
if (imageBuffer.length > maxFileSizeBytes) {
|
|
2267
|
+
throw new Error(
|
|
2268
|
+
`${profile.label} exceeds ${maxFileSizeBytes / (1024 * 1024)} MB: ${Math.ceil(imageBuffer.length / (1024 * 1024))} MB.`,
|
|
2269
|
+
);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2094
2273
|
async function captureProfile(client, snapshot, profile, screenshotFileName) {
|
|
2095
2274
|
await client.send('Emulation.setDeviceMetricsOverride', {
|
|
2096
2275
|
width: profile.width,
|
|
@@ -2118,7 +2297,8 @@ async function captureProfile(client, snapshot, profile, screenshotFileName) {
|
|
|
2118
2297
|
}
|
|
2119
2298
|
|
|
2120
2299
|
const screenshot = await client.send('Page.captureScreenshot', {
|
|
2121
|
-
format: 'png',
|
|
2300
|
+
format: profile.outputFormat || 'png',
|
|
2301
|
+
quality: profile.outputFormat === 'jpeg' ? 90 : undefined,
|
|
2122
2302
|
fromSurface: true,
|
|
2123
2303
|
captureBeyondViewport: false,
|
|
2124
2304
|
});
|
|
@@ -2126,6 +2306,12 @@ async function captureProfile(client, snapshot, profile, screenshotFileName) {
|
|
|
2126
2306
|
const profileDirectory = path.join(screenshotDirectory, profile.outputDirectory);
|
|
2127
2307
|
const screenshotPath = path.join(profileDirectory, screenshotFileName);
|
|
2128
2308
|
const screenshotBuffer = Buffer.from(screenshot.data, 'base64');
|
|
2309
|
+
validateStoreImage(
|
|
2310
|
+
profile,
|
|
2311
|
+
profile.width * profile.deviceScaleFactor,
|
|
2312
|
+
profile.height * profile.deviceScaleFactor,
|
|
2313
|
+
screenshotBuffer,
|
|
2314
|
+
);
|
|
2129
2315
|
|
|
2130
2316
|
fs.mkdirSync(profileDirectory, { recursive: true });
|
|
2131
2317
|
fs.writeFileSync(screenshotPath, screenshotBuffer, { flag: 'wx' });
|
|
@@ -2145,6 +2331,22 @@ async function captureScreenshotSet(
|
|
|
2145
2331
|
selectedProfiles,
|
|
2146
2332
|
fileNameInput,
|
|
2147
2333
|
) {
|
|
2334
|
+
const storeProfile = selectedProfiles.find((profile) => profile.storeRequirements);
|
|
2335
|
+
if (storeProfile) {
|
|
2336
|
+
const profileDirectory = path.join(screenshotDirectory, storeProfile.outputDirectory);
|
|
2337
|
+
const existingImageCount = fs.existsSync(profileDirectory)
|
|
2338
|
+
? fs.readdirSync(profileDirectory, { withFileTypes: true })
|
|
2339
|
+
.filter((entry) => entry.isFile() && /\.(png|jpe?g|webp)$/i.test(entry.name))
|
|
2340
|
+
.length
|
|
2341
|
+
: 0;
|
|
2342
|
+
|
|
2343
|
+
if (existingImageCount >= storeProfile.storeRequirements.maxImages) {
|
|
2344
|
+
throw new Error(
|
|
2345
|
+
`${storeProfile.label} already contains ${existingImageCount} images; the store allows a maximum of ${storeProfile.storeRequirements.maxImages}.`,
|
|
2346
|
+
);
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2148
2350
|
console.log('Capturing the current rendered page and resolved native data...');
|
|
2149
2351
|
const snapshot = await capturePageSnapshot(deviceClient);
|
|
2150
2352
|
const screenshotFileName = getScreenshotFileName(fileNameInput, selectedProfiles);
|
|
@@ -2213,6 +2415,148 @@ async function frameExistingScreenshots(selectedProfiles) {
|
|
|
2213
2415
|
}
|
|
2214
2416
|
}
|
|
2215
2417
|
|
|
2418
|
+
async function createVivoAssetsFromExistingScreenshots() {
|
|
2419
|
+
const vivoProfile = deviceProfiles.find((profile) => profile.name === 'vivo-store');
|
|
2420
|
+
const sourceDirectory = path.join(screenshotDirectory, 'Android');
|
|
2421
|
+
const outputDirectory = path.join(screenshotDirectory, vivoProfile.outputDirectory);
|
|
2422
|
+
const sourceFiles = fs.existsSync(sourceDirectory)
|
|
2423
|
+
? fs.readdirSync(sourceDirectory, { withFileTypes: true })
|
|
2424
|
+
.filter((entry) => entry.isFile() && /\.png$/i.test(entry.name))
|
|
2425
|
+
.map((entry) => entry.name)
|
|
2426
|
+
.sort((first, second) => first.localeCompare(second, undefined, { numeric: true }))
|
|
2427
|
+
: [];
|
|
2428
|
+
|
|
2429
|
+
if (!sourceFiles.length) {
|
|
2430
|
+
throw new Error(`No existing PNG screenshots found in ${sourceDirectory}.`);
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
const { maxImages } = vivoProfile.storeRequirements;
|
|
2434
|
+
const selectedSourceFiles = sourceFiles.slice(0, maxImages);
|
|
2435
|
+
if (sourceFiles.length > maxImages) {
|
|
2436
|
+
console.warn(
|
|
2437
|
+
`Vivo Store allows a maximum of ${maxImages} images; using the first ${maxImages} of ${sourceFiles.length} existing Android screenshots.`,
|
|
2438
|
+
);
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
let replayBrowser;
|
|
2442
|
+
let replayClient;
|
|
2443
|
+
let createdCount = 0;
|
|
2444
|
+
|
|
2445
|
+
try {
|
|
2446
|
+
replayBrowser = await launchReplayBrowser();
|
|
2447
|
+
replayClient = await createReplayPage(replayBrowser);
|
|
2448
|
+
fs.mkdirSync(outputDirectory, { recursive: true });
|
|
2449
|
+
|
|
2450
|
+
for (const screenshotFileName of selectedSourceFiles) {
|
|
2451
|
+
const sourcePath = path.join(sourceDirectory, screenshotFileName);
|
|
2452
|
+
const outputPath = path.join(outputDirectory, screenshotFileName);
|
|
2453
|
+
const sourceBuffer = fs.readFileSync(sourcePath);
|
|
2454
|
+
const vivoBuffer = await sharp(sourceBuffer)
|
|
2455
|
+
.resize(vivoProfile.width * vivoProfile.deviceScaleFactor, vivoProfile.height * vivoProfile.deviceScaleFactor, {
|
|
2456
|
+
fit: 'contain',
|
|
2457
|
+
background: '#f5f7fc',
|
|
2458
|
+
})
|
|
2459
|
+
.png()
|
|
2460
|
+
.toBuffer();
|
|
2461
|
+
|
|
2462
|
+
validateStoreImage(
|
|
2463
|
+
vivoProfile,
|
|
2464
|
+
vivoProfile.width * vivoProfile.deviceScaleFactor,
|
|
2465
|
+
vivoProfile.height * vivoProfile.deviceScaleFactor,
|
|
2466
|
+
vivoBuffer,
|
|
2467
|
+
);
|
|
2468
|
+
|
|
2469
|
+
fs.writeFileSync(outputPath, vivoBuffer);
|
|
2470
|
+
createdCount += 1;
|
|
2471
|
+
console.log(`Saved Vivo frameless screenshot: ${outputPath}`);
|
|
2472
|
+
|
|
2473
|
+
await captureFramedScreenshot(
|
|
2474
|
+
replayClient,
|
|
2475
|
+
sourceBuffer,
|
|
2476
|
+
vivoProfile,
|
|
2477
|
+
screenshotFileName,
|
|
2478
|
+
false,
|
|
2479
|
+
);
|
|
2480
|
+
}
|
|
2481
|
+
} finally {
|
|
2482
|
+
if (replayClient) replayClient.close();
|
|
2483
|
+
if (replayBrowser) await closeReplayBrowser(replayBrowser);
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
console.log(`Vivo assets created from existing screenshots: ${createdCount} frameless image(s).`);
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
async function createOppoAssetsFromExistingScreenshots() {
|
|
2490
|
+
const oppoProfile = deviceProfiles.find((profile) => profile.name === 'oppo-store');
|
|
2491
|
+
const sourceDirectory = path.join(screenshotDirectory, 'Android');
|
|
2492
|
+
const outputDirectory = path.join(screenshotDirectory, oppoProfile.outputDirectory);
|
|
2493
|
+
const sourceFiles = fs.existsSync(sourceDirectory)
|
|
2494
|
+
? fs.readdirSync(sourceDirectory, { withFileTypes: true })
|
|
2495
|
+
.filter((entry) => entry.isFile() && /\.png$/i.test(entry.name))
|
|
2496
|
+
.map((entry) => entry.name)
|
|
2497
|
+
.sort((first, second) => first.localeCompare(second, undefined, { numeric: true }))
|
|
2498
|
+
: [];
|
|
2499
|
+
|
|
2500
|
+
if (!sourceFiles.length) {
|
|
2501
|
+
throw new Error(`No existing PNG screenshots found in ${sourceDirectory}.`);
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
const { maxImages } = oppoProfile.storeRequirements;
|
|
2505
|
+
const selectedSourceFiles = sourceFiles.slice(0, maxImages);
|
|
2506
|
+
if (sourceFiles.length > maxImages) {
|
|
2507
|
+
console.warn(
|
|
2508
|
+
`Oppo Store allows a maximum of ${maxImages} images; using the first ${maxImages} of ${sourceFiles.length} existing Android screenshots.`,
|
|
2509
|
+
);
|
|
2510
|
+
}
|
|
2511
|
+
|
|
2512
|
+
let replayBrowser;
|
|
2513
|
+
let replayClient;
|
|
2514
|
+
let createdCount = 0;
|
|
2515
|
+
|
|
2516
|
+
try {
|
|
2517
|
+
replayBrowser = await launchReplayBrowser();
|
|
2518
|
+
replayClient = await createReplayPage(replayBrowser);
|
|
2519
|
+
fs.mkdirSync(outputDirectory, { recursive: true });
|
|
2520
|
+
|
|
2521
|
+
for (const sourceFileName of selectedSourceFiles) {
|
|
2522
|
+
const outputFileName = `${path.basename(sourceFileName, path.extname(sourceFileName))}.jpg`;
|
|
2523
|
+
const sourceBuffer = fs.readFileSync(path.join(sourceDirectory, sourceFileName));
|
|
2524
|
+
const oppoBuffer = await sharp(sourceBuffer)
|
|
2525
|
+
.resize(oppoProfile.width * oppoProfile.deviceScaleFactor, oppoProfile.height * oppoProfile.deviceScaleFactor, {
|
|
2526
|
+
fit: 'contain',
|
|
2527
|
+
background: '#f5f7fc',
|
|
2528
|
+
})
|
|
2529
|
+
.jpeg({ quality: 90 })
|
|
2530
|
+
.toBuffer();
|
|
2531
|
+
const outputPath = path.join(outputDirectory, outputFileName);
|
|
2532
|
+
|
|
2533
|
+
validateStoreImage(
|
|
2534
|
+
oppoProfile,
|
|
2535
|
+
oppoProfile.width * oppoProfile.deviceScaleFactor,
|
|
2536
|
+
oppoProfile.height * oppoProfile.deviceScaleFactor,
|
|
2537
|
+
oppoBuffer,
|
|
2538
|
+
);
|
|
2539
|
+
|
|
2540
|
+
fs.writeFileSync(outputPath, oppoBuffer);
|
|
2541
|
+
createdCount += 1;
|
|
2542
|
+
console.log(`Saved Oppo frameless screenshot: ${outputPath}`);
|
|
2543
|
+
|
|
2544
|
+
await captureFramedScreenshot(
|
|
2545
|
+
replayClient,
|
|
2546
|
+
sourceBuffer,
|
|
2547
|
+
oppoProfile,
|
|
2548
|
+
outputFileName,
|
|
2549
|
+
false,
|
|
2550
|
+
);
|
|
2551
|
+
}
|
|
2552
|
+
} finally {
|
|
2553
|
+
if (replayClient) replayClient.close();
|
|
2554
|
+
if (replayBrowser) await closeReplayBrowser(replayBrowser);
|
|
2555
|
+
}
|
|
2556
|
+
|
|
2557
|
+
console.log(`Oppo assets created from existing screenshots: ${createdCount} frameless image(s).`);
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2216
2560
|
async function runInteractiveCaptureLoop(
|
|
2217
2561
|
deviceClient,
|
|
2218
2562
|
replayClient,
|
|
@@ -2254,6 +2598,8 @@ async function getInteractiveOptions(options) {
|
|
|
2254
2598
|
|| options.dryRun
|
|
2255
2599
|
|| options.amazonAssets
|
|
2256
2600
|
|| options.samsungAssets
|
|
2601
|
+
|| options.vivoExisting
|
|
2602
|
+
|| options.oppoExisting
|
|
2257
2603
|
) {
|
|
2258
2604
|
return options;
|
|
2259
2605
|
}
|
|
@@ -2332,6 +2678,16 @@ async function main() {
|
|
|
2332
2678
|
return;
|
|
2333
2679
|
}
|
|
2334
2680
|
|
|
2681
|
+
if (options.vivoExisting) {
|
|
2682
|
+
await createVivoAssetsFromExistingScreenshots();
|
|
2683
|
+
return;
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
if (options.oppoExisting) {
|
|
2687
|
+
await createOppoAssetsFromExistingScreenshots();
|
|
2688
|
+
return;
|
|
2689
|
+
}
|
|
2690
|
+
|
|
2335
2691
|
if (!options.dryRun) {
|
|
2336
2692
|
await createMissingStoreAssets();
|
|
2337
2693
|
}
|