play: a new language is created with everything Play needs to commit it (icon, feature graphic, phone and tablet screenshots); play images creates a missing listing
This commit is contained in:
parent
2ec1f0ab13
commit
ed8d138a8e
7 changed files with 172 additions and 32 deletions
|
|
@ -20,7 +20,7 @@ import type { Ctx } from '../lib/ctx';
|
|||
import { confirm, need } from '../lib/ctx';
|
||||
import { done, log, printJson, step, warn } from '../lib/log';
|
||||
import { playClient } from './client';
|
||||
import { firstGraphics } from './images';
|
||||
import { newLanguageImages, type NewLangImages } from './images';
|
||||
import { stdinIsTTY } from '../lib/tty';
|
||||
|
||||
/** Play release notes that name iOS, iPhone, App Store, ... are refused before any edit, dry runs included (pitfall 77). */
|
||||
|
|
@ -140,12 +140,40 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
if (!a.has('json')) log('play', `${copy.length} listings: ${copy.map(c => c.lang).join(', ')}${config.play?.video ? ` · promo video ${config.play.video}` : ''}`);
|
||||
const play = await playClient(root, pkg);
|
||||
const bodies = copy.map(c => listingBody(c, config.play?.video));
|
||||
// A language Play does not have yet only commits with its icon, feature graphic, 2+ phone screenshots (and the
|
||||
// tablet sets when the other languages have them) in the same edit: planned here so the dry run refuses early.
|
||||
const fresh = new Map<string, NewLangImages>();
|
||||
const planFresh = async (id: string, now: PlayListing[]) => {
|
||||
const missing = bodies.filter(b => !now.some(n => n.language === b.language)).map(b => b.language!);
|
||||
if (!missing.length) return;
|
||||
const ref = now.find(n => n.language === details.defaultLanguage) ?? now[0];
|
||||
let tabletsOnPlay = false;
|
||||
if (ref) for (const t of ['sevenInchScreenshots', 'tenInchScreenshots']) {
|
||||
try { tabletsOnPlay ||= !!((await play.call<{ images?: unknown[] }>('GET', `${play.API}/edits/${id}/listings/${ref.language}/${t}`)).images?.length); } catch { /* no tablet set */ }
|
||||
}
|
||||
for (const code of missing) {
|
||||
const f = newLanguageImages(ctx, code, details.defaultLanguage, tabletsOnPlay);
|
||||
// the very first listing of an app: Play checks the images at release, not at this commit, so only a warning
|
||||
if (!now.length && f.errors.length) { f.notes.push(...f.errors.map(e => `warning: ${e}`)); f.errors = []; }
|
||||
fresh.set(code, f);
|
||||
}
|
||||
};
|
||||
const p = await play.read(async id => {
|
||||
const cur = await play.call<Record<string, string>>('GET', `${play.API}/edits/${id}/details`);
|
||||
const now = (await play.call<{ listings?: PlayListing[] }>('GET', `${play.API}/edits/${id}/listings`)).listings ?? [];
|
||||
await planFresh(id, now);
|
||||
return playPlan(cur, details, now, bodies, { skipped, notes, only: a.has('only') });
|
||||
});
|
||||
for (const f of fresh.values()) {
|
||||
p.notes.push(...f.notes);
|
||||
if (!f.errors.length) p.notes.push(`${f.code} is new on Play: uploads ${f.uploads.map(([t, fl]) => `${t} (${fl.length})`).join(', ')} in the same edit`);
|
||||
}
|
||||
const dry = a.has('dry');
|
||||
const refuse = [...fresh.values()].flatMap(f => f.errors);
|
||||
if (refuse.length) {
|
||||
if (a.has('json')) printJson({ dry, ...p, errors: refuse }); else for (const line of playPlanLines(p)) console.log(line);
|
||||
throw new Error(['a new Play language needs its images in the same edit:', ...refuse].join('\n'));
|
||||
}
|
||||
if (a.has('json')) printJson({ dry, ...p });
|
||||
else for (const line of playPlanLines(p)) console.log(line);
|
||||
if (dry) { done('play', `dry run: ${p.changes ? `${p.changes} change(s)` : 'nothing to change'}; read-only, nothing written`); return; }
|
||||
|
|
@ -168,13 +196,11 @@ export async function run(ctx: Ctx): Promise<void> {
|
|||
for (const [i, b] of todo.entries()) {
|
||||
await play.call('PUT', `${play.API}/edits/${id}/listings/${b.language}`, b);
|
||||
log('play', step(i + 1, todo.length, b.language!));
|
||||
// a language Play does not have yet: its edit only commits with a hi-res icon (pitfall 102)
|
||||
// a language Play does not have yet: its edit only commits with its images in it (pitfall 102)
|
||||
if (!now.some(n => n.language === b.language)) {
|
||||
const graphics = firstGraphics(ctx, b.language!);
|
||||
if (!graphics.some(([t]) => t === 'icon')) warn('play', `${b.language}: no 512x512 icon to send with this new language (play.icon or store/icons/play-512.png; storebound icons makes it): Play may refuse the commit with 403 "no high resolution icon"`);
|
||||
for (const [type, f] of graphics) {
|
||||
await play.call('POST', `${play.UPLOAD}/edits/${id}/listings/${b.language}/${type}?uploadType=media`, new Uint8Array(readFileSync(f)), { 'Content-Type': /\.png$/i.test(f) ? 'image/png' : 'image/jpeg' });
|
||||
log('play', `${b.language}: ${type} uploaded with the new listing`);
|
||||
for (const [type, files] of fresh.get(b.language!)?.uploads ?? []) {
|
||||
for (const f of files) await play.call('POST', `${play.UPLOAD}/edits/${id}/listings/${b.language}/${type}?uploadType=media`, new Uint8Array(readFileSync(f)), { 'Content-Type': /.png$/i.test(f) ? 'image/png' : 'image/jpeg' });
|
||||
log('play', `${b.language}: ${type} (${files.length}) uploaded with the new listing`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue