fix(downloads): GIF review round 1 — shape, HDR, caps, audio, copy

- A GIF squares its pixels before the size, so an anamorphic source keeps
  its shown shape (a 720x480 DVD at 16:9 was 480x320).
- An editor GIF of an HDR upload is tonemapped, as a clip GIF is.
- The length caps are judged in whole milliseconds: a range exactly at a
  cap is no longer refused for a float hair over it.
- A GIF is made of a video only: an audio file is refused with its reason
  and the editor offers no GIF for it.
- A GIF clip keeps no audio track: the track neither splits its cache key
  nor fails it.
- The editor's GIF notes keep their live region mounted; one size reads
  as one ("about 1 MB"), none is shown with nothing kept; the size choices
  show their unit; a shared picture that fails to load says so.
- Copy: the two-sentence GIF notes keep their last stop (a copy-rule test
  now holds it); the English warns of "only a still picture".
This commit is contained in:
2026-11-12 23:24:25 +01:00
parent 0b92b40db5
commit 8845d1aa49
23 changed files with 403 additions and 78 deletions
+7
View File
@@ -39,6 +39,13 @@ describe("the copy rule", () => {
expect(offenders((v) => v.includes("✓"))).toEqual([]);
});
it("keeps the stops of a message of two sentences, the last one too", () => {
// A sentence break: a stop, a space, then a capital ("kb. {{n}}" is an abbreviation, not one). A
// value ending in a space is the head of a sentence a link or a number completes on screen.
const twoSentences = (v: string) => /[.!?] \p{Lu}/u.test(v) && !v.endsWith(" ");
expect(offenders((v) => twoSentences(v) && !/[.!?…]["”)]?$/u.test(v))).toEqual([]);
});
it("spells no unit as a bare letter after a number ('90m', '24h', '{{count}}d', '10 s')", () => {
expect(offenders((v) => /(\d|\}\})\s?(m|h|d|s)(?![\p{L}\d/])/u.test(v))).toEqual([]);
});