MENU

iPhotoの写真・動画&アルバムをNASに移行しました。

ふと思いつき、半年かけて、デスクトップPCのiPhoto(現「写真」アプリ)にローカル保存している写真・動画&アルバムを、NASに移行しました。

NAS(Network Attached Storage)とは、ざっくり言えば遠隔でアクセスできる外付けハードディスク、あるいは自家製のクラウドストレージのようなものです。小型の箱状のデバイスで、自宅やオフィスのネットワークに繋げて設置します。

懐かしみたいときに、昔の写真や動画をスマホでブラウズできるようになりたい!というモチベーションでした。

筆者がiPhotoの写真・動画&アルバムをNASに移行したモチベーション

  • 昔の写真・動画に、いつでもどこでもアクセスできるようになりたい。
  • 実家のデスクトップPCにしか保存していない写真・動画を、バックアップの取りやすいNASに移動しておきたい。
  • 写真・動画の追加やアルバムの作成を、スマホで完結できるようになりたい。
  • iPhoneからAndroidスマホに近々買い換えたいので、Apple依存から少しずつ脱却していきたい。

今後同じようなことをされる方がいるかもしれないと思い、記録として本記事を書きました。iMacのOSが古いので「iPhoto」です。

現「写真」アプリはアルバム情報のファイル出力がなく、データベース管理のみという話を見かけたので、アルバム移行手法のうち、節「3.1. iPhotoから出力:アルバムごとのファイルパス一覧の取得」の手法に関しては、現「写真」アプリでは通用しなさそうです。現「写真」アプリのデータ移行をする場合は、データベースからアルバムごとのファイルパス一覧を出力する手法を検討する必要がありますが、本記事では対象としていません。

なお、本記事は以下を前提としています。

  • NASサーバを構築済みで、移行元のPC(iMacなど)からストレージにアクセスできる。
    • ※NAS以外のストレージ(外付けハードディスクなど)にも移行は可能です。
  • NASクライアント(スマホなど)からNAS上の写真・動画を閲覧できる。
  • NASクライアント(スマホなど)からNAS上のアルバムを閲覧できる。

本記事では、特に章「2. 重複写真の削除」以降において、Pythonスクリプトを多用していますが、節「2.0. 事前準備:NASサーバの端末にログイン・PythonおよびExifToolをインストール」にてPythonインストール方法から紹介していますので、Pythonを使ったことがない方でも参考にしていただけると思います。

筆者

ぜひ、ご参考にどうぞ!!

目次

0. 移行元・移行先の情報

  • 移行元:デスクトップPC(iMac 13,2、2012年製)
    実家に設置してあり、アプリケーション「iPhoto」に写真・動画を取り込み続けて12年以上、全36,031件の写真・動画ファイルをローカル保存しています。環境の詳細は脚注1を参照。
  • 移行先:NASサーバ(Synology DS218、2017年製)
    同じく実家に設置してあります。Synology社は、インターネット経由でNAS上の写真・動画を管理できる「Synology Photos」というアプリケーションを提供しています。環境の詳細は脚注2を参照。
  • 写真・動画閲覧クライアント:スマートフォン(iPhone 12 mini、2020年製)
    同名の「Synology Photos」というSynology社製のクライアントアプリで、インターネット経由でNAS上の「Synology Photos」サーバにアクセスできます。PCのWebブラウザ上でも「Synology Photos」を開いて写真や動画を閲覧できますが、インタフェースはスマートフォン向けアプリとほとんど変わらないため、本記事ではスマートフォン上での写真・動画閲覧を目的と設定します。環境の詳細は脚注3を参照。

1. 写真・動画の移行

1.1. 移行元のフォルダパスを特定(iPhotoのすべての写真・動画を格納している場所)

iPhoto(現「写真」アプリ)上で、適当な1枚を選択した状態で、上部メニューから「ファイル」>「Finderに表示」>「オリジナルファイル」をクリックします。Finderが開き、元データの写真・動画ファイルがある場所を特定することができます。

図1.1. iPhotoの写真・動画の元データをFinder上で表示する

複数のファイルについて同じことをすれば分かりますが、iPhotoではすべての写真・動画のオリジナルファイルが以下のようなパスのフォルダにまとめて格納されています。

移行元のフォルダパス: /Users/<Macのユーザ名>/Pictures/iPhoto Library.photolibrary/Masters

現「写真」アプリでも同様の手順で確認できますが、フォルダパスは上記と異なります。

「Finder」アプリ上で、ファイルパス(またはフォルダパス)をコピーすることができます。ファイルを右クリックしてメニューを表示させた状態で「option」キーを押したままにすると、メニューのうち「”<ファイル名>”をコピー」が「”<ファイル名>”のパス名をコピー」に変わるので、「option」キーを押したままその項目をクリックします。

1.2. NASのマウント

移行元のフォルダを特定したので、次は移行先のフォルダを決定したい所ですが、そのために「Finder」アプリ上でNASの中身にアクセスできるようにしておきます。

いくつか方法があるかと思いますが、今回はNASサーバ上でSambaサーバを立てて、Mac上のSambaクライアントでマウントする方法を採用しました。

初めはSambaではなくWebDAVを利用しようとしましたが、実験的に移行したファイルの権限や最終更新日が変更されてしまったので、WebDAVは採用しませんでした。

1.2.1. NASサイド:Sambaサーバの起動(Synology DSM)

Synology社製のNASサーバでは、GUI(DSM)上からSambaサービスを起動できます。
以下のURLをWebブラウザで開いて、NASサーバのDSMにアクセスします。管理者権限を持つユーザでログインすることで、アプリ「コントロールパネル」を開くことができます。
http://QuickConnect.to/<NASサーバに設定したQuickConnect ID>

アプリ「コントロールパネル」 > メニュー「ファイルサービス」 > タブ「SMB」を開き、「SMBサービスを有効化」のチェックボックスを付けて「適用」することで、起動が完了します。

図1.2. Synology DSM上でのSambaサービスの起動

1.2.2. Macサイド:Sambaクライアントによるマウント

Mac上で「Finder」アプリを開き、上部メニューから「移動」>「サーバへ接続」をクリックします。「サーバアドレス」の入力を求められるので、上の図1.2.に指示のある通り、以下のURLを入力します。
smb://diskstation

