User Tools

Site Tools


takeoutphotosanitizer:uncertain_reclassification_workflow_guide

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
takeoutphotosanitizer:uncertain_reclassification_workflow_guide [2026/02/23 17:03] – [3단계 – 연도 오버라이드 파일 생성] hyjeongtakeoutphotosanitizer:uncertain_reclassification_workflow_guide [2026/02/24 17:08] (current) – [1단계 – _Uncertain 목록 추출] hyjeong
Line 22: Line 22:
  
   (작업 디렉토리)   (작업 디렉토리)
-   └─ Photos_Backup/ +   └─ Photos_Backup\ 
-      ├─ From_Google_Takeout/ +      ├─ From_Google_Takeout\ 
-      │   ├─ 2019/ +      │   ├─ 2019\ 
-      │   ├─ 2020/+      │   ├─ 2020\
       │   ├─ ...       │   ├─ ...
       │   └─ SHA-256.txt   ← hash DB       │   └─ SHA-256.txt   ← hash DB
-      └─ _ops/ +      └─ _ops\ 
-           ├─ reclass/ +           ├─ reclass\ 
-           └─ notes/+           └─ notes\
  
 이 폴더 및 그 하위에는 운영 및 관리 파일만 저장한다. 이 폴더 및 그 하위에는 운영 및 관리 파일만 저장한다.
Line 41: Line 41:
  
 <code powershell> <code powershell>
-$root = "Photos_Backup"+$unc = "From_Google_Takeout\_Uncertain" 
 +$out = "_ops\reclass\uncertain_review.csv"
  
-$unc = Join-Path $root "From_Google_Takeout\_Uncertain" +if (!(Test-Path -LiteralPath $unc)) { 
-$out = Join-Path $root "_ops\reclass\uncertain_review.csv"+    throw "_Uncertain 폴더가 없습니다: $unc
 +}
  
-Get-ChildItem $unc -File -Recurse |+Get-ChildItem -LiteralPath $unc -File -Recurse |
 Select-Object FullName, Name, Length, LastWriteTime | Select-Object FullName, Name, Length, LastWriteTime |
-Export-Csv $out -NoTypeInformation -Encoding UTF8+Export-Csv -LiteralPath $out -NoTypeInformation -Encoding utf8BOM
 </code> </code>
  
 생성 파일: 생성 파일:
  
-  Photos_Backup/_ops/reclass/uncertain_review.csv+  Photos_Backup\_ops\reclass\uncertain_review.csv
  
 ----- -----
Line 68: Line 70:
 저장 파일: 저장 파일:
  
-  Photos_Backup/_ops/reclass/uncertain_review_done.csv+  Photos_Backup\_ops\reclass\uncertain_review_done.csv
  
 ----- -----
Line 122: Line 124:
   sha256<TAB>year_final<TAB>date<TAB>note   sha256<TAB>year_final<TAB>date<TAB>note
  
-이 파일은 “수동 재분류 패치 기록”이다.+이 파일은 “수동 재분류 패치 기록”이다. 매 실행 시 재생성(덮어쓰기) 된다. 
  
 ----- -----
Line 131: Line 133:
  
 <code powershell> <code powershell>
-# Photos_Backup 폴더에서 실행한다고 가정 +작업 디렉토리(= Photos_Backup)에서 실행한다고 가정 
-$in  = "_ops\reclass\uncertain_review_done.csv"+ 
 +$in        = "_ops\reclass\uncertain_review_done.csv"
 $rootMedia = "From_Google_Takeout" $rootMedia = "From_Google_Takeout"
