ここ最近、Eagle を使用して画像・ナレッジ管理すると便利だと聞き、試したところ噂通り便利だったため一括で移行を進めることにしました。
普段、画像はとりあえずGoogleフォトに保管していたので、まとめて欲しいものだけEagleにアップロードしたいと思ったときに今回の方法を実施しました。
Eagleとは
Eagleとは、台湾のogdesign.incという会社が開発したクリエイター向けの画像管理ツールです。
筆者はクリエイターではなくエンジニアですが、
- 管理できるものがPNGやJPEGなどの画像ファイルに留まらずPDF、ウェブページ、GIFなど多岐に渡る
- ローカルで動作しますが、Googleドライブなどのクラウドストレージの紐づけられる
- Chrome拡張機能が提供されているためブラウザの画像を直接Eagleに保存できる
- Eagle APIを使用してAPIベースで操作も可能
な点に惹かれました。
事前準備
事前準備として以下を実施します。
- Python実行環境の用意
- Eagle API Tokenの取得
- Google Cloud の OAuthクライアントの認証情報の取得
- 必要なパッケージのインストール
Python実行環境の用意
今回はPythonを使って処理を行うためご自身のPC環境にPythonの実行環境を用意します。
各OS毎に手順に沿ってインストールをしてください。
Eagle API Tokenの取得
Eagle APIを使ってアップロードをするにはAPI Tokenを使用し認証する必要があります。
API TokenはEagleのソフトの左上にあるハンバーガーメニューを選択後、「環境設定 > 開発者」を見るとAPI Tokenを参照できます。
Google Cloud の OAuthクライアントの認証情報の取得
GoogleフォトからPythonを使用しアルバムの情報を取得するために、
Google Photo APIを使用します。
Google Photo APIを使用するための認証情報は、
Google Cloudのコンソールから取得する必要があります。
下記ブログの「Google Cloud Platform の設定」にて分かりやすく説明されているためご参照ください。
Google Cloudを使ったことがある方は既存のプロジェクトを使用していただいても大丈夫です。
取得した.json
の拡張子のファイルは必ずclient_secrets.json
の名前に変更してください。
必要なパッケージのインストール
Python環境を用意できたら必要なパッケージをインストールします。
Windowsであればコマンドプロンプト、MacであればTerminalを開いて下記コマンドを実行してください。
pip install google-api-python-client google-auth-oauthlib EagleWrapper
実行してみる
事前準備はできたので実際にPythonのファイルを作成します。
index.pyなどファイル名はなんでも大丈夫なので、下記コードを書いたファイルを用意してください。
※コードの説明はあとがきで記載します。
2点 1点、環境に応じて修正が必要なため書き換えてください。
- albumName
- Googleフォトのアルバム名を記載してください
-
ALBUM_NAME
を正しいものに置き換えてください
-
EAGLE_API_KEY事前に取得したEagleのAPI Tokenを記載してくださいYOUR_EAGLE_API_KEY
を正しいものに置き換えてください
from googleapiclient.discovery import build
import google.oauth2.credentials
import google_auth_oauthlib.flow
import json, os
from eaglewrapper import Eagle
albumName = "ALBUM_NAME" # <- アルバム名を入力
#EAGLE_API_KEY = 'YOUR_EAGLE_API_KEY' # <- Eagle API Tokenを入力
SCOPES = ['https://www.googleapis.com/auth/photoslibrary']
API_SERVICE_NAME = 'photoslibrary'
API_VERSION = 'v1'
CLIENT_SECRET_FILE = 'client_secrets.json'
CREDENTIAL_FILE = 'credential.json'
#EAGLE_API_ENDPOINT = 'http://localhost:41595/api/item/addFromURL'
eagle = Eagle()
# Credentialを取得
def getCredentials():
if os.path.exists(CREDENTIAL_FILE):
with open(CREDENTIAL_FILE) as f_credential_r:
credentials_json = json.loads(f_credential_r.read())
credentials = google.oauth2.credentials.Credentials(
credentials_json['token'],
refresh_token=credentials_json['refresh_token'],
token_uri=credentials_json['token_uri'],
client_id=credentials_json['client_id'],
client_secret=credentials_json['client_secret']
)
else:
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, scopes=SCOPES)
credentials = flow.run_local_server()
with open(CREDENTIAL_FILE, mode='w') as f_credential_w:
f_credential_w.write(credentials.to_json())
return credentials
# アルバムから画像を取得
def getPhotosFromAlbum(service, albumId):
photos = []
nextPageToken = ''
while True:
body = {
'albumId': albumId,
'pageSize': 100,
'pageToken': nextPageToken
}
response = service.mediaItems().search(body=body).execute()
items = response.get('mediaItems', [])
for item in items:
photos.append([item['baseUrl'],item['filename']])
nextPageToken = response.get('nextPageToken', None)
if not nextPageToken:
break
return photos
# アルバムIDを取得
def findAlbumByName(service, albumName):
nextPageToken = ''
while True:
response = service.albums().list(pageSize=50, pageToken=nextPageToken).execute()
albums = response.get('albums', [])
for album in albums:
if album['title'] == albumName:
return album['id']
nextPageToken = response.get('nextPageToken', None)
if not nextPageToken:
break
return None
# Eagleに画像をアップロード
def upload_to_eagle(image_url, filename):
response = eagle.add_from_url(image_url, filename)
return response
def main():
credentials = getCredentials()
service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials,static_discovery=False)
albumId = findAlbumByName(service, albumName)
if albumId:
print(f"Found album '{albumName}' with ID: {albumId}")
photos = getPhotosFromAlbum(service, albumId)
i=0
# 各画像をEagleにアップロード
for photo in photos:
print(photo[1]+"をアップロード")
image_url = photo[0]
filename = photo[1]
upload_to_eagle(image_url, filename)
i += 1
else:
print(f"Album '{albumName}' not found.")
if __name__ == "__main__":
main()
コードが記述されたファイル(index.py)と同じフォルダにclient_secrets.json
を配置してください
用意ができたら最後実行して完了です。
python index.py
初回のみブラウザが起動し、認証が求められるためそのまま認証を進めるとコードの処理が実行されます。
コード解説
モジュール・変数の指定
ここでは使用するモジュールと変数を指定しています。
EagleのAPIを使いやすいようPython Wrapperがあるため今回はこちらを活用します。
開発者さんに感謝!
from googleapiclient.discovery import build
import google.oauth2.credentials
import google_auth_oauthlib.flow
import json, os
from eaglewrapper import Eagle
albumName = "ALBUM_NAME" # <- アルバム名を入力
EAGLE_API_KEY = 'YOUR_EAGLE_API_KEY' # <- Eagle API Tokenを入力
SCOPES = ['https://www.googleapis.com/auth/photoslibrary']
API_SERVICE_NAME = 'photoslibrary'
API_VERSION = 'v1'
CLIENT_SECRET_FILE = 'client_secrets.json'
CREDENTIAL_FILE = 'credential.json'
EAGLE_API_ENDPOINT = 'http://localhost:41595/api/item/addFromURL'
eagle = Eagle()
Credentialの取得
こちらの関数では、毎回client_secrets.json
を使用してログインを行わなくても良いように、
初回はclient_secrets.json
を使って認証を行いcredential.json
を生成し、次回以降はcredential.json
を用いて認証するロジックとなっています。
こちらのブログを参考にさせていただきました。
def getCredentials():
if os.path.exists(CREDENTIAL_FILE):
with open(CREDENTIAL_FILE) as f_credential_r:
credentials_json = json.loads(f_credential_r.read())
credentials = google.oauth2.credentials.Credentials(
credentials_json['token'],
refresh_token=credentials_json['refresh_token'],
token_uri=credentials_json['token_uri'],
client_id=credentials_json['client_id'],
client_secret=credentials_json['client_secret']
)
else:
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(CLIENT_SECRET_FILE, scopes=SCOPES)
credentials = flow.run_local_server()
with open(CREDENTIAL_FILE, mode='w') as f_credential_w:
f_credential_w.write(credentials.to_json())
return credentials
アルバムから画像を取得
こちらの関数では、Googleフォトのアルバムから画像を取得するものになります。
1度の処理でまとめて取得するのではなくnextPageToken
があれば無くなるまで取得し続ける処理となっています。
画像を取得と表現していますが、厳密にはアップロード用に使用するURLを取得しているためローカル環境に一時的に保存するような処理は走っていません。
def getPhotosFromAlbum(service, albumId):
photos = []
nextPageToken = ''
while True:
body = {
'albumId': albumId,
'pageSize': 100,
'pageToken': nextPageToken
}
response = service.mediaItems().search(body=body).execute()
items = response.get('mediaItems', [])
for item in items:
photos.append([item['baseUrl'],item['filename']])
nextPageToken = response.get('nextPageToken', None)
if not nextPageToken:
break
return photos
アルバムIDを取得
こちらの関数はGoogleフォトのアルバム名からアルバムIDを取得する処理になります。
アルバム一覧を取得し一致するものを検索します。
def findAlbumByName(service, albumName):
nextPageToken = ''
while True:
response = service.albums().list(pageSize=50, pageToken=nextPageToken).execute()
albums = response.get('albums', [])
for album in albums:
if album['title'] == albumName:
return album['id']
nextPageToken = response.get('nextPageToken', None)
if not nextPageToken:
break
return None
Eagleに画像をアップロード
こちらの関数は、EagleにAPIを使用して取得した画像をアップロードしています。
def upload_to_eagle(image_url, filename):
response = eagle.add_from_url(image_url, filename)
return response
main関数
最後はmain関数となり、実際に処理のフローを記述しています。
ファイル名とアップロード用URLを含んだ2次元リストを作成することでそれぞれ同時に指定してアップロードが可能となります。
def main():
credentials = getCredentials()
service = build(API_SERVICE_NAME, API_VERSION, credentials=credentials,static_discovery=False)
albumId = findAlbumByName(service, albumName)
if albumId:
print(f"Found album '{albumName}' with ID: {albumId}")
photos = getPhotosFromAlbum(service, albumId)
i=0
# 各画像をEagleにアップロード
for photo in photos:
print(photo[1]+"をアップロード")
image_url = photo[0]
filename = photo[1]
upload_to_eagle(image_url, filename)
i += 1
else:
print(f"Album '{albumName}' not found.")
if __name__ == "__main__":
main()
参考
おわりに
今回、GoogleフォトからEagleへの移行にチャレンジしてみたのでせっかくだと思いブログにしました。
Eagleを使用することでプレゼン資料に使う素材や画像をタグ付けすることもできますし、PowerPointやPDFに対応しているので自分のものに限らず他人のプレゼン資料などを事前にタグ付けしておくことでタグベースの検索も可能です。
Eagleを使うことでアイデアを気軽に管理できるようになったのでぜひおすすめのツールです。
今まで、Googleフォト使ってたしアップロードしなおすのめんどくさいからEagle使わなくてもいいかな…と思っていた方はぜひ参考にしていただければと思います!
付記
Eagle API Keyの取得は不要だったためスキップいただいて大丈夫です。