play images: tablet, TV and Wear sets are optional; play.tablets switch (default: tablet renders exist); a missing optional set never deletes Play's images without --prune

A phone-only project aborted with 'no sevenInchScreenshots'. Play requires the 512 icon, the 1024x500 feature graphic and at least 2 screenshots (Play Console Help answer 9866151). play images uploads what exists and prints an info line for missing optional sets; play.tablets true makes missing tablet sets an error in shots render/check/gallery, validate and play images. Pitfall 19.
This commit is contained in:
CRTkafa 2026-10-12 08:21:03 +08:00
parent 18fde37b9b
commit a9261a8052
18 changed files with 364 additions and 83 deletions

View file

@ -23,8 +23,9 @@ import { checkUrl } from './lib/http';
import { collectHealth } from './health';
import { healthFindings } from './lib/health';
import { log, printJson, warn } from './lib/log';
import { type AppleSnapshot, appleRules, type Finding, formatFindings, PLAY_REQUIRED_IMAGES, type PlaySnapshot, playRules, type ProfileFacts, rendersFindings, sortFindings } from './lib/validate-rules';
import { type AppleSnapshot, appleRules, type Finding, formatFindings, type PlaySnapshot, playRequiredImages, playRules, type ProfileFacts, rendersFindings, sortFindings } from './lib/validate-rules';
import { rendersCheck } from './shots/check';
import { resolvedTablets } from './shots/report';
import { runScan } from './lib/scan';
import type { ScanFinding } from './lib/scan/rules';
import { playClient } from './play/client';
@ -115,6 +116,7 @@ export async function collectApple(ctx: Ctx): Promise<AppleSnapshot> {
export async function collectPlay(ctx: Ctx): Promise<PlaySnapshot> {
const { config, root } = ctx.loaded;
const play = await playClient(root, config.play!.packageName);
const tablets = resolvedTablets(config, ctx.loaded.resolve(ctx.args.get('src') ?? config.renders ?? config.shots?.out ?? 'store/renders'));
const e = await play.call<{ id: string }>('POST', `${play.API}/edits`, {});
log('validate', `play: read-only edit ${e.id} (deleted afterwards)`);
try {
@ -123,7 +125,7 @@ export async function collectPlay(ctx: Ctx): Promise<PlaySnapshot> {
const listings: PlaySnapshot['listings'] = [];
for (const l of raw) {
const images: Record<string, number> = {};
for (const type of Object.keys(PLAY_REQUIRED_IMAGES))
for (const type of Object.keys(playRequiredImages(tablets)))
images[type] = ((await play.call<{ images?: unknown[] }>('GET', `${play.API}/edits/${e.id}/listings/${l.language}/${type}`)).images ?? []).length;
listings.push({ ...l, images });
}
@ -148,7 +150,7 @@ export async function collectPlay(ctx: Ctx): Promise<PlaySnapshot> {
} while (page);
}
return {
subscriptions, expectedSubscriptions: wantSubs.map(({ sub }) => ({ id: sub.id, basePlanId: basePlanId(sub) })),
tablets, subscriptions, expectedSubscriptions: wantSubs.map(({ sub }) => ({ id: sub.id, basePlanId: basePlanId(sub) })),
profile: await collectProfile(ctx.loaded),
defaultLanguage: details.defaultLanguage ?? config.play?.defaultLanguage ?? 'en-US',
expectedLanguages: config.languages.flatMap(playCodes), listings, tracks, products,