Spaces:
Running
Running
Commit History
-
feat(text): thêm tab "Chèn chữ vào video" (nhiều video) + nhận dạng lời (ASR)
- Tab mới /chen-chu: vào 1..N video, chèn chữ hard-sub, ra N video tương ứng. - Dùng lại SubtitleEditor (đủ phông/màu/11 kiểu nền/3 kiểu hiển thị/kéo thả) qua props tùy chọn initialSegs/initialMode/onChange/headerExtra/onFetchLines (mặc định null -> tab Dịch/đổi giọng không đổi). - Lấy text: nút "Tự lấy lời từ video (nhận dạng)" -> ASR Whisper (Groq) không dịch, đổ lời + mốc vào editor để sửa; hoặc gõ tay. - Áp form giữa các video: "Áp cả lời + kiểu" (cùng nội dung) và "Áp kiểu (giữ lời riêng)" (mỗi video tự nhận dạng lời khác nhau). - Backend: endpoint /api/dub/subtitle/transcribe (extract_tracks + asr, nhẹ); burn + preview-frame ra thư mục RIÊNG theo từng video (hash) -> burn nhiều video 1 phiên không đè nhau. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>788bc93
-
feat(sub): thêm 7 phông chữ phụ đề (Oswald, Nunito, Lato, Merriweather, Playfair, Kanit, Dancing Script)
Phông mã nguồn mở (Google Fonts, OFL), đã kiểm cmap phủ ĐỦ dấu tiếng Việt. Variable font -> instance về 1 weight tĩnh bằng fontTools + đặt tên family sạch (như bộ cũ là 1 face khai báo normal). Nhúng Git LFS + @font-face; Dockerfile tự cp *.ttf. Đo hệ số co k (libass/CSS, nhất quán <1% qua 3 chuỗi) cho từng phông để preview KHỚP burn: Oswald .587, Nunito .724, Lato .714, Merriweather .577, Playfair Display .705, Kanit .630, Dancing Script .710. Đã verify overlay Oswald + Dancing Script khớp cỡ/ giãn dòng/vị trí, dấu tiếng Việt hiện đủ. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>9206420 -
style(sub): thu nhỏ 4 tay kéo cạnh ô phụ đề cho gọn (12x22 -> 6x13, viền 1px)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>0b41d4a -
feat(sub): loé nền nút "về giữa‑đáy / áp style / áp vị trí" khi bấm
Ba nút hành động tức thì trước đây bấm xong không đổi gì trên nút -> user không biết đã áp chưa. Thêm doFlash: loé nhẹ nền cam ~0.6s (dùng transition sẵn của .btn) để báo "đã nhấn". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>2621912 -
fix(fe): render lần 2 hiện video đen — cache-bust <video> khi ghi đè cùng tên file
Render/burn/xào LẠI ghi đè output cùng tên -> URL không đổi -> React tái dùng <video> + trình duyệt giữ bytes đã cache/đã decode của lần trước -> khung ĐEN. Tải về vẫn đúng vì là request mới. Sửa: gắn mốc thời gian (outStamp/resStamp/_v) vào src <video> (?v=...) + đổi key để remount mỗi lần render. Áp cho DubVideo (dịch/đổi giọng), SubtitleEditor (chèn phụ đề), ShuffleVideo (xào). Link tải giữ nguyên (đã đúng). videoRel/srtRel truyền sang trình sửa phụ đề không kèm query. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>9f6c247 -
feat(sub+shuffle): tay kéo giãn ô phụ đề + giữ/tắt tiếng gốc khi xào
Phụ đề: thêm 4 tay kéo cạnh cho ô đang chọn — trái/phải đổi BỀ RỘNG vùng (w), trên/dưới GIÃN cỡ chữ (fontSize theo khoảng cách con trỏ tới tâm ô, con trỏ bám cạnh). Bỏ tay kéo góc cũ. Xào video: thêm tùy chọn "Giữ âm thanh gốc" (mặc định BẬT) — ghép nối tiếng gốc các khúc theo đúng thứ tự xào; nếu có lồng track thì TRỘN track lên tiếng gốc. Tắt -> video câm (như cũ) / chỉ còn track. Mô hình theo tool video_cook: - normalize_clip(with_audio): giữ tiếng gốc (aac 44100 stereo), clip câm chèn im lặng để concat copy đồng nhất; cache key riêng theo chế độ audio. - attach_audio(keep_original): amix track lên tiếng gốc (normalize=0) thay vì thay hẳn. Đã verify render thật: giữ/tắt/trộn đều đúng, tiếng gốc đúng vị trí từng khúc. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>ad3a570 -
fix(sub): CSS xem trước KHỚP burn - hệ số co cỡ chữ + giãn dòng đo thực nghiệm
Nguyên nhân: libass vẽ Fontsize=F ra cỡ pixel nhỏ hơn CSS font-size=F. Đo render_frame(libass) vs canvas trình duyệt -> hệ số co K cố định mỗi font (BVP .655, Roboto .829, OpenSans .692, Montserrat .641, Arimo .694, Tinos .905). Khoảng cách dòng libass = 1.0*fsize mọi font. - FE: cỡ chữ preview = fontSize*k*scale; lineHeight = 1/k; measureBreaks đo ở fontSize*k; padding/bo góc hộp quy theo fpx; lề ngang 1.5% khớp measureBreaks. - BE: box_h = n*fsize + 2*pad (bỏ *1.25*K sai) -> hộp ôm sát chữ, khớp hộp CSS. Kiểm chứng overlay CSS đè khung burn thật: cỡ/bề rộng/ngắt dòng/giãn dòng/hộp khớp cho cả font mặc định lẫn font lệch nhất. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>0ce96ff -
fix(sub): không bao giờ trống chữ - luôn hiện CSS nền, ảnh chuẩn đè lên
Bug: khi DỪNG mà ảnh chuẩn (server) chưa về/lỗi thì ẩn luôn chữ CSS -> phụ đề biến mất (chỉ còn khung chọn). Sửa: CHỈ ẩn CSS khi ảnh chuẩn ĐÃ hiện (showExact = idle && previewImg). Còn lại (đang chờ ảnh / lỗi / đang phát / gõ / kéo) luôn hiện CSS làm nền -> không bao giờ trống. Ảnh chuẩn về thì đè lên. - <img> lỗi tải -> tự lùi về CSS (onError) thay vì trống. - Dòng trạng thái phân biệt rõ: đang dựng / đã khớp / lỗi / đang phát. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>1b53507 -
fix(sub): lúc phát ẩn phụ đề gần-đúng + render khung chuẩn nhanh 3x
Gốc hiểu lầm: đang PHÁT vẫn hiện phụ đề CSS gần-đúng nên trông khác bản burn. - FE: chỉ hiện CSS khi TẮT exact (xem nhanh) hoặc đang gõ/kéo. Bật exact + đang phát -> KHÔNG hiện phụ đề (tránh nhầm); DỪNG mới hiện phụ đề CHUẨN (=burn). - Hiện lỗi rõ nếu server render khung thất bại ("Lỗi dựng khung chuẩn"). - render_frame: seek ĐẦU VÀO + -copyts (nhanh gấp ~3: 0.22s vs 0.62s, ảnh trùng khít) -> server yếu vẫn mượt. Debounce 200ms; render ngay khi có metadata. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>6547b89 -
fix(sub): preview khớp 100% burn bằng render server (bỏ libass-wasm)
libass-wasm và ffmpeg dùng 2 BẢN libass khác phiên bản -> render KHÁC nhau (chữ bị rớt do bug fallback libass #460, khác font-hinting...). Không thể đảm bảo giống hệt bằng bộ vẽ thứ 2 trong trình duyệt. Cách chắc chắn = dùng CHÍNH ffmpeg/libass của bản burn để xem trước: - Bỏ hẳn libass-wasm (gỡ package + public/libass + endpoint /subtitle/ass). - Khi BẬT "Xem trước khớp 100%" + video TẠM DỪNG + không gõ/kéo -> tự gọi /subtitle/preview-frame render đúng khung tại thời điểm hiện tại (server ffmpeg) rồi đè ảnh lên video. Ảnh này = ĐÚNG video sẽ xuất. - Đang phát/gõ/kéo -> hiện CSS nhanh (mượt); dừng lại tự cập nhật khung chuẩn (debounce 350ms, chống race bằng frameSeq). - Giữ fix cỡ video = nội dung thật (bỏ letterbox) để ảnh đè khớp vùng video. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>4f9859d -
feat(sub): xem trước phụ đề KHỚP 100% bản burn (libass-wasm + render khung server)
Preview CSS chỉ 'bắt chước' libass -> không bao giờ giống hệt. Nay preview dùng CHÍNH libass, cùng ASS + font như bản burn: - Backend: tách build_ass_str (1 nguồn ASS cho burn/preview), thêm render_frame (render đúng 1 khung), 2 endpoint: /subtitle/ass (ASS cho libass-wasm), /subtitle/preview-frame (ảnh khớp 100% để đối chiếu). - FE (A) libass-wasm (SubtitlesOctopus): vẽ phụ đề THẬT đè video, real-time; nạp ASS từ backend (debounce), font từ /fonts. Toggle "Xem trước khớp 100%"; lỗi -> tự lùi về CSS. Ẩn lớp CSS khi libass bật (tránh chồng đôi); ẩn canvas khi đang gõ. - FE (B) nút "Xem trước chuẩn (ảnh)" -> gọi render 1 khung server. - Sửa lệch hình học gốc: cỡ hiển thị video = nội dung THẬT (bỏ letterbox ngang) nên overlay ánh xạ đúng toạ độ video (trước tính theo khung thẻ kèm viền đen). - worker/wasm libass để LFS (khớp *.wasm), HF chấp nhận. Đã kiểm: build FE pass; backend build_ass_str/render_frame ra ASS+khung đúng (highlight đúng thời điểm); libass-wasm nạp worker+was…d908e31
-
fix(sub): nhúng font mã nguồn mở -> burn phụ đề KHỚP preview trên server
Server Linux không có font Microsoft nên libass fallback -> chữ lệch bản xem trước (Windows dev khớp vì có sẵn font MS = bẫy). Nhúng 6 font OSS đủ tiếng Việt (Be Vietnam Pro, Roboto, Open Sans, Montserrat, Arimo~Arial, Tinos~Times) vào backend/app/assets/fonts; trình duyệt nạp CHÍNH file này qua @font-face(/fonts) nên preview=render mọi máy. - FONTS/measureBreaks(bỏ bold)/boxStyle(fontWeight 400) đồng bộ tên+độ rộng - ASS Bold=0 (font đã đậm sẵn, tránh làm-đậm-giả lệch metric) - burn() dùng fontsdir tương đối (né dấu ":" ổ đĩa Windows làm hỏng filter ffmpeg) - main.py mount /fonts, vite proxy /fonts cho dev - Dockerfile cài fontconfig + copy font hệ thống + fc-cache Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>d4a04dd
-
feat(sub): nút "Áp vị trí cho mọi đoạn" trong trình sửa phụ đề
Chọn 1 đoạn, kéo tới vị trí mong muốn rồi bấm nút này để chép x/y và bề rộng vùng sang tất cả các đoạn còn lại, giữ nguyên font/màu/nền riêng của từng đoạn. Bổ trợ cho "Áp style cho mọi đoạn" (nút cũ cố ý giữ nguyên vị trí riêng của mỗi đoạn). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>00151ba
-
perf: queue theo loại + code-split FE + streaming upload cho nhiều user
Backend: - Viết lại JobManager thành hàng đợi theo loại tác vụ (heavy/io), có vị trí hàng đợi (queue_pos/total) và tự dọn job cũ để không rò rỉ RAM. Cấu hình qua env JOB_HEAVY_WORKERS/JOB_IO_WORKERS/JOB_HISTORY_MAX. - core/bg.py: pool nền có giới hạn (BG_WORKERS) thay raw thread không giới hạn ở listing/listing_free/flux2. - Đưa OpenAI blocking ra khỏi event loop (listing analyze/create_session, listing_free analyze/auto-generate: async def -> def). - Streaming upload (save_upload_stream) thay vì đọc cả file vào RAM; enforce MAX_UPLOAD_MB. Áp cho dub/cut/shuffle. - Cache: Demucs model, ffprobe theo (path,mtime), client Groq. - thumbnail_strip gộp 40 lần ffmpeg -> 1 pass (fallback chậm khi lỗi). - Endpoint GET /api/queue/stats. Frontend: - Sửa bug double <Outlet> trong Layout (mọi trang mount 2 lần -> chạy đôi upload/poll/API). - Code-split các page bằng React.lazy + Suspense; tách react-vendor chunk. - pollJob nhận AbortSignal; hủy poll khi rời trang (chống rò rỉ setTimeou…3370310
-
update add subtitle
c55989f