중복 탐지
- 이미지 근접쌍 밴드 색인 + 스트리밍 클러스터, 후보 검증(타일 다수결·크롭 해시)
- 색 지문으로 색만 다른 오탐 제거, 회전·반전본 탐지(8변형 질의, 선택 옵션)
- 오디오 지문(chromaprint)을 같은 디코드 패스에서 뽑아 레터박스 사본을 잡는다.
배경음만 같은 남남은 시각 확인 패스(트림 축 프레임 거리)로 걸러낸다 — 실측 9 vs 29.
- 비교 재생(CompareView): 여러 사본을 offset 정렬해 나란히 재생
- 지문 생성 속도 조절(느림·보통·빠름) — 재시작 없이 반영
간단 편집 (원본을 직접 고침, Ctrl+Z로 되돌림)
- 회전·반전: JPEG은 EXIF 방향 태그 2바이트만, MP4는 회전 행렬만 — 화질 손실 0.
방향값 전이표는 군의 성질(90도x4=제자리)로 검산하고, 실제 화소를 transpose=1과
비교해 "시계 방향"이 정말 시계인지 확인한다.
- 자르기: 화면 좌표 기준(회전 메타가 붙어 있어도 어긋나지 않는다)
- 구간 자르기: 스트림 복사라 무손실. 필름스트립 타임라인 + 손잡이 끌기 + 구간 미리보기.
- 되돌릴 수 없는 편집(자르기·반전)은 원본을 .archive_trash/edits로 옮겨 보관
- 편집이 수정시각을 바꾸지 않는다 — 기본 정렬이 촬영일이라 항목이 튀면 다시 찾아야 한다
동시 재생
- 고른 영상을 최대 9개 격자에 놓고 함께 재생. 소리는 한 칸만.
- 실시간 변환이 필요한 코덱은 2개까지만 — 그 이상은 ffmpeg가 기계를 멈춘다
그 외
- 별점(스냅샷 flags 남는 비트에 얹어 항목당 바이트 증가 0)
- 태그: 검색 없이 클릭으로 붙이기, 세트+단축키, 이름 수정 시 붙은 항목에 전파
- 파일 로깅(tracing-appender) — 릴리스는 콘솔이 없어 stdout만으로는 원인을 못 찾았다
- ARM64 크로스 컴파일 스크립트(관리자 권한 없이 VS 카탈로그에서 조립)
- DB 마이그레이션 v7~v10
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
기존엔 중복 탐지 진행이 전체화면 패널 안에서만 보였고, 패널을 닫으면
진행 상황을 알 수 없었다.
- 중복 탐지 실행/진행 상태를 store로 이관(runDedupe/dedupeRunning/dedupeProgress)
→ 패널 열림 여부와 무관하게 유지.
- DedupePanel은 store 상태를 사용(로컬 running/progress 제거), 완료 시 결과 갱신.
- StatusBar에 진행 표시: "완전 동일 검사 N/M" + 스피너 + 취소(✕), 텍스트 클릭 시
패널 다시 열기.
검증(대용량 3000장): 패널을 닫은 상태에서 상태바가 완전 동일 검사 517→3,000
진행을 실시간 표시, 취소 버튼 노출 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
증상: 영상 재생 시 재생바가 실시간으로 늘어나며 요동침. 총 재생시간이
고정되지 않음.
원인: durationSec가 직접 모드에서 <video>.duration을 우선 사용했는데, 스트림/
일부 컨테이너(리먹스 fMP4 등)에선 재생 중 요소 duration이 계속 커져 재생바가
current/duration 비율로 요동쳤다. 또 메타(duration_ms)가 아직 추출 안 된 영상은
playback_info가 null을 반환해 요소 duration에 의존.
수정:
- VideoPlayer.durationSec: ffprobe 메타 총길이를 항상 우선, 없을 때만 요소 duration
폴백. (고정 총길이라 재생바 안정)
- playback_info: 영상인데 duration_ms가 null이면 즉석 ffprobe로 채우고 DB에 캐시
(SMB 등 메타 미추출 상태에서도 정확한 총길이/코덱 보장, 다음 재생부터 재프로브 없음).
검증(VP9 20s): playback_info durationMs=20000, 재생 중 표시 0:00→ 진행하며 총길이는
0:20 고정, 진행바 0%→4%→8% 단조 증가(요동 없음).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
증상: SMB(네트워크) 소스 + 자료 많음 상태에서 재실행하면 창이 백지 + "응답 없음".
원인: setup()가 메인 스레드에서 watcher.refresh()를 동기 호출 → 각 로컬 소스에
debouncer.watch(경로, Recursive)를 등록하는데, 재실행 직후 SMB 공유가 느리거나
재연결 중이면 watch()가 블로킹 → 메인 스레드(이벤트 루프)가 멈춰 창이 안 그려짐.
(처음 열 땐 소스가 없어 no-op이라 정상이었고, 소스 추가는 워커 스레드에서 refresh해
안 멈췄음 — 재실행 때만 메인 스레드에서 SMB를 건드려 멈춤.)
수정: 워처 매니저는 즉시 등록하되 refresh(watch 등록)는 백그라운드 스레드로,
시작 썸네일 백필(enqueue_pending)도 백그라운드로 이동. setup()가 SMB를 동기로
건드리지 않으므로 창이 즉시 렌더되고 응답 유지.
검증(로컬): 소스 있는 상태 재실행 → 창 ~0.7초에 렌더(사이드바+그리드 30셀),
새 파일 추가 시 워처가 3초 내 감지해 재스캔(31셀). 회귀 없음.
(실제 SMB 블로킹은 로컬 재현 불가 — 메인 스레드에서 SMB를 건드리는 유일한 지점을 제거.)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
증상: 파일(특히 영상)이 많으면 첫 소스 추가 시 오래 걸림. 원인은
library-changed(그리드 표시)가 스캔+이미지메타+영상메타를 모두 마친 뒤에야
발생 → 영상마다 ffprobe 프로세스를 띄우는 영상 메타가 끝날 때까지 그리드가 빈 채로.
수정: run_scan_pipeline에 on_refresh 콜백 추가.
- 열거(파일 DB 삽입) 직후 썸네일 생성 시작 + library-changed 발생 → 그리드 즉시 표시
- 이미지 메타(헤더, 빠름) 후 재배치
- 영상 메타(ffprobe, 느림)는 백그라운드 진행, 완료 후 최종 재배치
watcher 재스캔도 동일 적용.
검증(영상 250개): 그리드가 300ms에 표시(메타 250 대기 중), 썸네일은 백그라운드로
채워지고 영상 메타 완료(~6.6s) 후 종횡비 재배치. 기존엔 ~6.6s 내내 빈 화면이었음.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
증상: 재생 중 재생바 이동이나 방향키 이동이 잘 안 됨.
원인 두 가지:
1) 재생바가 오직 ffprobe 메타(pb.durationMs)에만 의존 → 메타 duration이
없으면(중단된 스캔·일부 포맷) durationSec=0이라 seekFromPointer가 항상 0으로
이동. 직접 재생인데도 <video> 요소가 아는 실제 길이를 안 썼다.
2) 스트림(트랜스코딩/리먹스) 모드는 시크마다 ffmpeg 재시작 → 재생바 드래그 시
pointermove마다 재시작해 스래싱.
수정:
- durationSec(): 직접 모드는 요소 duration 우선(메타 없어도 시크바 동작),
스트림 모드는 -ss로 잘린 요소값이 부정확하므로 메타 우선. 요소 duration은
유한·양수일 때만 채택.
- 스트림 시크는 250ms 디바운스로 마지막 위치 한 번만 재시작(드래그·연타 합침),
seekingTo로 재시작 전 표시 위치 고정(옛 스트림이 되돌리지 않게).
- 길이 미상이면 재생바 클릭 무시.
검증(직접 재생 VP9): 방향키 2→7→2, 재생바 50%→6.0s / 25%→3.0s / 80%→9.6s.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 메타 백필: 이전 스캔이 중단돼 meta_state=0으로 남은 파일을 시작 시
(전체 재스캔 없이) 저우선순위로 이어서 분석. 썸네일 백필(enqueue_pending)과 짝.
- pending_counts 커맨드 + 상태바 표시: "썸네일 생성 중 N / 메타 분석 중 M".
thumbs-ready·library-changed·시작 시 트리거하고, 남은 작업이 있으면 2초 폴링,
0이 되면 자동으로 숨김.
검증: 영상 200개 스캔 중 상태바가 200→0으로 감소 후 사라짐. 메타 도중
강제 종료 후 재실행 시 재스캔 없이(scanning=false) 메타/썸네일 백필만 재개됨.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
증상: 영상이 많은 라이브러리에서 첫 로딩이 오래 걸리고, 다 불러온 뒤
재실행하면 멈춤. 원인은 미완료 영상 썸네일 백로그가 시작 시
enqueue_pending으로 재개되는데, ffmpeg/ffprobe가 '자식 프로세스'라
스레드 저우선순위(이전 수정)를 상속받지 못해 NORMAL로 전 코어를 포화시켜
WebView UI가 멈춘 것. (재실행 시 전체 재스캔은 없음 — 자동스캔은 dev 전용,
워처도 시작 시 스캔 안 함. 재처리는 미완료 썸네일 재개일 뿐.)
- ffmpeg::command(): Windows CREATE_NO_WINDOW에 BELOW_NORMAL_PRIORITY_CLASS 추가,
Unix는 pre_exec로 setpriority(nice+10). 검증: 스캔 중 ffmpeg/ffprobe
PriorityClass=BelowNormal 관측(ffmpeg 406, ffprobe 46 샘플).
- 시작 유지보수 스레드도 저우선순위로, DB 백업(VACUUM INTO=전체 복제)은
24시간 내 백업 있으면 건너뜀 — 대용량 라이브러리 재실행 부하/디스크 낭비 감소.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
기존엔 항상 라이브러리 전체를 대상으로 했다. 이제 중복 검토 패널에서
현재 보고 있는 뷰(폴더=하위 포함 / 소스)로 범위를 좁힐 수 있고,
폴더/소스 뷰에서는 기본값이 '현재 위치'다. 전체/검색/태그/스마트 뷰는
전체 라이브러리로 고정.
- dedupe::Scope { All | Source | Folder{recursive} } 도입, load_files/run에 적용
(folder_snapshot과 동일한 경로 프리픽스 스코핑)
- start_dedupe에 folder_id/recursive 파라미터 추가
- DedupePanel: view() 기반 범위 세그먼트 컨트롤
- 테스트: folder_scope_restricts_detection (folderA=1그룹, 전체=2그룹, 누출 없음)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Compress-Archive는 빈 디렉터리를 zip에 넣지 않아, 포터블 감지 신호였던
data\ 폴더가 배포 zip에서 사라졌다. 그 결과 압축 해제 후 실행하면
포터블 모드가 아닌 %APPDATA%에 데이터를 저장했다(x64/ARM64 공통).
paths.rs가 인식하는 portable.marker 파일을 스테이지에 추가해 해결.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ContentArea의 소스 목록 리소스가 마운트 시 1회만 조회해, 소스가
0개인 세션에서 첫 폴더를 추가해도 온보딩 화면이 그대로 남았다.
sidebarVersion을 리소스 소스로 키잉해 소스 추가/제거 시 재조회하도록 수정
(Sidebar와 동일 패턴). library-changed → refreshSidebar로 즉시 전환.
검증: 온보딩 상태에서 소스 추가+스캔 → 리로드 없이 ~1초 후 그리드 표시.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
썸네일 미준비 셀이 빈 칸으로 보이던 것을 개선. 스냅샷 flags에
비트1(생성 실패, thumb_state=2)을 추가해 대기/실패를 구분한다.
- 대기(생성 전): 은은한 pulse 스켈레톤(bg-hover)
- 실패: 정적 아이콘(🖼) — 무한 pulse 방지
- 준비됨: 썸네일 이미지
검증: 619개 대기 상태에서 하단 스크롤 시 pulse 스켈레톤 50개 →
생성 완료되며 이미지로 즉시 전환 확인(bg #33363d, animation pulse).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
원인: JustifiedGrid 셀 본문에서 snapshot/id를 한 번만 캡처(const)했다.
<For>는 인덱스 값이 같으면(뷰 전환 시 가시범위 [0..N] 동일) DOM 행을
재사용하므로, 재사용된 셀이 이전 폴더의 id·썸네일을 그대로 유지했다.
(레이아웃 리사이즈 버그와 동일 계열)
- id()/showImg()/isVideo()/version()을 snapshot() 기반 반응형 접근자로 변경
- 클릭/컨텍스트/드래그 핸들러도 호출 시점의 snapshot()을 읽도록
- img에 onLoad 추가 — 재사용된 img가 이전 onError로 display:none에 걸려
새 썸네일이 안 보이던 문제 방지
검증: 3개 하위폴더 픽스처에서 폴더 클릭 시 가시 썸네일 id가
folderA(1-40)/folderB(41-80)/folderC(83-140)로 즉시 전환 확인.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
원인: 실사진(수십 MP) 스캔 시 메타 추출(rayon)과 썸네일 워커가
NORMAL 우선순위로 전 코어를 포화시켜 WebView UI 스레드를 굶김.
풀해상도 JPEG 디코드는 파일당 ~72MB를 할당해 병렬 시 메모리 대역폭까지 포화.
- prio 모듈: 현재 스레드 우선순위 낮추기(Win BELOW_NORMAL / macOS nice+5),
메타 전용 저우선순위 rayon 풀(코어-1, 전역 풀과 분리)
- 썸네일 워커 스레드·스캔 스레드를 저우선순위로 → CPU 포화 시 UI 우선 스케줄
- meta 이미지/영상 추출을 저우선순위 풀에서 실행
- JPEG는 jpeg-decoder DCT 축소 디코드(1/8 등) 사용:
24MP 기준 풀디코드 63ms/72MB → 축소 38ms/1MB (1.7배·메모리 ~70배 절감),
RGB24/L8만 처리하고 그 외(CMYK)는 기존 경로로 폴백
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 사이드바 소스 행 hover 시 ✕ 버튼 → 확인 후 인덱스/폴더/태그/썸네일
캐시 제거. 디스크의 실제 파일은 삭제하지 않음.
- 로컬: 파일 워처 해제. 원격: 연결 해제 + 자격증명(키체인/볼트) 삭제.
- maintenance::remove_source (defer_foreign_keys로 자기참조 FK 처리),
스캔 중 제외 방지, 제외한 소스를 보던 중이면 전체 뷰로 전환.
Rust 테스트: 실제 파일 보존 + 인덱스/썸네일 제거 검증 통과.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
증상: 창을 최대화하거나 썸네일 줌을 바꿔도 그리드가 옛 폭에 갇혀
오른쪽이 비고 느리게 느껴짐.
근본 원인: <For>가 인덱스로 셀 DOM을 재사용하는데 셀의 x/y/w/h를
item 함수 본문에서 1회만 계산해, layout 변경(리사이즈/줌) 시 재사용된
셀 위치가 갱신되지 않았음(뷰 변경=인덱스 전면 교체 때만 반영됐음).
수정:
- 셀 위치/크기를 반응형(box())으로 읽어 layout 변경 시 재배치
- 레이아웃 계산을 Web Worker→메인 스레드 동기 계산으로 전환
(프로덕션 Tauri 빌드에서 module worker가 첫 메시지 후 무응답)
- 리사이즈/줌을 폴링(clientWidth+gridRowHeight 직접 읽기)+Ctrl휠 직접
recompute로 구동, 스냅샷 변경은 effect로. 이벤트 누락에 견고.
- 가상 그리드 썸네일 lazy→eager 로딩으로 스크롤 중 즉시 표시
결과: 최대화 시 폭 99% 채움, 줌 재배치 정상, 스크롤 ~34→~57fps.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- 그리드 썸네일 줌: Ctrl+휠 + 툴바 슬라이더(110~420px), localStorage 유지
- 라이트박스 사진 줌/팬: 휠(커서 기준)·드래그·더블클릭·+/-/0 키,
파일 이동 시 리셋, 확대율 배지
- 영상 재생목록: 종료 시 다음 항목 자동재생, 🔁 반복 토글
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
P1 원격 소스 UX:
- remote_thumbs: VFS 다운로드로 원격 썸네일 생성(이미지 EXIF 내장 우선,
영상은 미디어서버 bridge URL로 ffmpeg Range 추출)
- 앱 시작 시 키체인 자격증명으로 원격 소스 자동 재연결
- fileops: physical_move에 Windows 공유위반 재시도
P3 그리드/포맷:
- RAW(cr2/nef/arw/dng 등) 내장 JPEG 프리뷰 추출 썸네일(scan_largest_jpeg)
- 그리드 마퀴(드래그 사각형) 다중선택
- .gitattributes 줄바꿈 정규화
Rust 테스트 51개 통과.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>