図1.3. Finderから「サーバへ接続」

接続できればユーザ認証を求められるので、NASユーザのログインIDとパスワードを入力します。これにより、「Finder」上で、以下のようなフォルダパスとしてNASの中身にアクセスできるようになります。
/Volumes/<NASサーバ上のトップフォルダ>

図1.4. Finder上でNASの中身にアクセスできる

私の環境では、iMacとNASサーバが同じネットワークにある(同じWi-Fiルータに接続している)ので、上記手順でアクセスできました。
別のネットワークにある場合は、「Tailscale」といったサービスを利用して安全なVPN網を構築することで、インターネット経由でマウントすることができるはずです。本記事では「Tailscale」の設定手順は紹介しませんが、その場合に「Finder」から接続するサーバアドレスは以下です。
smb://<Tailscaleで発行したNASサーバのIPアドレス>

1.3. 移行先のフォルダパスを決定(すべての写真・動画を新しく格納する場所)

「Finder」上でNASの中身をブラウズできるようになったので、移行先のフォルダパスを決めておきます。

Synology社製の写真・動画管理サービス「Synology Photos」が管理する写真・動画ファイル用フォルダは、デフォルトで/volume1/homes/<NASユーザのID>/Photos/となっています。そこに今回の移行用のフォルダを作成して、以下のパスのフォルダを移行先とすることとしました。

移行先のフォルダパス: /volume1/homes/<NASユーザのID>/Photos/iPhoto_backup_2025_04

1.4. NASへの写真・動画の全コピー

移行元と移行先が決まったので、実際にデータをコピーします。

対象のデータサイズが大きいことから、全てコピーし切るまで10時間を超えることが予想できます。その中で万一、途中で処理が落ちてしまったら最初からやり直しになってしまいます。また、処理が完了したあとに、本当に全てのファイルが漏れなく破損なく複製できているのかを、大切なファイルだからこそ確認したいです。

そこで、iMacの画面上でコピペ作業をするのではなく、ターミナル上でrsyncコマンドを使ってコピーしました。その手順は以下の別記事にまとめましたので、ご参照ください。

1.5. NASの写真・動画管理アプリでの閲覧チェックと対処

今回の移行の最終目的は、Synology社が提供するスマートフォンアプリ「Synology Photos」上で、NAS上の写真・動画ファイルを閲覧することです。「Synology Photos」は多くの形式の写真・動画ファイルに対応していますが、一部形式のファイルは閲覧できない可能性があります(詳細は「Synology Photos」の技術仕様4を参照ください)。したがって、ファイル形式ごとに問題なく閲覧できるかどうかを確認する必要があります。

1.5.1. コピーしたファイルの拡張子一覧の確認

ファイル形式の全容を把握するため、まずは拡張子一覧を確認します。

iMac上で「ターミナル」アプリを開き、以下のコマンドを実行します。これにより、今回移行したファイルについて、拡張子とその件数を一覧で確認できます。

COPY_SOURCE_PATH='<移行元のフォルダパス>'
find "$COPY_SOURCE_PATH" -type f | awk -F/ '{print $NF}' | awk -F. '{print $NF}' | sort | uniq -c | sort -r

移行”先”ではなく移行”元”としているのは、移行後にNASの機能によって「@eaDir」といったフォルダの中に、サムネイルなどのメタファイルが新規生成されてしまっていたためです。移行データ以外の拡張子をカウントしないようにしています。

筆者の環境では、以下のようになりました。

表1.1. 筆者が移行したファイルの拡張子一覧

拡張子ファイル件数「Synology Photos」対応
JPG20,614○:JPGファイルはそのまま閲覧可能。
jpg12,983○:JPGファイルはそのまま閲覧可能。
PNG1,502○:PNGファイルはそのまま閲覧可能。
MP4263○:MP4ファイルはそのまま動画再生可能。
MOV182○:MOVファイルはそのまま動画再生可能。
mov133○:MOVファイルはそのまま動画再生可能。
png122○:PNGファイルはそのまま閲覧可能。
mp475○:MP4ファイルはそのまま動画再生可能。
AVI72△:デバイスによっては動画再生できない可能性あり。
GIF37○:GIFファイルはそのまま閲覧可能。
MPG19△:デバイスによっては動画再生できない可能性あり。
jpeg12○:JPEGファイルはそのまま閲覧可能。
m4v11△:デバイスによっては動画再生できない可能性あり。
tif4○:TIFファイルはそのまま閲覧可能。
JPEG2○:JPEGファイルはそのまま閲覧可能。

※HEIF形式・HEVC形式で圧縮された写真・動画をWebブラウザで再生する場合は、別途アドオンのインストールが必要な場合あり[4]

なお、特定の拡張子を持つファイルの一覧を確認したい場合は、「ターミナル」アプリで以下のコマンドを実行します。

COPY_SOURCE_PATH='<移行元のフォルダパス>'
TARGET_EXT='<対象の拡張子(ドットより右側)>'
find "$COPY_SOURCE_PATH" -type f -name "*.$TARGET_EXT"

1.5.2. 不要なファイルの削除

表1.1.の通り、拡張子単位で削除すべき不要なファイルはありませんでした。

1.5.3. 閲覧できない可能性のあるファイルの閲覧チェック

表1.1.において「△:デバイスによっては動画再生できない可能性あり。」となった3種の拡張子「AVI」「MPG」「m4v」の動画ファイルについて、それぞれクライアントアプリ上で再生テストを実施しました。結果としては、全種類問題なく再生できました(念のため、PCのWebブラウザ上でも再生できることを確認しました)。

これで、移行したすべての写真・動画が、変換などすることなくクライアントアプリ上で閲覧できることがわかりました。

2. 重複写真の削除

節「1.5. NASの写真・動画管理アプリでの閲覧チェックと対処」で閲覧チェックをする中で気づいたのですが、かなりの枚数の写真が重複していることがわかりました。重複した写真には以下の2種類があり、どうやらiPhotoが気を利かせて写真を複製してくれたものが大半のようです。

  • 顔トリミング写真 … 顔の部分だけをトリミングした写真
  • 回転リサイズ写真 … オリジナル画像を回転させたりリサイズさせた写真