-$log = "_ops\reclass\move_log.tsv"+$log       = "_ops\reclass\move_log.tsv" 
 + 
 +# 입력 파일 확인 
 +if (!(Test-Path -LiteralPath $in)) { 
 +    throw "입력 파일이 없습니다: $in" 
 +
 + 
 +# Media 루트 확인 
 +if (!(Test-Path -LiteralPath $rootMedia)) { 
 +    throw "Media 루트 폴더가 없습니다: $rootMedia" 
 +}
  
 # 로그 폴더가 없으면 생성 # 로그 폴더가 없으면 생성
 $logDir = Split-Path -Parent $log $logDir = Split-Path -Parent $log
-if (!(Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir | Out-Null }+if (!(Test-Path -LiteralPath $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null }
  
-Import-Csv $in | Where-Object { $_.year_final -match '^\d{4}$'|+# 카운터(요약 출력용) 
 +$cnt_total  = 0 
 +$cnt_skip   = 0 
 +$cnt_moved  = 0 
 +$cnt_failed = 0 
 + 
 +Import-Csv -LiteralPath $in |
 ForEach-Object { ForEach-Object {
  
 +    $cnt_total++
 +
 +    # year_final 정리(공백 제거)
 +    $yy = ("" + $_.year_final).Trim()
 +    if ($yy -notmatch '^\d{4}$') { $cnt_skip++; return }
 +
 +    # 원본 파일 경로 확인
     $src = $_.FullName     $src = $_.FullName
-    $yy  = $_.year_final+    if ([string]::IsNullOrWhiteSpace($src)) { $cnt_skip++; return } 
 +    if (!(Test-Path -LiteralPath $src)) { $cnt_skip++; return }
  
-    # 목적 연도 폴더 (없으면 생성)+    # 안전장치: _Uncertain 내부 파일만 이동(의도치 않은 이동 방지) 
 +    # (대소문자 무시, 경로 구분자 혼용을 감안해 \\ 와 / 모두 허용) 
 +    if ($src -notmatch '[\\/]+From_Google_Takeout[\\/]+_Uncertain[\\/]+') { $cnt_skip++; return } 
 + 
 +    # 목적 연도 폴더 생성
     $dstDir = Join-Path $rootMedia $yy     $dstDir = Join-Path $rootMedia $yy
-    if (!(Test-Path $dstDir)) { New-Item -ItemType Directory -Path $dstDir | Out-Null }+    if (!(Test-Path -LiteralPath $dstDir)) { New-Item -ItemType Directory -Path $dstDir -Force | Out-Null }
  
-    # 일 파일명 충돌 시 sha256 prefix를 붙여 회피 +    # 목적 파명 (CSV의 Name 필드 우선, 없으면 src에서 파일명 추출) 
-    $dst = Join-Path $dstDir $_.Name +    $name = $_.Name 
-    if (Test-Path $dst) { +    if ([string]::IsNullOrWhiteSpace($name)) { $name = [System.IO.Path]::GetFileName($src) } 
-        $h8 = (Get-FileHash $src -Algorithm SHA256).Hash.Substring(0,8) + 
-        $dst = Join-Path $dstDir ("{0}_{1}" -f $h8, $_.Name)+    $dst = Join-Path $dstDir $name 
 + 
 +    # 동일 파일명 충돌 시 sha256 prefix로 회피 
 +    if (Test-Path -LiteralPath $dst) { 
 +        $h8 = (Get-FileHash -LiteralPath $src -Algorithm SHA256).Hash.Substring(0,8) 
 +        $dst = Join-Path $dstDir ("{0}_{1}" -f $h8, $name)
     }     }
  
-    Move-Item -LiteralPath $src -Destination $dst+    $status = "moved" 
 +    try { 
 +        Move-Item -LiteralPath $src -Destination $dst -ErrorAction Stop 
 +        $cnt_moved++ 
 +    } 
 +    catch { 
 +        $status = "move_failed: " + ($_.Exception.Message -replace "(\r\n|\n|\r)", " " -replace "`t"," ") 
 +        $cnt_failed++ 
 +    }
  
-    "{0}`t{1}`t{2}`t{3}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $src, $dst"moved" +    # 로그 기록(탭/개행 제거) 
-      Add-Content $log -Encoding UTF8+    $srcLog = ($src -replace "`t"," " -replace "(\r\n|\n|\r)"," ") 
 +    $dstLog = ($dst -replace "`t"," " -replace "(\r\n|\n|\r)"," ") 
 + 
 +    # 로그 형식: time, year_final, src, dst, status 
 +    "{0}`t{1}`t{2}`t{3}`t{4}" -f (Get-Date -Format "yyyy-MM-dd HH:mm:ss"), $yy, $srcLog$dstLog, $status 
 +      Add-Content -LiteralPath $log -Encoding UTF8
 } }
 +
 +# 요약 출력
 +Write-Host ("[MOVE] total={0} moved={1} failed={2} skipped={3}  log={4}" -f $cnt_total, $cnt_moved, $cnt_failed, $cnt_skip, $log)
 </code> </code>
  
Line 172: Line 224:
 생성 가능 파일: 생성 가능 파일:
  
-  Photos_Backup/_ops/notes/annotations.tsv+  Photos_Backup\_ops\notes\annotations.tsv
  
 형식: 형식:
takeoutphotosanitizer/uncertain_reclassification_workflow_guide.1771833783.txt.gz · Last modified: by hyjeong