diff --git a/src/components/PresetSelector.tsx b/src/components/PresetSelector.tsx
index 052a3698..e43637eb 100644
--- a/src/components/PresetSelector.tsx
+++ b/src/components/PresetSelector.tsx
@@ -285,7 +285,7 @@ export default function PresetSelector({ recipe, onChange }: Props) {
step={2}
value={recipe.customWidth}
onChange={(e) => handleWidthChange(Number(e.target.value))}
- className="w-full rounded-md border border-[var(--border)] bg-[var(--bg)] px-3 py-2 text-sm font-heading transition-all focus:outline-none focus:ring-2 focus:ring-film-400"
+ className="w-full rounded-md border border-[var(--border)] bg-[var(--bg)] px-3 py-2 text-sm font-heading transition-all focus:outline-none focus:ring-2 focus:ring-film-400 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
/>
@@ -310,7 +310,7 @@ export default function PresetSelector({ recipe, onChange }: Props) {
step={2}
value={recipe.customHeight}
onChange={(e) => handleHeightChange(Number(e.target.value))}
- className="w-full rounded-md border border-[var(--border)] bg-[var(--bg)] px-3 py-2 text-sm font-heading transition-all focus:outline-none focus:ring-2 focus:ring-film-400"
+ className="w-full rounded-md border border-[var(--border)] bg-[var(--bg)] px-3 py-2 text-sm font-heading transition-all focus:outline-none focus:ring-2 focus:ring-film-400 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none"
/>
diff --git a/src/components/TrimControl.tsx b/src/components/TrimControl.tsx
index a4a03d19..fa5cb170 100644
--- a/src/components/TrimControl.tsx
+++ b/src/components/TrimControl.tsx
@@ -109,7 +109,7 @@ export default function TrimControl({ recipe, onChange, duration }: Props) {
};
const inputClass =
- "w-full text-sm px-3 py-2 border border-[var(--border)] rounded-md bg-[var(--bg)] font-heading focus:outline-none focus:ring-2 focus:ring-film-400 text-[var(--text)] transition-shadow";
+ "w-full text-sm px-3 py-2 border border-[var(--border)] rounded-md bg-[var(--bg)] font-heading focus:outline-none focus:ring-2 focus:ring-film-400 text-[var(--text)] transition-shadow [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none";
return (
diff --git a/src/lib/tests/ffmpeg.test.ts b/src/lib/tests/ffmpeg.test.ts
index bdde5d41..c2e42e74 100644
--- a/src/lib/tests/ffmpeg.test.ts
+++ b/src/lib/tests/ffmpeg.test.ts
@@ -3,15 +3,15 @@ import { buildAudioFilter } from "../ffmpeg";
describe("buildAudioFilter", () => {
it("should return an empty string for 1.0x speed", () => {
- expect(buildAudioFilter(1)).toBe("");
+ expect(buildAudioFilter(1, false)).toBe("");
});
it("should chain two 0.5x filters for 0.25x speed", () => {
- expect(buildAudioFilter(0.25)).toBe("atempo=0.5,atempo=0.5");
+ expect(buildAudioFilter(0.25, false)).toBe("atempo=0.5,atempo=0.5");
});
it("should chain two 2.0x filters for 4.0x speed", () => {
- expect(buildAudioFilter(4)).toBe("atempo=2.0,atempo=2");
+ expect(buildAudioFilter(4, false)).toBe("atempo=2.0,atempo=2");
});
it("should chain multiple 0.5x filters and a remainder for 0.1x speed", () => {
@@ -19,25 +19,30 @@ describe("buildAudioFilter", () => {
// 0.2 / 0.5 = 0.4
// 0.4 / 0.5 = 0.8
// Result should be three 0.5s and one 0.8
- expect(buildAudioFilter(0.1)).toBe("atempo=0.5,atempo=0.5,atempo=0.5,atempo=0.8");
+ expect(buildAudioFilter(0.1, false)).toBe("atempo=0.5,atempo=0.5,atempo=0.5,atempo=0.8");
});
it("should chain multiple 2.0x filters and a remainder for 3.0x speed", () => {
// 3.0 / 2.0 = 1.5
- expect(buildAudioFilter(3)).toBe("atempo=2.0,atempo=1.5");
+ expect(buildAudioFilter(3, false)).toBe("atempo=2.0,atempo=1.5");
});
it("should handle boundary values inside the 0.5x-2.0x range without chaining", () => {
- expect(buildAudioFilter(0.5)).toBe("atempo=0.5");
- expect(buildAudioFilter(2.0)).toBe("atempo=2"); // Note: Number(2.0.toFixed(4)) -> 2
- expect(buildAudioFilter(1.5)).toBe("atempo=1.5");
- expect(buildAudioFilter(0.75)).toBe("atempo=0.75");
+ expect(buildAudioFilter(0.5, false)).toBe("atempo=0.5");
+ expect(buildAudioFilter(2.0, false)).toBe("atempo=2"); // Note: Number(2.0.toFixed(4)) -> 2
+ expect(buildAudioFilter(1.5, false)).toBe("atempo=1.5");
+ expect(buildAudioFilter(0.75, false)).toBe("atempo=0.75");
});
it("should chain properly for very large speeds", () => {
// 10 / 2.0 = 5
// 5 / 2.0 = 2.5
// 2.5 / 2.0 = 1.25
- expect(buildAudioFilter(10)).toBe("atempo=2.0,atempo=2.0,atempo=2.0,atempo=1.25");
+ expect(buildAudioFilter(10, false)).toBe("atempo=2.0,atempo=2.0,atempo=2.0,atempo=1.25");
+ });
+
+ it("should append loudnorm filter when normalizeAudio is true", () => {
+ const result = buildAudioFilter(1, true);
+ expect(result).toContain("loudnorm");
});
});