takeoutphotosanitizer:uncertain_reclassification_workflow_guide
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| takeoutphotosanitizer:uncertain_reclassification_workflow_guide [2026/02/23 16:11] – [4단계 – 실제 파일 이동] hyjeong | takeoutphotosanitizer:uncertain_reclassification_workflow_guide [2026/02/23 17:17] (current) – [4단계 – 실제 파일 이동] hyjeong | ||
|---|---|---|---|
| Line 19: | Line 19: | ||
| ===== 0단계 – 운영 폴더 생성 ===== | ===== 0단계 – 운영 폴더 생성 ===== | ||
| - | 다음과 같이 _ops 및 하위 폴더를 생성한다. | + | 다음과 같이 |
| (작업 디렉토리) | (작업 디렉토리) | ||
| - | | + | |
| - | ├─ From_Google_Takeout/ | + | ├─ From_Google_Takeout\ |
| - | │ | + | │ |
| - | │ | + | │ |
| + | │ | ||
| │ | │ | ||
| - | └─ _ops/ | + | └─ _ops\ |
| - | | + | |
| - | | + | |
| 이 폴더 및 그 하위에는 운영 및 관리 파일만 저장한다. | 이 폴더 및 그 하위에는 운영 및 관리 파일만 저장한다. | ||
| Line 40: | Line 41: | ||
| <code powershell> | <code powershell> | ||
| - | $root = "Photos_Backup" | + | $unc = "From_Google_Takeout\_Uncertain" |
| + | $out = " | ||
| - | $unc = Join-Path $root "From_Google_Takeout\_Uncertain" | + | if (!(Test-Path -LiteralPath |
| - | $out = Join-Path $root " | + | throw " |
| + | } | ||
| - | Get-ChildItem $unc -File -Recurse | | + | Get-ChildItem |
| Select-Object FullName, Name, Length, LastWriteTime | | Select-Object FullName, Name, Length, LastWriteTime | | ||
| - | Export-Csv $out -NoTypeInformation -Encoding UTF8 | + | Export-Csv |
| </ | </ | ||
| 생성 파일: | 생성 파일: | ||
| - | Photos_Backup/_ops/reclass/uncertain_review.csv | + | Photos_Backup\_ops\reclass\uncertain_review.csv |
| ----- | ----- | ||
| Line 67: | Line 70: | ||
| 저장 파일: | 저장 파일: | ||
| - | Photos_Backup/_ops/reclass/uncertain_review_done.csv | + | Photos_Backup\_ops\reclass\uncertain_review_done.csv |
| ----- | ----- | ||
| Line 76: | Line 79: | ||
| <code powershell> | <code powershell> | ||
| - | # Photos_Backup | + | # 작업 디렉토리(= |
| $in = " | $in = " | ||
| $out = " | $out = " | ||
| + | |||
| + | # 입력 파일 확인 | ||
| + | if (!(Test-Path $in)) { | ||
| + | throw " | ||
| + | } | ||
| # 출력 폴더가 없으면 생성 | # 출력 폴더가 없으면 생성 | ||
| Line 84: | Line 93: | ||
| if (!(Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null } | if (!(Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null } | ||
| - | Import-Csv $in | Where-Object { $_.year_final -match ' | + | Import-Csv $in | |
| ForEach-Object { | ForEach-Object { | ||
| - | $h = (Get-FileHash | + | |
| - | " | + | |
| - | } | Set-Content $out -Encoding UTF8 | + | |
| + | # 확정 연도(4자리)만 처리 | ||
| + | if ($yy -notmatch ' | ||
| + | |||
| + | # FullName 확인 | ||
| + | $src = $_.FullName | ||
| + | if ([string]:: | ||
| + | if (!(Test-Path -LiteralPath $src)) { return } | ||
| + | |||
| + | # note 정리 (TSV 깨짐 방지: 탭/개행 제거) | ||
| + | $note = ("" | ||
| + | $note = $note -replace " | ||
| + | $note = $note -replace " | ||
| + | $note = $note.Trim() | ||
| + | |||
| + | # sha256 계산 | ||
| + | $h = (Get-FileHash -LiteralPath $src -Algorithm SHA256).Hash | ||
| + | |||
| + | # TSV 한 줄 출력 | ||
| + | " | ||
| + | } | Set-Content | ||
| </ | </ | ||
| Line 95: | Line 124: | ||
| sha256< | sha256< | ||
| - | 이 파일은 “수동 재분류 패치 기록”이다. | + | 이 파일은 “수동 재분류 패치 기록”이다. 매 실행 시 재생성(덮어쓰기) 된다. |
| ----- | ----- | ||
| Line 104: | Line 133: | ||
| <code powershell> | <code powershell> | ||
| - | $in = " | + | # 작업 디렉토리(= Photos_Backup)에서 실행한다고 가정 |
| + | |||
| + | $in = " | ||
| $rootMedia = " | $rootMedia = " | ||
| - | $log = " | + | $log |
| + | |||
| + | # 입력 파일 확인 | ||
| + | if (!(Test-Path -LiteralPath $in)) { | ||
| + | throw " | ||
| + | } | ||
| + | |||
| + | # Media 루트 확인 | ||
| + | if (!(Test-Path -LiteralPath $rootMedia)) { | ||
| + | throw "Media 루트 폴더가 없습니다: | ||
| + | } | ||
| # 로그 폴더가 없으면 생성 | # 로그 폴더가 없으면 생성 | ||
| $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 |
| + | |||
| + | # 카운터(요약 출력용) | ||
| + | $cnt_total | ||
| + | $cnt_skip | ||
| + | $cnt_moved | ||
| + | $cnt_failed = 0 | ||
| - | Import-Csv $in | Where-Object { $_.year_final -match ' | + | Import-Csv |
| ForEach-Object { | ForEach-Object { | ||
| + | $cnt_total++ | ||
| + | |||
| + | # year_final 정리(공백 제거) | ||
| + | $yy = ("" | ||
| + | if ($yy -notmatch ' | ||
| + | |||
| + | # 원본 파일 경로 확인 | ||
| $src = $_.FullName | $src = $_.FullName | ||
| - | $yy = $_.year_final | + | |
| + | if (!(Test-Path -LiteralPath $src)) { $cnt_skip++; | ||
| - | # 목적 연도 폴더 | + | |
| + | # (대소문자 무시, 경로 구분자 혼용을 감안해 \\ 와 / 모두 허용) | ||
| + | if ($src -notmatch ' | ||
| + | |||
| + | | ||
| $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 |
| - | # 동일 파일명 | + | # 목적 파일명 (CSV의 Name 필드 우선, 없으면 src에서 |
| - | $dst = Join-Path $dstDir $_.Name | + | $name = $_.Name |
| - | if (Test-Path $dst) { | + | if ([string]:: |
| - | $h8 = (Get-FileHash $src -Algorithm SHA256).Hash.Substring(0, | + | |
| - | $dst = Join-Path $dstDir (" | + | $dst = Join-Path $dstDir $name |
| + | |||
| + | # 동일 파일명 충돌 시 sha256 prefix로 회피 | ||
| + | if (Test-Path | ||
| + | $h8 = (Get-FileHash | ||
| + | $dst = Join-Path $dstDir (" | ||
| } | } | ||
| - | Move-Item -LiteralPath $src -Destination $dst | + | |
| + | try { | ||
| + | | ||
| + | $cnt_moved++ | ||
| + | } | ||
| + | catch { | ||
| + | $status = " | ||
| + | $cnt_failed++ | ||
| + | } | ||
| - | " | + | |
| - | Add-Content $log -Encoding UTF8 | + | $srcLog = ($src -replace " |
| + | $dstLog = ($dst -replace " | ||
| + | |||
| + | # 로그 형식: time, year_final, src, dst, status | ||
| + | | ||
| + | Add-Content | ||
| } | } | ||
| + | |||
| + | # 요약 출력 | ||
| + | Write-Host (" | ||
| </ | </ | ||
| Line 144: | Line 224: | ||
| 생성 가능 파일: | 생성 가능 파일: | ||
| - | Photos_Backup/_ops/notes/annotations.tsv | + | Photos_Backup\_ops\notes\annotations.tsv |
| 형식: | 형식: | ||
takeoutphotosanitizer/uncertain_reclassification_workflow_guide.1771830708.txt.gz · Last modified: by hyjeong
