Client-side optimization pipeline with apply-to-J-ID
Backend: - POST /api/files/J-x/optimize/ applies a browser-processed file: replaces every copy (renaming when the extension changes), recomputes MD5, size and perceptual hashes, seeds guest visibility; 400 when identical, 409 when the result matches another item, owner/staff only. Frontend (no server-side processing by design): - optimize.worker.ts + pipelines: Mediabunny/WebCodecs for video with a prefer-hardware hint and per-browser codec detection; MozJPEG/OxiPNG/ libwebp (jSquash) for images; gifuct-js+gifenc and UPNG for GIF/APNG. - OptimizeModal: per-file-type options, original vs processed previews with sizes/savings, progress bar with ETA, then Apply (overwrite). - Optimize button on the library detail for the uploader/staff.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
import { canEncodeVideo, getEncodableVideoCodecs, type VideoCodec } from "mediabunny";
|
||||
|
||||
export interface VideoCodecSupport {
|
||||
codec: VideoCodec;
|
||||
supported: boolean;
|
||||
hardware: boolean;
|
||||
}
|
||||
|
||||
const VIDEO_CODEC_CANDIDATES: VideoCodec[] = ["avc", "hevc", "vp9", "av1"];
|
||||
|
||||
/** Which codecs this browser can encode, and whether hardware is preferred. */
|
||||
export async function detectVideoCodecs(): Promise<VideoCodecSupport[]> {
|
||||
const supported = new Set(await getEncodableVideoCodecs());
|
||||
const results: VideoCodecSupport[] = [];
|
||||
for (const codec of VIDEO_CODEC_CANDIDATES) {
|
||||
const encodable = supported.has(codec);
|
||||
let hardware = false;
|
||||
if (encodable) {
|
||||
try {
|
||||
hardware = await canEncodeVideo(codec, {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
hardwareAcceleration: "prefer-hardware",
|
||||
});
|
||||
} catch {
|
||||
hardware = false;
|
||||
}
|
||||
}
|
||||
results.push({ codec, supported: encodable, hardware });
|
||||
}
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user