結果として、保有している35,276枚の写真のうち、実に20%に当たる6,956枚が複製された写真でした。これらの複製写真をそのままにしておくのは昔の写真を懐かしむ上でかなりのノイズになりますので、この機会に全て削除することとしました。

本来の目的である、iPhotoの写真・動画のNASへのコピーには関係ありませんので、必ずしもこの工程は必要ありませんが、著者の『自己満』として実施しました。恐らくiPhotoの「顔認識」などの機能に因るもので、重複画像の生成日は2008~2015年頃に集中していたので、同様の方がいるかもしれません。

2.0. 事前準備:NASサーバの端末にログイン・PythonおよびExifToolをインストール

2.0.1. NASサーバの端末にログイン

本章以降では、NASサーバ上で直接作業していきます。スクリプトで画像を開いたり、ファイルを移動したりする上では、Samba経由でiMacからファイルを開くよりも、直接NASサーバ上で操作するほうが効率的だからです。

Synology社製のNASサーバの場合は、「ターミナル」や「コマンドプロンプト」のような自身の端末にログインするGUIのアプリケーションは用意されていないので、外部からSSHログインする必要があります。

Synology社製のNASサーバにSSHログインするためには、DSMの画面上でSSHサービスを有効化しておく必要があります。アプリ「コントロールパネル」 > メニュー「端末とSNMP」 > タブ「端末」を開き、「SSHサービスを有効化する。」のチェックボックスを付けて「適用」することで、SSHログインを許可します。SSHサービスのポート番号もこの画面で設定できます。

NASサーバと同じネットワークに接続している状態で、Macの「ターミナル」アプリやWindowsの「PowerShell」アプリを開き、以下のコマンドを実行することで、NASサーバにログインできます。パスワードが求められるので、ユーザ名に対応するパスワードを入力してログインします。

ssh <NASサーバのユーザ名(管理者)>@<NASサーバのIPアドレス> -p <NASサーバ上のSSHサービスのポート番号>

Synology社製のNASサーバのIPアドレスは、DSMの画面上で確認できます。アプリ「コントロールパネル」 > メニュー「情報センター」 > タブ「ネットワーク」を開き、項目「IPアドレス」の値を確認します。

「Tailscale」といったサービスを利用して安全なVPN網を構築することで、インターネット経由でSSH接続することも可能です。本記事では、詳細は割愛します。

2.0.2. NASサーバにPythonをインストール

本章以降では、複雑なファイル操作をするためにPythonスクリプトを実行していきます。そのため、NASサーバにPythonをインストールします。

Synology社製のNASサーバ上に新しいバージョンのPythonをインストールする場合は、DSMの画面上で操作して、サードパーティのコミュニティ「SynoCommunity」を別途追加する必要があります。

  1. DSMに管理者ユーザでログインする。
  2. 「パッケージセンター」アプリを開く。
  3. 「設定」ボタン>「パッケージソース」タブ>「追加」ボタンをクリックする。
  4. 以下を入力して、「OK」ボタンを押す。
    • 名前:SynoCommunity
    • 場所:https://packages.synocommunity.com/
  5. 「パッケージセンター」アプリのサイドメニューに「コミュニティ」が追加されるので、クリックする。
  6. メニュー内から利用したいPythonのバージョンをインストールする。
  7. SSH接続し、以下のコマンドでPythonが実行できることを確認する。(xxはインストールしたバージョン。pythonコマンドだと、Synology公式の古いバージョンが実行される。)
    python3.xx -V

2.0.3. NASサーバにExifToolをインストール

撮影日時などの写真・動画のメタデータを取得するために、「ExifTool」というツールをNASサーバにインストールします。以下は、Synology社製のNASサーバの場合の手順です(こちらのコミュニティの記事を参考にしました5)。

  1. ExifToolの公式サイトから最新バージョンのTAR.GZファイルImage-ExifTool-xx.xx.tar.gzをダウンロードする。
    https://exiftool.org/index.html
  2. NASサーバ上の適当なフォルダにImage-ExifTool-xx.xx.tar.gzを格納する。
  3. NASサーバの端末に管理者ユーザでSSH接続後、以下のコマンドを実行してTAR.GZファイルを解凍する。
    cd <TAR.GZファイルを格納したフォルダ>
    tar xzvf Image-ExifTool-xx.xx.tar.gz
  4. TAR.GZファイルは、以下のコマンドで削除して問題ない。
    rm Image-ExifTool-xx.xx.tar.gz
  5. 以下のコマンドを実行してエラーになることで、アプリケーションフォルダに既存のExifToolが存在しないことを確認する。
    ls /usr/share/applications/ExifTool
  6. 解凍されたフォルダを、以下のコマンドでアプリケーションフォルダに移動する。
    mv ./Image-ExifTool-xx.xx /usr/share/applications/ExifTool
  7. 以下のコマンドを実行することで、ExifToolを格納したフォルダを、シェル設定ファイル/etc/profileのPATHに追加する(パスワードを求められたらログインしている管理者ユーザのパスワードを入力)。
    sudo sed -i.bak 's|^PATH=.*|&:/usr/share/applications/ExifTool|' /etc/profile
  8. 修正前後が想定通りであることを確認する(PATHから始まる行の末尾にExifToolを格納したフォルダが追記されている)。
    diff -u /etc/profile{.bak,}
  9. バックアップされたファイルを削除する
    sudo rm /etc/profile.bak
  10. SSH接続を切断して、新しくSSH接続し直し(修正した/etc/profileがSSH接続時に読み込まれる)、以下のコマンドがエラーなく実行できることを確認する。
    exiftool

DSMのアップデートにより、アプリケーションフォルダや/etc/profileがリセットされる場合があるようです。その場合は、本項の手順をやり直してください。

2.1. すべての写真・動画のファイルパス一覧を作成

複製写真を特定する準備として、まずは移行した全ての写真・動画のファイルパス一覧を作成します。

端末上で以下のコマンドを実行し、移行先フォルダに格納された全ファイルのファイルパス一覧をCSVとして作成します。(次節以降で実行するスクリプトに読み込ませるために1列のCSVとしておく。)

cd '<適当な作業フォルダ>'
COPY_DESTINATION_PATH_ON_NAS='<移行先のフォルダパス(NAS上)>'
find "$COPY_DESTINATION_PATH_ON_NAS" -type f > ./file_paths_list.csv
sed -i '1s/^/file_paths\n/' ./file_paths_list.csv  # 列ヘッダー「file_paths」を追加

