Files
UnifyDrive2NAS/PROJECT.md
T

247 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: UnifyDrive2NAS の現状
tags:
- homelab
- UnifyDrive2NAS
status: 方式検討中
---
# UnifyDrive2NAS の現状
> [!info] このファイルの位置づけ
> UnifyDrive2NAS プロジェクトの現状(決定事項・要件・構成・課題)を積み上げていく。運用規約は [[AGENTS]]、ホームラボ基盤は [[homelab/AGENTS|ホームラボ共通基盤]] を参照。
## 今の状態
- **方式検討中。** コード・テストはまだ無い
- リポジトリ: 未作成
## 目的
ホームラボ内の Unify Drive に格納されている画像ファイルを、Synology NAS(`ds923p`)へコピーする。そのための方式を検討して実装する。
## 決定事項
| 項目 | 決定 |
|---|---|
| コピー元 | Unify Drive(`UT2-9EV9`)のストレージ `M.211` 配下(詳細は [[#確認済みの事実]]) |
| コピー先 | NAS `ds923p` の共有フォルダ `homes` 配下 `kazu634/Photos/PhotoLibrary` |
| コピー先のフォルダ構成 | `YYYY/YYYYMMDD/` のフォルダを作り、その中に画像を置く(例: `PhotoLibrary/2026/20261010/`) |
| 実行方法 | **定期実行**。その日に Unify Drive へ格納された分をコピーする(ユーザー判断、2026-10-10) |
| 対象ファイル種別 | **RAW(arw・dng)は含めない。動画(mov・mp4)とスクリーンショット(png)は含める**(ユーザー判断、2026-10-10) |
| コピー対象のフォルダ | `nvme11-admin`(= `M.211`)配下の `PlugBackup`・`iPhone18,1`・`iPad14,9`・`frankel` の**すべて**。**`.samba_recycle` は除く**(ユーザー判断、2026-10-10) |
| 新しいファイルの判定 | **コピー済みの一覧を持ち、まだコピーしていないファイルをコピーする**(案 A。ユーザー判断、2026-10-10)。WebDAV の日時からは格納日が分からないため([[#WebDAV で取れる日時]]) |
| 初回の扱い | **本番開始の前日に初期化だけを行う**。既存のファイルをすべて「コピー済み」として一覧に記録し、コピーはしない。翌日からの定期実行で、一覧に無い新しいファイルだけをコピーする。初期化した日のうち、初期化より後に格納されたファイルは翌日の実行でコピーされる(ユーザー判断、2026-10-10) |
| 実行場所 | **Dagu(`192.168.10.156`)**から `ssh.run` で NAS 上の処理を呼ぶ(ユーザー判断、2026-10-10)。Dagu の方針([[ITProjects/homelab/Projects/Dagu/AGENTS|Dagu]]: Step Type は `shell` / `ssh.run` のみ、スクリプト実体はリモートホスト側の固定パス)に従う |
| Unify Drive の読み方 | **Unify Drive を NAS にマウントする**(ユーザー判断、2026-10-10)。プロトコルは [[#未決事項]] |
| コピー済みの一覧 | **SQLite** に持つ。キーは**コピー元のパス・サイズ・更新日時**(ユーザー判断、2026-10-12)。マウント経由では WebDAV の ETag が取れないため |
| EXIF・動画メタデータの読み取り | **NAS 上の Python 3.8(標準ライブラリのみ)で読む**。純 Python のライブラリ(`exifread` 等)をディレクトリごと配置し、動画(mov・mp4)の作成日時は QuickTime の `mvhd` を自前で読む(ユーザー判断、2026-10-12)。docker(root 相当)は使わない |
| 同名で中身が違うファイル | **両方残す**。中身が同じなら何もしない。違えば連番を付ける(例: `DSC00001_1.JPG`)(ユーザー判断、2026-10-10) |
| コピー元のファイル | **残す**(コピーのみで、消さない)(ユーザー判断、2026-10-10) |
| `YYYYMMDD` の日付 | **EXIF の撮影日時 → 動画のメタデータ(QuickTime の作成日時等)→ ファイルの日時**の順に、取れたものを使う(ユーザー判断、2026-10-10) |
| 動画の日時の優先順 | **Apple の作成日時(`moov/meta`、タイムゾーン付き)→ `moov/mvhd` の作成日時(UTC を JST に変換)**(ユーザー判断、2026-10-12) |
| 隠しファイル | **先頭が `.` のファイル・フォルダはコピーしない**(`.<元の名前>.z<16 進 32 桁>` の書きかけと推定されるファイルを含む)(ユーザー判断、2026-10-12) |
## 要件
### 機能要件
- Unify Drive 上の画像ファイルを NAS の `PhotoLibrary/YYYY/YYYYMMDD/` へコピーする
- コピー先に `YYYY` / `YYYYMMDD` フォルダが無ければ作る
### 非機能要件
- 未定
## 構成(案)
未定。[[#未決事項]] を決めてから書く。
## 外部とのつながり
| 相手 | アドレス | 用途 | 根拠 |
|---|---|---|---|
| Unify Drive `UT2-9EV9` | `192.168.10.200/24`(固定 IP。Web UI `http://192.168.10.200:5055`) | コピー元 | ユーザーが DHCP(旧 `192.168.10.37`)から固定 IP に変更。[実機] 2026-10-10 ping 応答と `:5055` の HTTP 302 を確認 |
| Synology `ds923p` | `192.168.10.201`(DSM `http://192.168.10.201:5000`) | コピー先 | [[homelab/docs/inventory\|インフラ詳細]] |
> [!note] Unify Drive の IP
> 当初は DHCP で `192.168.10.37` だったが、2026-10-10 にユーザーが `192.168.10.200/24` の固定 IP に変更した。[[homelab/docs/inventory|インフラ詳細]] と [[homelab/AGENTS|ホームラボ共通基盤]] の IP 割当に登録済み。
## 確認済みの事実
### コピー元: Unify Drive
[実機] 2026-10-10 踏み台から WebDAV(`https://192.168.10.200:5006/`、`~/.config/unifydrive.netrc` で認証)で一覧を取得して確認。件数・容量・日付は PROPFIND の `getcontentlength` / `getlastmodified`(ファイルの更新日時)による。
- デバイス名は `UT2-9EV9`
- WebDAV のルート直下は `nvme11-admin/`・`Shared Files/`・`public/`・`sharetome/`。Web UI の `M.211` は **`nvme11-admin/`** にあたる(直下のフォルダ名が一致)。`Shared Files`・`public`・`sharetome` は空
- `nvme11-admin/` 直下は `PlugBackup`・`frankel`・`iPhone18,1`・`iPad14,9` と、隠しフォルダ `.samba_recycle`
| フォルダ | 何のバックアップか(推定を含む) | ファイル数 | 容量 | 拡張子 | 更新日時の範囲 |
|---|---|---|---|---|---|
| `PlugBackup/` | Unify Drive に差した SD カードのバックアップ | 5,059 | 211.27 GiB | jpg 4,475 / arw 452 / dng 109 ほか | 2025-11-08〜2026-10-10 |
| `iPhone18,1/iPhone18,1PhotoBackup/all photos/` | iPhone のアプリからの写真バックアップ | 2,241 | 15.75 GiB | jpg 1,061 / heic 536 / jpeg 436 / mov 120 / png 72 / mp4 2 ほか | 2023-10-26〜2026-10-04 |
| `iPad14,9/iPad14,9PhotoBackup/all photos/` | iPad のアプリからの写真バックアップ | 90 | 0.69 GiB | png 82 / jpg 6 / mp4 2 | 2025-09-23〜2026-09-23 |
| `frankel/frankelPhotoBackup/Camera/` | 別端末(`frankel`)の写真バックアップ | 4 | 0.01 GiB | jpg 4 | 2025-12-27〜2026-01-16 |
| `.samba_recycle/` | SMB のごみ箱(削除済みファイル) | 3,889 | 460.02 GiB | arw 3,839 / dng 45 ほか | 2025-11-08〜2026-05-17 |
#### `PlugBackup/` の構成
バックアップ 1 回ごとにフォルダが 1 つできる。フォルダ名の形式は 2 通りある。
| 形式 | 例 | 画像の場所 |
|---|---|---|
| `YYYYMMDDHH` + 連番 3 桁(と推定) | `2026051623001` | `<回>/Generic MassStorageClass/<ボリューム名>/DCIM/<100MSDCF 等>/` |
| `SDCARD1_YYYYMMDD_HH_連番` | `SDCARD1_20261010_11_001` | `<回>/DCIM/100MSDCF/` |
- ボリューム名は `SDCARD1`・`AVPRO SD`・`RICOH GR` の 3 種類を確認。カメラは Sony(`100MSDCF`、`DSC*.ARW`、`PRIVATE/M4ROOT`)と RICOH GR IIIx(`101RICOH`、`R*.DNG`)と推定
- 画像以外に、カメラの管理ファイル(`AVF_INFO/*.bnp|inp|int`、`PRIVATE/` 配下、`.Spotlight-V100/`)とバックアップごとの `.txt` がある
- `2026022819001` と `2026050219001` には Synology のサムネイル用フォルダ `@eaDir/` が混じっている
- `2025102520001`・`2025110304001` には画像が無い(フォルダはあるがファイルは 0 件)
| 回 | 画像のあるフォルダ | 件数 |
|---|---|---|
| `2025102520001` | なし | 0 |
| `2025110304001` | `SDCARD1/DCIM/100MSDCF/`(空) | 0 |
| `2025110806001` | `SDCARD1/DCIM/100MSDCF/` | 821 |
| `2025112401001` | `SDCARD1/DCIM/100MSDCF/` | 40 |
| `2025120719001` | `RICOH GR/DCIM/101RICOH/` | 34 |
| `2026011119001` | `RICOH GR/DCIM/101RICOH/` | 45 |
| `2026022819001` | `RICOH GR/DCIM/101RICOH/` | 182 |
| `2026050219001` | `SDCARD1/DCIM/100MSDCF/` | 56 |
| `2026051623001` | `SDCARD1/DCIM/100MSDCF/` | 1,540 |
| `2026051723001` | `AVPRO SD/DCIM/100MSDCF/` | 1,482(すべて jpg、51.88 GiB) |
| `SDCARD1_20260913_14_001` | `DCIM/100MSDCF/` | 208 |
| `SDCARD1_20261010_11_001` | `DCIM/100MSDCF/` | 600(jpg 300 / arw 300、45.83 GiB) |
#### iPhone / iPad / frankel の構成
- `all photos/` の下は **`YYYY-MM`(月)フォルダ**に分かれている(iPhone は `2023-10`〜`2026-10`、iPad は `2025-09`〜`2026-09`)
- iPhone には `1970-01/` フォルダ(2 件)がある。撮影日時が取れなかったファイルと推定
- iPhone には、拡張子が `z` + 32 桁の 16 進数になっているファイルがある(少なくとも 4 件)。正体は未確認
- 写真のほかに動画(mov / mp4)とスクリーンショットらしい png を含む
#### `.samba_recycle/`(SMB のごみ箱)
- `PlugBackup/` と同じ構成のフォルダの下に、ARW が 3,839 件、合計 460 GiB 残っている。`PlugBackup/` から RAW を消した跡と推定
- コピー対象から外すかどうかは [[#未決事項]] で決める
#### WebDAV で取れる日時
[実機] 2026-10-10、`PlugBackup/SDCARD1_20261010_11_001/DCIM/100MSDCF/` の 600 件で確認。
- 取れるのは `creationdate` と `getlastmodified` の 2 つで、**どちらもカメラで記録した日時と同じ値**(例: `DSC06493.JPG` はどちらも 2026-08-05 11:43:30Z)
- このバックアップは 2026-10-10 11 時に行われたが、ファイルの日時は 2026-08-05〜2026-10-07。**WebDAV の日時からは「Unify Drive に格納された日」は分からない**
#### SMB で取れる日時
[実機] 2026-10-10、`smbclient -m SMB3` の `allinfo` で確認。
- `PlugBackup/SDCARD1_20261010_11_001/DCIM/100MSDCF/DSC06493.JPG` は `create_time`・`write_time`・`change_time` がすべて 2026-08-05 20:43:30 JST で、カメラの日時と同じ。`access_time` だけが 2026-10-10 11:02:11 JST
- **SMB でも「Unify Drive に格納された日」は分からない**(`access_time` は読み出しでも更新されうるので使わない)。新しいファイルの判定は、決定事項どおりコピー済みの一覧で行う
### コピー元への到達手段
[実機] 2026-10-10 踏み台 `bastion2404` から確認。
| ポート | 応答 | 解釈 |
|---|---|---|
| `22` | 閉じている | SSH の標準ポートではない |
| `10000` | SSH(rsa / ecdsa / ed25519 のホスト鍵あり)。認証方式は `publickey,password` | 2026-10-10 にユーザーが Web UI の「Remote assist/SSH」で有効化(ポート `10000`、「LAN access only」・15 分で自動切断)。UI の注意書きでは**管理者アカウントで接続し、root 権限は `sudo`**。また **SSH を有効にするとソフトウェアのサポート対象外になる**(システムを復元すれば戻せる)。踏み台から `kazu634` の鍵認証は `Permission denied` |
| `21` | `220 ZFileShare 2.5.4 ready`。anonymous は `530` | FTP。認証が必要 |
| `139` / `445` | 匿名では `Shared Files` だけが見える(中身は空)。`~/.config/unifydrive.smbauth` で認証すると共有 `Shared Files`・`nvme`・`sharetome`・`External Device-rescuefs` が見える。SMB1 は無効 | **SMB。共有 `nvme` のルートが `nvme11-admin`(= `M.211`)の中身にあたる**(直下に `PlugBackup`・`iPad14,9`・`iPhone18,1`・`frankel`・`.samba_recycle`)。`External Device-rescuefs` は空(容量 0)。[実機] 2026-10-10 確認 |
| `111` / `2049` | 開いている | NFS。エクスポートは `/tmp/zfsv3/share_fake/share`(許可 `*`)の 1 件だけで、名前からダミーと推定 [要確認] |
| `5005`(http)/ `5006`(https) | 認証なしは `401`(`Basic realm="Restricted"`)。`~/.config/unifydrive.netrc` で認証すると PROPFIND に `207` | **WebDAV。一覧の取得に成功**([[#コピー元: Unify Drive]]) |
| `5055` | `302 → /home/`(openresty) | Web UI(My Files) |
| `5056` | openresty(http は 400、https は 404) | 用途不明 |
### コピー先: Synology NAS
[実機] 2026-10-10 ユーザー提供のスクリーンショット(DSM File Station)で確認。
- File Station 上のパスは `homes > kazu634 > Photos > PhotoLibrary`。ファイルシステム上の実パス(`/volume1/homes/kazu634/...` か)は [要確認]
- `PhotoLibrary` には 27 項目あり、見えた範囲は以下
- 年フォルダ: `2020`〜`2026`
- その他のフォルダ: `99999999_ios`・`99999999_misc`・`99999999_tumblr`・`iPad`・`Mobile`
- ファイル: `upload2Flickr.sh`
- 年フォルダの中が `YYYYMMDD` 形式かどうかは、スクリーンショットからは確認できない [要確認]
### NAS 側の実行環境
[実機] 2026-10-12、Dagu の VM から `ssh -i ~/.ssh/id_ed25519_nas kazu634@192.168.10.201` で確認。
- **Dagu → NAS の SSH は鍵で通る**(ポート `22`、ユーザー `kazu634`、`administrators` グループ所属)。NAS のホスト鍵は Dagu の `known_hosts` に登録済み
- DSM 7.4.1(build 90080)
- **マウントの実パスは `/volume1/homes/kazu634/UnifyDrive`**(`$HOME` は `/var/services/homes/kazu634`)。種別は `cifs`、`vers=3.02`、`username=admin`、`uid=1026(kazu634)`・`gid=100(users)` に固定、`file_mode=0777`、`noexec`、`nocase`
- マウント経由の `stat` も、`Modify`・`Change` はカメラの日時(`DSC06493.JPG` は 2026-08-05 20:43:30 JST)。`Birth` は取れない
- 使えるもの: `python3`(3.8.15、標準ライブラリのみで `pip` も無い)・`sqlite3`・`rsync`
- 使えないもの: `exiftool`・`ffprobe`・`perl` は無い
- **docker の制約:** `docker` は `/usr/local/bin/docker` にある(非対話 SSH の `PATH` には入っていない)。ただし `/var/run/docker.sock` は `root:root` の `660` で、`kazu634` からは使えない。`sudo` はパスワードを要求する
- インストール済みのパッケージに `Node.js_v20`・`Node.js_v22`・`Python2`・`ContainerManager` がある
### 純 Python での日時の取得(実現可能性の確認)
[実機] 2026-10-12、NAS 上の Python 3.8.15 + `exifread` 3.5.1(純 Python・依存なし・`Requires-Python >=3.7`)と、QuickTime の atom を読む自前のコードで確認。調査用のファイルは NAS の `/tmp/unify-probe` に置き、確認後に削除した。
**取れた日時の出どころ**(iPhone・iPad・frankel は全件、`PlugBackup` は 3 フォルダから数件ずつ)
| 形式 | 取れたもの | 件数 |
|---|---|---|
| JPG(Sony・RICOH GR・iPhone・iPad・Pixel) | EXIF `DateTimeOriginal` | iPhone 940 / iPad 6 / frankel 4 / `PlugBackup` のサンプルすべて |
| HEIC | EXIF `DateTimeOriginal` | 535 |
| PNG(スクリーンショット) | EXIF `DateTimeOriginal`(`eXIf` チャンク) | iPhone 58 / iPad 82 |
| MOV(iPhone) | `moov/meta` の Apple の作成日時(例 `2025-11-08T20:46:34+0900`、タイムゾーン付き) | 119 |
| MOV・MP4(それ以外) | `moov/mvhd` の作成日時(1904 年起点の UTC 秒を JST に変換) | iPhone mov 1・mp4 2 / iPad mp4 2 |
- MOV では、Apple の作成日時と `mvhd` は 1 秒ほどしか違わない(`mvhd` は書き出し終了時刻の可能性)。Apple の作成日時を優先し、無ければ `mvhd` を使うのがよい
- DJI の MP4 は、`mvhd` を JST にした時刻がファイル名の時刻(`DJI_20250518131016`)と一致した。ただし、カメラによっては現地時刻を UTC として `mvhd` に書くものがあり、その場合は 9 時間ずれる(日付が変わりうる)[要確認]
**日時が取れなかったもの**(すべて iPhone。ファイルの中身を見て、`exifread` の読み落としではなく**日時の情報自体が無い**ことを確認した)
| 種類 | 件数 | 中身 | ファイルの日時(決定事項どおりの代替) |
|---|---|---|---|
| UUID 名の `.jpeg`(`2024-02`〜`2024-03` 等) | 436 | JFIF のみで EXIF 自体が無い | すべて 2024-03-04 15:56:27。**取り込んだ日時であって撮影日ではない** |
| `IMG_*.JPG` | 121 | EXIF はあるが日時のタグが無い(編集・書き出し後と推定) | 個別の日時 |
| `IMG_*.PNG` | 14 | 中身は JPEG(拡張子と中身が違う)。EXIF はあるが日時のタグが無い | 個別の日時 |
| `IMG_2542.HEIC` | 1 | EXIF が無い(XMP はあるが日時は無い) | 個別の日時 |
| `1970-01/IMG_1824.JPG` 等 | 2 | 12 KB ほどで、中身は JPEG を Base64 にしたテキスト(`/9j/4AAQ...`)。画像として壊れている | 2025-03-23 |
**設計に効く事実**
- **拡張子と中身が一致しないファイルがある**(`.PNG` の中身が JPEG)。`exifread` は中身で形式を判定するので、拡張子に頼らず読める
- **先頭が `.` の隠しファイル `.<元の名前>.z<16 進 32 桁>` が 14 件ある**(例: `.IMG_2584.MOV.zb0bad79...`、`.DSC07166.JPG.z6d2802...`)。iPhone からのバックアップの途中のファイルか一時ファイルと推定。**コピー対象から外さないと、書きかけのファイルを取り込むおそれがある**
- iPhone・iPad・frankel の全 2,331 件を読むのに約 78 秒(ほぼ iPhone)。日々の実行では新しいファイルだけを読むので、時間は問題にならない見込み
### コピー先の現状
[実機] 2026-10-12 確認。
- `~/Photos/PhotoLibrary/2026/` には `20260110`〜`20260517` の `YYYYMMDD` フォルダが既にある
- 例として `20260517` には 385 項目があり、**JPG と ARW の両方と `@eaDir`** が入っている。これまで RAW も含めて手作業でコピーしていたと推定。今後は RAW を含めない(決定事項)
## 未決事項
方式を決める前に決める必要がある項目。
- [x] **純 Python で日付が取れるかの実機確認**: 2026-10-12 確認。JPG・HEIC・PNG・MOV・MP4 とも取れる([[#純 Python での日時の取得(実現可能性の確認)]])
- [x] **マウントのプロトコル**: SMB(CIFS)。2026-10-10 にユーザーが DSM の File Station「リモートフォルダのマウント」で `\\192.168.10.200\nvme` を `/home/UnifyDrive`(File Station 上のパス)にマウントした。Unify Drive 側のアカウントは `admin`、「起動時に自動的にマウントする」にチェック。DSM のリモートフォルダのマウントは SMB と NFS のみ対応 [公式] https://www.synology.com/en-global/dsm/7.4/software_spec/file_access (取得日: 2026-10-10)。[実機] 2026-10-10 ユーザー提供の File Station のスクリーンショットで、`home > UnifyDrive` の下に `.samba_recycle`・`frankel`・`iPad14,9`・`iPhone18,1`・`PlugBackup`(12 回分のフォルダ)が見えることを確認。実パスは `/volume1/homes/kazu634/UnifyDrive`([[#NAS 側の実行環境]])
- [ ] **マウントの再起動後の扱い**: 「起動時に自動的にマウントする」は有効にした。実際に NAS の再起動後にマウントし直されるかは未確認 [要確認]
- [x] **Dagu → NAS の SSH 鍵**: 2026-10-12 に登録・ログインを確認([[#NAS 側の実行環境]])
- [x] **Unify Drive の IP 固定とインベントリへの登録**(2026-10-10、`192.168.10.200/24`)
## 課題
- なし([[#未決事項]] を参照)
## 経緯
- 2026-10-10: プロジェクト開始。`AGENTS.md` を tver から流用し、`PROJECT.md` を作成
- 2026-10-10: Unify Drive を DHCP(`192.168.10.37`)から固定 IP `192.168.10.200/24` に変更
- 2026-10-10: 踏み台から WebDAV でコピー元のディレクトリ構成を調査
- 2026-10-12: Dagu → NAS の SSH 鍵を登録。NAS 上の純 Python で撮影日時が取れることを確認
## 確かめ方
未定(実装後に書く)。