A live photo's default names fit, and no cut name starts with a dot
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
`defaultFileName` in `src/filename.ts` now gives the name a file is saved under when the caller gives no path, and `originalName`, `thumbnailName`, `downloadFile` and `downloadThumbnail` all call it. For a live photo's image and video it puts the part's own extension in before cutting the name short, so those names fit too; a path from `--out` or `outPath` is kept as given. `shortenKeepingExtension` keeps the first character before the extension, cutting a long extension short to leave room for it, so a cut name no longer starts with a dot. The backup's links for such a title change to match. TODO.md names the open bug and describes what the code does. Model: opus-5-5
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
defaultFileName,
|
||||
safeExtension,
|
||||
sanitizeFileName,
|
||||
shortenKeepingExtension,
|
||||
@@ -141,9 +142,17 @@ describe("shortenKeepingExtension", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("cuts the extension short when it alone does not fit", () => {
|
||||
// A name cut down to its extension would start with a dot, and so be
|
||||
// hidden.
|
||||
it("keeps the first character before the extension, cutting the extension short to leave room for it", () => {
|
||||
expect(shortenKeepingExtension(`b.${"e".repeat(300)}`, 255)).toBe(
|
||||
`.${"e".repeat(254)}`,
|
||||
`b.${"e".repeat(253)}`,
|
||||
);
|
||||
expect(shortenKeepingExtension(`ab.${"e".repeat(300)}`, 255)).toBe(
|
||||
`a.${"e".repeat(253)}`,
|
||||
);
|
||||
expect(shortenKeepingExtension(`é.${"e".repeat(300)}`, 255)).toBe(
|
||||
`é.${"e".repeat(252)}`,
|
||||
);
|
||||
// "€" takes three bytes, so the extension is cut to 253 and the
|
||||
// part before it keeps the two bytes left over, for the "a".
|
||||
@@ -161,6 +170,50 @@ describe("shortenKeepingExtension", () => {
|
||||
).toBe(`${"t".repeat(247)} (7).jpg`);
|
||||
expect(
|
||||
shortenKeepingExtension(`b.${"e".repeat(300)}`, 255, " (7)"),
|
||||
).toBe(` (7).${"e".repeat(250)}`);
|
||||
).toBe(`b (7).${"e".repeat(249)}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("defaultFileName", () => {
|
||||
it("is the title when it is safe and fits", () => {
|
||||
expect(defaultFileName("IMG_0001.HEIC", 42)).toBe("IMG_0001.HEIC");
|
||||
});
|
||||
|
||||
it("replaces unsafe characters, and is file-<id> for an empty title", () => {
|
||||
expect(defaultFileName("../x.jpg", 42)).toBe("__x.jpg");
|
||||
expect(defaultFileName("", 42)).toBe("file-42");
|
||||
});
|
||||
|
||||
it("cuts a title over 255 bytes short, keeping its extension", () => {
|
||||
expect(defaultFileName(`${"t".repeat(296)}.jpg`, 42)).toBe(
|
||||
`${"t".repeat(251)}.jpg`,
|
||||
);
|
||||
expect(defaultFileName(`b.${"e".repeat(300)}`, 42)).toBe(
|
||||
`b.${"e".repeat(253)}`,
|
||||
);
|
||||
});
|
||||
|
||||
it("puts `prefix` before the title and leaves room for it", () => {
|
||||
expect(defaultFileName("beach.jpg", 42, { prefix: "thumb_" })).toBe(
|
||||
"thumb_beach.jpg",
|
||||
);
|
||||
expect(
|
||||
defaultFileName(`${"t".repeat(296)}.jpg`, 42, { prefix: "thumb_" }),
|
||||
).toBe(`thumb_${"t".repeat(245)}.jpg`);
|
||||
});
|
||||
|
||||
// A live photo's image and video are each named with their own
|
||||
// extension, and the name is cut short once that extension is in it.
|
||||
it("puts `ext` in place of the title's extension before cutting the name short", () => {
|
||||
expect(defaultFileName("IMG_0001.HEIC", 42, { ext: ".mov" })).toBe(
|
||||
"IMG_0001.mov",
|
||||
);
|
||||
expect(defaultFileName("", 42, { ext: ".mov" })).toBe("file-42.mov");
|
||||
expect(
|
||||
defaultFileName(`${"t".repeat(251)}.jpg`, 42, { ext: ".heic" }),
|
||||
).toBe(`${"t".repeat(250)}.heic`);
|
||||
expect(defaultFileName("t".repeat(300), 42, { ext: ".heic" })).toBe(
|
||||
`${"t".repeat(250)}.heic`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user