diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-06-20 11:10:36 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2026-06-20 11:10:36 +0900 |
| commit | f2a60d11af0b1db24de65a3001afd5019b5259e7 (patch) | |
| tree | ea394a740f62997d9ed8f3aed44ebef7417df238 /ar/.config | |
| parent | f533c8e39c06c268c4ec68ce47907888181766b4 (diff) | |
modified mpv/input.conf, modified scripts/integrity-check.lua, created bin/rmev
Diffstat (limited to 'ar/.config')
| -rw-r--r-- | ar/.config/mpv/input.conf | 1 | ||||
| -rw-r--r-- | ar/.config/mpv/scripts/integrity-check.lua | 179 |
2 files changed, 166 insertions, 14 deletions
diff --git a/ar/.config/mpv/input.conf b/ar/.config/mpv/input.conf index 4d63c44..427581f 100644 --- a/ar/.config/mpv/input.conf +++ b/ar/.config/mpv/input.conf @@ -71,6 +71,7 @@ alt+h script-message cycle_video_rotate -90 alt+l script-message cycle_video_rotate 90 # Rotate 90 g script-message contact-sheet-close; script-message playlist-view-toggle # Toggle gallery i script-message-to misc print-media-info # Toggle video info +I script-message integrity-status # Show integrity check status (playlist) n set volume 50 # Set volume 50 shift+n set speed 1.0 # Set normal speed 1.0 m cycle mute # Toggle mute diff --git a/ar/.config/mpv/scripts/integrity-check.lua b/ar/.config/mpv/scripts/integrity-check.lua index 8db71fa..fce3d1d 100644 --- a/ar/.config/mpv/scripts/integrity-check.lua +++ b/ar/.config/mpv/scripts/integrity-check.lua @@ -7,6 +7,11 @@ -- * 손상 구간을 만나면 -xerror 로 즉시 중단 → 손상 파일은 빠르게 판정. -- * 결과는 경로+수정시각으로 캐시 → 다음에 같은 파일은 즉시 표시. -- * 손상 파일 경로는 corrupted.log 에 기록. +-- * 재생목록이 있으면(scan_playlist) 현재 파일 검사가 끝난 뒤, +-- 뒤따르는 항목들을 한 번에 하나씩 백그라운드로 미리 검사한다. +-- (배지는 현재 재생 파일에만 표시하고, 미리 검사는 캐시·로그만 갱신) +-- * 재생목록 미리 검사가 끝나면 OSD 로 요약 알림(notify_done). +-- script-message integrity-status 로 진행 현황을 즉시 확인할 수 있다. -- -- 한계: -c copy(디코딩 안 함) 기반이라 컨테이너/끊김/잘림은 잡지만, -- 컨테이너는 멀쩡하고 화면만 미세하게 깨지는 결함은 못 잡는다. @@ -22,6 +27,8 @@ local msg = require 'mp.msg' local opts = { enabled = true, -- 기능 on/off scan_on_load = true, -- 파일 열 때 자동 검사 + scan_playlist = true, -- 현재 파일 검사 후 뒤따르는 재생목록 항목도 백그라운드 검사 + notify_done = true, -- 재생목록 백그라운드 검사가 끝나면 OSD 로 요약 표시 show_scanning = false, -- 검사 중 표시 여부 (기본: 표시 안 함) deep_scan = false, -- true 면 디코딩까지 검사(정밀하지만 느림) use_cache = true, -- 검사 결과 캐시 사용 @@ -45,6 +52,7 @@ local cache = {} -- path -> {mtime=, size=, status=, errors=} local overlay = mp.create_osd_overlay("ass-events") local current_path = nil local scan_token = 0 -- 오래된(stale) 콜백 무시용 +local bg_token = 0 -- 재생목록 백그라운드 검사 무효화용 ---------------------------------------------------------------------- -- 캐시 입출력 @@ -173,7 +181,25 @@ local function apply_result(path, corrupt, from_cache) if not from_cache then append_cache(path, cache[path]) end end -local function start_scan(path) +-- subprocess 결과를 손상 여부로 환산 +local function determine_corrupt(result) + local stderr = result.stderr or "" + local status = result.status or 0 + return (stderr:gsub("%s+", "") ~= "") or (status ~= 0) +end + +-- 캐시가 현재 파일 상태(수정시각·크기)와 일치하면 그 항목을 반환 +local function cached_fresh(path) + if not (opts.use_cache and cache[path]) then return nil end + local mtime, size = file_sig(path) + local e = cache[path] + if mtime and e.mtime == mtime and e.size == size then + return e + end + return nil +end + +local function start_scan(path, on_done) scan_token = scan_token + 1 local token = scan_token show_scanning() @@ -192,32 +218,140 @@ local function start_scan(path) hide_badge() return end - local stderr = result.stderr or "" - local status = result.status or 0 - local corrupt = (stderr:gsub("%s+", "") ~= "") or (status ~= 0) - apply_result(path, corrupt, false) + apply_result(path, determine_corrupt(result), false) + if on_done then on_done() end end) end ---------------------------------------------------------------------- +-- 재생목록 백그라운드 검사 (현재 파일 검사 완료 후 뒤따르는 항목들) +---------------------------------------------------------------------- +-- 진행 중인 재생목록 검사를 무효화(파일 전환·토글 시) +local function cancel_bg() + bg_token = bg_token + 1 +end + +-- 재생목록 항목의 filename 을 실제 검사 가능한 경로로 변환 +local function resolve_playlist_path(filename) + if not filename then return nil end + if filename:find("^%a[%w%+%-%.]*://") then return filename end -- URL 은 그대로 + if filename:find("^/") then return filename end -- 절대경로 + local wd = mp.get_property("working-directory") + if wd then return utils.join_path(wd, filename) end + return filename +end + +-- 배지 없이 캐시·로그만 갱신 (백그라운드 항목용) +local function record_result_quiet(path, corrupt) + local mtime, size = file_sig(path) + cache[path] = { + mtime = mtime or 0, + size = size or 0, + status = corrupt and "corrupt" or "ok", + errors = 0, + } + if corrupt then + log_corrupted(path) + msg.warn("손상됨(재생목록): " .. path) + end + append_cache(path, cache[path]) +end + +-- 재생목록 전체의 검사 현황을 캐시 기준으로 집계 +local function playlist_stats() + local count = mp.get_property_number("playlist-count", 0) + local s = { total = 0, ok = 0, corrupt = 0, pending = 0 } + for i = 0, count - 1 do + local path = resolve_playlist_path( + mp.get_property("playlist/" .. i .. "/filename")) + if scannable(path) then + s.total = s.total + 1 + local e = cached_fresh(path) + if not e then s.pending = s.pending + 1 + elseif e.status == "corrupt" then s.corrupt = s.corrupt + 1 + else s.ok = s.ok + 1 end + end + end + return s +end + +-- start_index 부터 재생목록 끝까지 한 번에 하나씩 순차 검사 +local function scan_playlist_from(start_index) + cancel_bg() + local token = bg_token + local count = mp.get_property_number("playlist-count", 0) + local did_scan = false -- 이번 검사에서 실제로 새로 검사한 항목이 있었는지 + + -- 끝까지 도달했을 때 요약 알림(새로 검사한 게 있을 때만 — 자동재생 중복 방지) + local function finish() + if not (opts.notify_done and did_scan) then return end + local s = playlist_stats() + local txt = (s.corrupt > 0) + and string.format("재생목록 검사 완료 · 손상 %d개 (총 %d)", s.corrupt, s.total) + or string.format("재생목록 검사 완료 · 이상 없음 (총 %d)", s.total) + mp.osd_message(txt, 4) + msg.info(txt) + end + + local function step(i) + if token ~= bg_token then return end -- 파일 전환/토글 → 중단 + if i >= count then finish(); return end + local path = resolve_playlist_path( + mp.get_property("playlist/" .. i .. "/filename")) + if not scannable(path) then return step(i + 1) end + if path == current_path then return step(i + 1) end -- 현재 파일은 이미 검사됨 + if cached_fresh(path) then return step(i + 1) end -- 이미 검사된 파일은 건너뜀 + + did_scan = true + mp.command_native_async({ + name = "subprocess", + args = build_args(path), + playback_only = false, + capture_stdout = true, + capture_stderr = true, + }, function(success, result, err) + if token ~= bg_token then return end -- 중간에 무효화됨 → 무시 + if result and not result.killed_by_us + and result.error_string ~= "init" then + record_result_quiet(path, determine_corrupt(result)) + end + step(i + 1) + end) + end + + step(start_index) +end + +-- 재생목록이 있으면 현재 위치 다음 항목부터 백그라운드 검사 시작 +local function maybe_scan_playlist() + if not (opts.enabled and opts.scan_playlist) then return end + local count = mp.get_property_number("playlist-count", 0) + if count <= 1 then return end -- 재생목록 없음 + local pos = mp.get_property_number("playlist-pos", 0) + scan_playlist_from(pos + 1) +end + +---------------------------------------------------------------------- -- 이벤트 ---------------------------------------------------------------------- local function on_file_loaded() hide_badge() + cancel_bg() -- 이전 재생목록 검사 중단 current_path = mp.get_property("path") if not opts.enabled or not opts.scan_on_load then return end - if not scannable(current_path) then return end + if not scannable(current_path) then + maybe_scan_playlist() -- 현재가 스트림이어도 목록은 검사 + return + end -- 캐시 적중(수정시각·크기 동일)이면 즉시 표시 - if opts.use_cache and cache[current_path] then - local mtime, size = file_sig(current_path) - local e = cache[current_path] - if mtime and e.mtime == mtime and e.size == size then - apply_result(current_path, e.status == "corrupt", true) - return - end + local e = cached_fresh(current_path) + if e then + apply_result(current_path, e.status == "corrupt", true) + maybe_scan_playlist() + return end - start_scan(current_path) + start_scan(current_path, maybe_scan_playlist) -- 현재 검사 완료 후 목록 검사 end ---------------------------------------------------------------------- @@ -236,6 +370,7 @@ end local function toggle() opts.enabled = not opts.enabled if not opts.enabled then + cancel_bg() hide_badge() else on_file_loaded() @@ -243,10 +378,26 @@ local function toggle() mp.osd_message("무결성 검사: " .. (opts.enabled and "켜짐" or "꺼짐")) end +-- 재생목록 검사 현황을 즉시 표시 (끝났는지 / 얼마나 남았는지 확인용) +local function status() + local count = mp.get_property_number("playlist-count", 0) + if count <= 1 then + mp.osd_message("무결성: 재생목록 없음") + return + end + local s = playlist_stats() + local state = (s.pending == 0) and "검사 완료" or ("검사 중(남음 " .. s.pending .. ")") + mp.osd_message(string.format( + "무결성 %s · 정상 %d · 손상 %d · 미검사 %d (총 %d)", + state, s.ok, s.corrupt, s.pending, s.total), 4) +end + mp.add_key_binding(nil, "rescan", rescan) mp.add_key_binding(nil, "toggle", toggle) +mp.add_key_binding(nil, "status", status) mp.register_script_message("integrity-rescan", rescan) mp.register_script_message("integrity-toggle", toggle) +mp.register_script_message("integrity-status", status) ---------------------------------------------------------------------- -- 초기화 |