中身を確認するとわかりますが、Synology社製のNASの場合は、「@eaDir」といったフォルダや「.DS_Store」といったファイルが管理用のメタデータとして自動生成されていて、写真・動画以外にそれらのファイルも拾ってしまっています。よって、それらの文字列を含む行をすべて削除しておきます。

sed -i '/@eaDir/d' ./file_paths_list.csv
sed -i '/\.DS_Store/d' ./file_paths_list.csv

2.2. 顔トリミング写真のファイルパス一覧を作成

複製写真のうち「顔だけトリミングされた写真」については、ファイルパス一覧と実際の写真を見比べることで、ファイル名が以下の命名規則になっていることがわかりました。
<元ファイル名>_face<連番半角数値>.jpg

よって、以下のコマンドを実行することで、顔トリミング写真のファイルパス一覧を作成することができます(全36,031件の写真・動画のうち2,279件)。このファイルに記載されているパスの写真はあとで削除するので、保管しておきます。

grep '_face' ./file_paths_list.csv > ./images_to_remove_as_face_trimmed.txt

2.3. すべての写真・動画のファイルパス一覧に撮影日時情報を付与

さて、次節では残る33,752件の写真・動画から「回転リサイズ写真」を特定しますが、そのための事前準備として各写真の「撮影日時」を特定しておく必要があります。なぜなら、オリジナル写真とその複製と見なせる複数の写真を特定できたとして、そのうちどれがオリジナル写真であるかを特定するために、撮影日時の情報が必要だからです。「オリジナル写真は常に複製写真の中で最も撮影日時が古い」という基準でオリジナル写真を特定します。

いくつかの複製写真を実際に確認することで、複製写真の撮影日時には複製したときの日時が登録されていることがわかりました。複製写真の撮影日時がオリジナルと全く同時であるケースもあるのですが、サイズなどの品質が全く同じケースがほとんどであったので、その場合は本来のオリジナル写真のほうを削除しても問題がないと判断しました。

以下の記事で紹介しているPythonスクリプトextract_image_taken_datetime.pyを実行することで、各写真・動画の撮影日時を取得することができます。

33,752件の写真・動画ファイルに対して実行するのに、35分ほどかかりました。

生成されたファイルfile_paths_list_with_image_taken_datetime.csvに対して、以下のコマンドを実行して、顔トリミング写真を除外しておきます。

grep -v '_face' ./file_paths_list_with_image_taken_datetime.csv > ./file_paths_list_with_image_taken_datetime_without_faces.csv
file_paths,datetime_tag_by_exiftool,datetime_by_exiftool,datetime_aware_iso8601_extended,datetime_local_unix
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/29/20121229-195439/IMG_0395.PNG,File:FileModifyDate,2012-12-05 22:46:41+09:00,2012-12-05T22:46:41.000000+09:00,1354715201.000000
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/29/20121229-195439/IMG_0401.PNG,File:FileModifyDate,2012-12-05 22:48:28+09:00,2012-12-05T22:48:28.000000+09:00,1354715308.000000
:

2.4. 回転リサイズ写真のファイルパス一覧を作成

2.4.1. 「複製された写真っぽい」組み合わせを絞り込む

33,752件の写真・動画を全て分析して「回転リサイズ写真」を見つけるのは、現実的には不可能です。よってまずは、「複製された写真っぽい」組み合わせを33,752件の中から絞り込み、その組み合わせの中で回転リサイズ写真を見つける方針をとります。

ファイルパス一覧と実際の写真を見比べていくと、ほとんどの複製写真はオリジナル写真のファイル名と同じファイル名であったり、末尾に「_1024」などの文字列が追加されていたりする場合がほとんどです。よって、「ファイル名が似ているファイル同士」を「複製された写真っぽい」組み合わせとしてグルーピングしていきます。

以下の記事で紹介しているPythonスクリプトgroup_file_paths_list_by_its_name.pyを実行することで、各ファイルのグループを取得できます。

ファイルgrouped_file_paths_list.csvが生成されます。

file_paths,datetime_tag_by_exiftool,datetime_by_exiftool,datetime_aware_iso8601_extended,datetime_local_unix,group,file_name
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012610/animal928-img600x380-1320574493ftqrpo80714.jpg,File:FileModifyDate,2012-03-04 21:54:48+09:00,2012-03-04T21:54:48.000000+09:00,1330865688.000000,animal928-img600x380-1320574493ftqrpo80714,animal928-img600x380-1320574493ftqrpo80714.jpg
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012120/animal928-img600x380-1320574493ftqrpo80714.jpg,File:FileModifyDate,2012-03-04 21:54:57+09:00,2012-03-04T21:54:57.000000+09:00,1330865697.000000,animal928-img600x380-1320574493ftqrpo80714,animal928-img600x380-1320574493ftqrpo80714.jpg
︙

33,752件の写真・動画ファイルに対して実行するのに、3分40秒ほどかかりました。

(補足)ファイル名が似ていない重複写真のグルーピング方法

同じ写真・動画を複数のプラットフォームで管理していたところをまとめるなどのケースにおいて、複製写真がオリジナル写真とまったく異なるファイル名になっている場合があります。例えば、OneDriveに写真をアップロードすると、独自の命名則でファイル名が書き換わってしまうことがあり、元のスマホで管理していた写真と合わせたときに、同じ写真なのに別のファイル名になるといった事態が発生します。

こういった場合は、写真・動画ファイルのメタデータが活用できる可能性があります。ファイル名が変わってしまっても、例えばEXIF:UserCommentEXIF:DateTimeOriginalMakerNotes:PhotoIdentifierといったメタデータタグの値は、オリジナル写真から変わっていない可能性があります。

ファイル名でグルーピングする方法で特定できない複製写真がある場合は、写真・動画ファイルのメタデータタグをグループとして、次項「2.4.2. 回転リサイズ写真のファイルパス一覧を作成」の比較を実施してみると特定できるかもしれません。

複数ファイルのメタデータの値を一覧で確認したい場合は、以下の記事で紹介しているリポジトリextract_image_taken_datetimeに同梱されているPythonスクリプトread_exiftool_values_of_files.pyをご活用ください。

2.4.2. 回転リサイズ写真のファイルパス一覧を作成

「複製された写真っぽい」グループを作ることができたので、グループ内の写真を総当たりで比較して、回転リサイズ写真を特定していきます。片方の写真を回転およびリサイズをしたときに、もう一方の写真との「Perseptual Hash」値の差分が10以下である場合は、回転リサイズ写真であると見なしています(この10という値は実験的に決めています)。

総当たりと言いつつ、たとえばグループ内の「写真Aと写真B」および「写真Aと写真C」がそれぞれ回転リサイズ写真と判別された場合は、自動的に「写真Bと写真C」も回転リサイズ写真と見なして比較は実施しないので、その部分で効率化は実施しています(「UnionFind」と呼ばれるアルゴリズム)。

以下の記事で紹介しているPythonスクリプトfind_duplicated_images.pyを実行することで、回転リサイズ写真を特定できます。

これにより、回転リサイズ写真のファイルパス一覧not_oldest_duplicated_images.txtが取得できます。(撮影日時を用いて、回転リサイズ写真のうち最も古いオリジナル写真を除いたファイルパス一覧が出力されています。)

6,910グループに割り当てられた15,956ファイルの処理に約3時間11分かかりました。結果として、全33,752件の写真・動画ファイルのうち、4,677件が回転リサイズ写真でした。

2.5. 削除対象のファイルパス一覧の確認

以下の2つの削除対象のファイルパス一覧を作成しました。この一覧を元に、節「3.3. 削除対象の重複写真ファイルを削除」にて対象のファイルを削除します。すぐに削除しない理由は、この削除対象のファイルのうちどれかがアルバムに含まれている場合に調整が必要だからです。

  • 顔トリミング写真(2.1.節): images_to_remove_as_face_trimmed.txt
  • 回転リサイズ写真(2.4.節): not_oldest_duplicated_images.txt

3. アルバムの移行

筆者はイベントごとの写真をiPhotoのアルバムで管理していて、全部で115件のアルバムを作成していました。各アルバムには4~1500枚の写真が登録されています。これを手動で一枚一枚移行するのは不可能なので、iPhotoから「アルバムごとのファイルパス一覧」を取得し、その一覧を元に、NASの写真管理サービス「Synology Photos」上にアルバムを再現します。

3.1. iPhotoから出力:アルバムごとのファイルパス一覧の取得

iPhotoのアルバム情報はデータベースで管理されていると同時に、アルバム情報などを外部サービスと連携するためにAlbumData.xmlというXMLファイルにも定期的に出力されます。よって、このXMLファイルを解析することで「アルバムごとのファイルパス一覧」を取得することができます。

現「写真」アプリでは、AlbumData.xmlは廃止されているようです(APIなどで外部サービスと連携できるため)。よって、データベースから直接、またはAPIに接続して、アルバムごとのファイルパス一覧を取得する必要があります(本記事では扱いません)。

以下のリポジトリのスクリプトparse_iphoto_album_data_xml.pyを実行します。詳細な実行方法は、リポジトリのREADME.mdを参照してください。

NASサーバへの最新のPythonのインストール方法は項「2.0.2. NASサーバにPythonをインストール」を参照してください。本スクリプトはNAS上ではなくても(例えばiMac上でも)動作します。

これにより、フォルダiphoto_album_composition直下に、アルバムごとに1ファイルずつ、ファイルパス一覧のテキストファイルが生成されます。

$ ls -l ./iphoto_album_composition/
total 2320
-rwxrwxrwx+ 1 u-man-lab users    122 Jul 11 23:54  000008_Regular_最後の読み込み.txt
-rwxrwxrwx+ 1 u-man-lab users  55731 Jul 11 23:54 '002519_Regular_ハワイ旅行 2010 8月.txt'
︙

3.2. NASに入力:ファイルパス一覧に基づきアルバムを作成

3.2.1. アルバム作成方針

Synology社製の写真管理サービス「Synology Photos」においてアルバムを作成する方法は1つのみで、アプリ画面上で写真や動画を1つずつ選択して作成するしかなく、ファイルパス一覧からアルバムを作成する機能は存在しません。

アルバム情報はNASサーバ上のデータベースに格納されているので、ファイルパス一覧をデータベースに直接書き込むことも検討しました。しかし、データベースの中身を確認したところ、アルバムが一カ所で管理されているようなシンプルな作りではありませんでした。ちゃんと解析をすればアルバムの書き込みを実装できるかもしれませんが、万が一システム構成に矛盾を作ってしまった場合は取り返しが付かなくなるので、断念しました。

よって、アプリ画面の操作によりファイルパス一覧に基づくアルバムを作成しなければなりません。そこで着目したのが、「Synology Photos」の「フォルダ表示」機能と「一括操作」機能です。「Synology Photos」では、iPhotoのように「タイムライン表示」で時系列に写真・動画を表示する機能の他に、ファイルエクスプローラやFinderのように、サーバ上のフォルダ構成で表示する「フォルダ表示」機能が存在します。

図3.1. タイムライン表示

そして、タイムライン表示でもフォルダ表示でも、アプリ画面に表示されている写真・動画を複数選択して「一括操作」をすることができます。その操作メニューの中には「アルバムに追加」も存在します。

図3.2. フォルダ表示(複数選択して一括操作)

したがって、アルバムごとのファイルパス一覧に記載されている写真・動画ファイルを、移動して一つのフォルダに集めることができれば、そのフォルダ内の全写真・動画を選択して1つのアルバムを作成することができます。注意点として、複数選択時にサブフォルダを選択することはできないので、1つのアルバムにまとめたい写真・動画ファイルは特定のフォルダの「直下」にすべて配置する必要があります。

3.2.2. アルバムごとのファイルパス一覧をNAS向けにローカライズ

各アルバムに属する写真・動画ファイルを特定フォルダに移動するため、まずはアルバムごとの写真・動画ファイルをNAS上で特定します。

節「3.1. iPhotoから出力:アルバムごとのファイルパス一覧の取得」でiPhotoから取得した「アルバムごとのファイルパス一覧」のテキストファイル群は、iPhotoがインストールされているiMac上のパスが記載されています。よって、NASサーバ上のパスに置換する必要があります。以下のコマンドを実行することで、アルバムごとのファイルパス一覧内のファイルパスを一括で置換できます。

WORKING_DIR='./iphoto_album_composition_for_nas'
cp -r ./iphoto_album_composition "$WORKING_DIR"  # テキストファイル群を作業用にコピー

COPY_SOURCE_PATH='<移行元のフォルダパス(iMac上)>'
COPY_DESTINATION_PATH='<移行先のフォルダパス(NAS上)>'
find "$WORKING_DIR" -type f -print0 | xargs -0 sed -i "$(printf 's|%s|%s|g' "$COPY_SOURCE_PATH" "$COPY_DESTINATION_PATH")"

また、不要なアルバムに対応するテキストファイルを削除します。筆者の場合は以下のテキストファイルを削除しました。

rm "${WORKING_DIR}\000008_Regular_最後の読み込み.txt"
rm "${WORKING_DIR}\012281_Regular_プリント.txt"

3.2.3. 各アルバムの写真・動画ファイルを個々のフォルダ直下に移動

NAS向けにローカライズしたアルバムごとのファイルパス一覧を用いて、アルバムごとの特定フォルダに、構成する写真・動画を集めます。写真・動画ファイルを移動するだけならシェルスクリプトで実行できますが、万が一のときに元の状態に戻せるようにしたいので、Pythonスクリプトで実行します。

まず、以下のコマンドでアルバムの写真・動画を格納するフォルダを作成します。

COPY_DESTINATION_PATH='<移行先のフォルダパス(NAS上)>'
mkdir "${COPY_DESTINATION_PATH}/albums"

次に、以下の記事で紹介しているPythonスクリプトmove_target_files_into_a_folder.pyを実行し、対象の写真・動画ファイルをアルバムごとのフォルダに移動します。

設定したフォルダに、アルバムごとの写真・動画を格納したフォルダが生成されていることを確認します。

$ ls -l "${COPY_DESTINATION_PATH}/albums"
total 0
drwxrwxrwx+ 1 u-man-lab users 102046 Nov  1 19:31 '002519_Regular_ハワイ旅行 2010 8月.txt'
drwxrwxrwx+ 1 u-man-lab users   8240 Nov  1 19:30  002521_Regular_名称未設定アルバム.txt
︙
$ ls -l "${COPY_DESTINATION_PATH}/albums/002519_Regular_ハワイ旅行 2010 8月.txt"
total 2037708
-rwxrwxrwx+ 1 u-man-lab users  2619990 Aug 21  2009 'volume1=homes=u-man-lab=Photos=iPhoto_backup_2025_04=2012=12=30=20121230-012150=0001BestPhoto.jpg'
-rwxrwxrwx+ 1 u-man-lab users  2133801 Feb 12  2009 'volume1=homes=u-man-lab=Photos=iPhoto_backup_2025_04=2012=12=30=20121230-012150=0002BestPhoto.jpg'
︙
トラブルシューティング:1つの写真・動画が複数のアルバムに含まれている場合の対処

1つの写真・動画が複数のアルバムに含まれている場合、以下のようなエラーが発生します。このエラー内容はのちほど項「3.2.7. 複数のアルバムに共通する写真を手作業で登録」でも使うので、テキストを保存しておきます。

2025-11-01 17:17:32,565 [ERROR] __main__: Script aborted because some errors happened while reading TXTs.
  + Exception Group Traceback (most recent call last):
  |   File "/volume1/homes/u-man-lab/files/move_target_files_into_a_folder.py", line 716, in __move_target_files_into_a_folder
  |     txt_path_to_listed_paths = __read_input_txts(
  |                                ^^^^^^^^^^^^^^^^^^
  |   File "/volume1/homes/u-man-lab/files/move_target_files_into_a_folder.py", line 622, in __read_input_txts
  |     raise ExceptionGroup('Some errors happened while reading TXTs.', exceptions)
  | ExceptionGroup: Some errors happened while reading TXTs. (442 sub-exceptions)
  +-+---------------- 1 ----------------
    | ValueError: Path "/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012202/NEC_0005.JPG" appears in multiple files.: "/volume1/homes/u-man-lab/files/iphoto_album_composition_for_nas/002519_Regular_ハワイ旅行 2010 8月.txt", "/volume1/homes/u-man-lab/files/iphoto_album_composition_for_nas/002521_Regular_名称未設定アルバム.txt", "/volume1/homes/u-man-lab/files/iphoto_album_composition_for_nas/002576_Regular_名称未設定アルバム 2.txt"
    +---------------- 2 ----------------
︙

写真・動画がどれか一つのアルバムにのみ含まれていれば良い場合は、それ以外のアルバムのTXTファイルから該当ファイルの行を削除し、再実行します。

一方、記載されている全てのアルバムに含まれている必要がある場合は、どれか一つ以外の全てのアルバムのTXTファイルにおいて、該当ファイルの行をダミーファイルに修正します。以下は、1つ目のアルバムのフォルダに本来の写真を移動し、残り2つのアルバムのフォルダにダミーファイルを格納させる場合の例です。

︙
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012202/NEC_0005.JPG
︙
︙
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012202/NEC_0005.dummy
︙
︙
/volume1/homes/u-man-lab/Photos/iPhoto_backup_2025_04/2012/12/30/20121230-012202/NEC_0005.dummy2
︙

エラーに記載されている全ての写真・動画ファイルについて同様に処理をしたら、以下のコマンドにより、TXTファイル群から必要なダミーファイル一覧を取得した上でダミーファイルを実際に作成します。

WORKING_DIR='./iphoto_album_composition_for_nas'
grep -r '\.dummy' "$WORKING_DIR" | cut -d':' -f2- | tr -d '\r' | xargs -d '\n' touch

再度、スクリプトmove_target_files_into_a_folder.pyを実行し、エラーなく完了することを確認します。移動されたダミーファイルは、写真管理サービスの画面からは閲覧することができないので、のちほど項「3.2.7. 複数のアルバムに共通する写真を手作業で登録」で本来の写真を手動登録していく必要があります。

3.2.4. 移動した写真・動画ファイルのインデックス作成完了を確認

「Synology Photos」が管理しているフォルダ配下にファイルを格納したり移動すると、自動的に再インデックスが開始されます。移動したファイルが多いと再インデックスにも時間がかかります(約18,000ファイルを再インデックスするのに半日以上かかりました)。

トラブルシューティング:写真・動画が正しく表示されない

時間が十分に経っても、一部の写真が画面上に表示されない、または表示されても以下のようにグレーのサムネイル表示になり、クリックしても画像が正しく表示されない、という事象があります。これは、なんらかの理由で再インデックスが中断されてしまったものと思われます。

図3.3. 再インデックス失敗アイコンと写真を開いたときの表示

まずは以下の手順で、再インデックスを手動実行してみます。

  1. 以下のURLをWebブラウザで開いて、管理者権限を持つユーザでNASサーバのDSMにログインします。
    http://QuickConnect.to/<NASサーバに設定したQuickConnect ID>
  2. 画面上部のタスクバーの右のほうに、タスクマネージャーが表示されていれば、クリックします。タスクマネージャーに「メディアインデックス付け」が進行中表示であれば、全てが完了してから、写真が正常に表示できていないか再度確認します。タスクマネージャーの表示がなければ、次の手順に進みます。
図3.4. タスクマネージャー上のインデックス進捗状況表示
  1. アプリ「コントロールパネル」を開きます。
  2. メニュー「サービスにインデックスを付けています」を開きます。
  3. 「再インデックス」ボタンをクリックします(ボタンがグレーアウトされている場合は、再インデックスが実行中です)。
  4. ボタンがグレーアウトし「メディアファイルのインデックス処理中」と表示されます。再びボタンが有効になれば、再インデックス完了です。写真が正常に表示できていないか再度確認します。
図3.5. 再インデックス化中の画面表示

手動の再インデックスを実施しても正常に写真が表示されない場合は、表示されない写真・動画ファイルが格納されているフォルダを丸ごと、一時的に別のフォルダに移動してから、元のフォルダに戻します。これにより、「Synology Photos」に新しいファイルが格納されたと認識してもらい、自動的な再インデックスを開始させます。

端末上のコマンドで、別のフォルダに移動してから戻す場合の処理の例は、以下の通りです。

PARENT_FOLDER_PATH='<移行先のフォルダパス(NAS上)>/albums/'
TARGET_FOLDER_NAME='002521_Regular_名称未設定アルバム.txt'  # 移動対象のフォルダを限定したほうが、再インデックスの時間が短縮されます。
TEMP_FOLDER_PATH='/volume1/homes/u-man-lab/files/tmp_folder/'
ls -ld "${PARENT_FOLDER_PATH}${TARGET_FOLDER_NAME}" "${TEMP_FOLDER_PATH}"

mv "${PARENT_FOLDER_PATH}${TARGET_FOLDER_NAME}" "${TEMP_FOLDER_PATH}"
# 1分ほど時間を空ける
mv "${TEMP_FOLDER_PATH}${TARGET_FOLDER_NAME}" "${PARENT_FOLDER_PATH}"

3.2.5. 個人アルバムのフォルダを対象ユーザのフォルダに振り分け

iPhoto上では家族全員が同じライブラリに個々人の写真・動画を取り込んで、個々人のアルバムを作成していたので、すべての写真・動画・アルバムがごちゃ混ぜになっています。例えば、筆者が個人的に保存した写真や作成したアルバムを、家族全員が見られる状態になっています。

「Synology Photos」では、NASのユーザごとのプライベートな写真・動画ライブラリ「個人スペース」が用意されていて、個人スペースは別のユーザからは見えません。

よって、この機会に個々人のアルバムフォルダを、家族それぞれのユーザの「Synology Photos」用フォルダに移動しておきます。なお、個々人のアルバムをあとで別のユーザやユーザグループに共有することができるので、ユーザ横断的なアルバムの場合は、いったん代表者のユーザのフォルダに置いておきます。

TARGET_DIR='/volume1/homes/<対象NASユーザのID>/Photos/iPhoto_backup_2025_04/albums'
mkdir "$TARGET_DIR"
mv '<移行先のフォルダパス(NAS上)>/albums/002573_Regular_●●中同窓会 2012 10月' "$TARGET_DIR"

アルバムフォルダの移動が完了したら、項「3.2.4. 移動した写真・動画ファイルのインデックス作成完了を確認」と同様に、インデックスが再作成されるまで待機して写真の表示を確認します。

3.2.6. フォルダ内全選択でアルバム作成(手作業)

3.2.6.1. アルバムを作成

以下の手順で、実際にアルバムを作成します。

  1. 「Synology Photos」のアプリを開き、アルバムを作成するユーザでログインします。
  2. タイムライン表示になっている場合は、画面下部の「フォルダ」ボタン(Web版の場合は右上の「田」のようなボタン)を押して、「フォルダ表示」に切り替えます(図3.1.を参照)。
  3. 階層をたどって、対象のアルバムフォルダを開きます。
  4. フォルダ内の全ての写真・動画を複数選択した状態で、画面下部に出た操作メニューから「アルバムに追加」をクリックします(図3.2.を参照)。
  5. 「新規アルバム」をクリックして好きなアルバム名を設定し、アルバムを新規作成します。

「Synology Photos」のアルバムは、iPhotoのアルバムと異なり、写真・動画の順番を定義することはできません。各アルバムを開いた時の右上のメニューから「撮影日時順」などを選択することができます(デフォルトでは撮影日時順)。

3.2.6.2. アルバムを他のユーザ・ユーザグループと共有

作成したアルバムを他のユーザ・ユーザグループと共有する場合は、以下の手順を実施します。

Synology社製のNASのユーザグループは、管理者権限を持つユーザでDSMにログインし、アプリ「コントロールパネル」 > メニュー「ユーザーとグループ」 > タブ「グループ」から作成できます。

  1. 画面下部のメニュー(Web版はサイドメニュー)から「アルバム」を開きます。
  2. アルバム一覧から、先ほど作成したアルバムを開きます。
  3. 「🔗共有」ボタンを押します。
図3.6. 個人アルバムを共有(1/2)
  1. 共有設定画面が開くので、各項目を設定して保存することで、共有アルバムを作成できます。
    • 「共有リンクを有効化」:オンにする。
    • 「プライバシー設定」:「非公開 – 招待された人のみがアクセスできます」を選択することで、このNASサーバにユーザ登録していない人が閲覧できないように制限できる。
    • 「招待された人のリスト」:共有対象のユーザ/ユーザグループを選択する。ユーザ/ユーザグループごとに「閲覧者」「ダウンローダ」「プロバイダー」のいずれかの権限を割り振ることができる(共有アルバムに写真・動画を追加してもらいたい場合は「プロバイダー」に設定しておく)。
図3.7. 個人アルバムを共有(2/2)
  1. 試しに共有先のユーザで「Synology Photos」にログインしてみると、アルバム一覧に先ほど作成したアルバムが表示されます。

3.2.7. 複数のアルバムに共通する写真を手作業で登録

項「3.2.3. 各アルバムの写真・動画ファイルを個々のフォルダ直下に移動」の「トラブルシューティング:1つの写真・動画が複数のアルバムに含まれている場合の対処」にてダミーファイルを作成して移動させた場合は、ダミーファイルに対応する本来の写真を、各アルバムに登録する必要があります。

以下のコマンドにより、ダミーファイルの一覧を確認し、対象の各アルバムに本来の写真を手作業で登録していきます。

WORKING_DIR='./iphoto_album_composition_for_nas'
grep -r '\.dummy' "$WORKING_DIR"

ダミーファイルが対象とする本来の写真をどのアルバムのフォルダに格納しているのかは、項「3.2.3. 各アルバムの写真・動画ファイルを個々のフォルダ直下に移動」で保存したエラー内容のテキストを参照します。

3.3. 削除対象の重複写真ファイルを削除

無事にアルバムを作成できたので、章「2. 重複写真の削除」で作成した以下の削除対象ファイルパス一覧を用いて、重複写真を削除します。

  • 顔トリミング写真(2.1.節): images_to_remove_as_face_trimmed.txt
  • 回転リサイズ写真(2.4.節): not_oldest_duplicated_images.txt

写真ファイルを削除するだけならシェルスクリプトで実行できますが、残すべきファイルを削除してしまったり意図せず中断してしまったりといった事故を防ぐために、Pythonスクリプトで実行します。

まずは、以下の記事で紹介しているPythonスクリプトmove_target_files_into_a_folder.pyを実行し、削除対象の写真・動画ファイルを、「Synology Photos」管理外の一時フォルダに移動します。

その後、一時フォルダの中身が削除対象として問題ないかを精査したあと、その一時フォルダごと削除します。

削除対象の一部のファイルが存在しないというエラーが出た場合は、項「3.2.3. 各アルバムの写真・動画ファイルを個々のフォルダ直下に移動」の操作により、対象のファイルがアルバムのフォルダに移動されている可能性があります。
項「2.4.2. 回転リサイズ写真のファイルパス一覧を作成」でnot_oldest_duplicated_images.txtと一緒に出力されたCSVファイルfile_paths_list_grouped_by_its_name_with_duplicated_id.csvを参照して、代わりに削除すべき重複写真に差し替えるか、削除対象ファイルの対象行を削除して、スクリプトを再実行します。

4. 写真・動画のユーザ振り分け(手作業)

項「3.2.5. 個人アルバムのフォルダを対象ユーザのフォルダに振り分け」により、iPhotoのアルバムに含まれていた写真・動画は、各ユーザの個人スペースや共有スペースに振り分けられました。一方で、アルバムに含まれてない個々の写真・動画にも、個人的なものが存在します。よって、地道で大変ですが、個々の写真・動画を手作業で、各ユーザの個人スペースに移動していきます。

オススメの方法としては、「Synology Photos」の画面上で「フォルダ表示」をして写真・動画を閲覧していき、移動対象のフォルダをメモした上で、あとで一括で以下のようなコマンドで移動していく方法です。

TARGET_DIR='/volume1/homes/<対象NASユーザのID>/Photos/iPhoto_backup_2025_04/yyyy/mm/dd'
mkdir "$TARGET_DIR"
mv '<移行先のフォルダパス(NAS上)>/yyyy/mm/dd/yyyymmdd-HHMMSS' "$TARGET_DIR"

ファイルを移動したあとは、項「3.2.4. 移動した写真・動画ファイルのインデックス作成完了を確認」を参照して、再インデックスされることを確認します。

筆者

本記事は以上です。ここまで読んでいただき、ありがとうございました!

脚注

  1. 移行元の環境情報
    ・デスクトップPC: iMac 13,2 (2012)
    ・MacOS: 10.13.6 High Sierra (2017)
    ・iPhoto: 9.6.1(910.42) (2015)
    ・Bash: 3.2.57(1)-release
    ・Homebrew: 4.4.24
    ・rsync: 3.4.1
    ・iPhotoで管理している写真・動画の総数: 36,031件
    ・iPhotoの総アルバム数: 115件 ↩︎
  2. 移行先の環境情報
    ・NAS: Synology DS218 (2017)
    ・DSM: 7.2.2-72806 Update 3 (2024)
    ・Linux: diskstation 4.4.302+ (2024)
    ・Bash: 4.4.23(1)-release
    ・Samba: 4.15.13
    ・Synology Photos: 1.8.0-10070 (2024)
    ・Python: 3.12.10
    ・ExifTool: 13.33 ↩︎
  3. 楽曲再生クライアントの環境情報
    ・スマートフォン: iPhone 12 mini (2020)
    ・iOS: 18.5 (2025)
    ・Synology Photos: 2.2.2 (2025) ↩︎
  4. “Synology Photos テクニカルスペック | Synology Inc.”, https://www.synology.com/ja-jp/dsm/0.0/software_spec/synology_photos. ↩︎
  5. “ExifTool for DSM 7.0 ? | Synology Community”, https://community.synology.com/enu/forum/68/post/144720. ↩︎

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!

筆者

ユーマン
在籍: SIer企業
職務: Python歴8年の開発職
大学: ロボ設計/PV制作 @NHKロボコン優勝サークル
大学院: 学会発表にて2度優秀賞 @AI研究
目標: "ふと思いついたモノを何でもつくれちゃう人"になりたい!
好き: Python / Excel / 友人たちとの交流 / カフェ作業 / アフター5の自分時間 / 自己分析 / ホラー映画 / '00年代アニメ / 散歩や登山 / スキー / Mr.Children / 笑顔がステキな人
目次