Creating a JSON database of photos and albums using Google Photos API
It turns out that using the Google Photos API is not particularly suited to organizing your photos collection. On the other hand, the API makes it easy to create a listing of all photos and albums in your collection.
For the case of creating a simple file-based JSON database, I wanted a command-line driven solution, so I used photoslibrary1-cli.
Authentication
The photoslibrary1-cli documentation claims to include a client secrets file for public use, but it no longer works.
Instead, you will need to create your own:
- Set up a project on Google Cloud Console
- Enable the Google Photos API
- Choose the type of credentials to create (I used OAuth 2.0)
- Download a JSON client secrets file
Then, copy your client secrets file into ./google-service-cli/photoslibrary1-secret.json
, and authenticate with the browser (if using OAuth 2.0) by running any photoslibrary1-cli command, e.g. photoslibrary1 media-items list
:
Please direct your browser to [URL] and follow the instructions displayed there.
Pagination
photoslibrary1-cli does not handle pagination, so I wrote photoslibrary1_paginated.sh to do the extra bookkeeping.
It takes four arguments:
--target-array
: The property name which stores the list of results for the given request.mediaItems
,albums
, orsharedAlbums
.--command
: The photoslibrary1-cli command to run. These are simply arguments forwarded directly tophotoslibrary1
.--output-name
: The name of the file to which items will be concatenated is<output-name>.json
.--page-token-arg
: I believe this may be a quirk of the way photoslibrary1-cli was written. Sometimes page tokens are provided as-p page-token=<page-token>
and sometimes as-r page-token=<page-token>
.
Page token is saved as <output-name>.token
. The script can be safely interrupted with Ctrl+C. Just re-run with the same --output-name
to resume.
JSON database structure
This is how we plan to structure our database:
./media-items.json
./albums.json
./albums/ALBUM_ID.json
./shared-albums.json
./shared-albums/ALBUM_ID.json
./media-item-to-albums/MEDIA_ITEM_ID.json
./media-item-to-shared-albums/MEDIA_ITEM_ID.json
Each file contains one JSON object per line. Let’s build up the database step-by-step.
Retrieve a list of media items
Save information about each media item (photo or video) into media-items.json
.
./photoslibrary1_paginated.sh \
--target-array mediaItems \
--command 'media-items list' \
--output-name media-items \
--page-token-arg p
Retrieve a list of albums
Albums that you created are listed here, even if they are shared with others. Save to albums.json
.
./photoslibrary1_paginated.sh \
--target-array albums \
--command 'albums list' \
--output-name albums \
--page-token-arg p
Retrieve a list of shared albums
Albums that others shared with you are listed here. Save to shared-albums.json
.
./photoslibrary1_paginated.sh \
--target-array sharedAlbums \
--command 'shared-albums list' \
--output-name shared-albums \
--page-token-arg p
Retrieve a list of media items in each album
For each album, retrieve a list of media items. Save to albums/ALBUM_ID.json
.
mkdir albums
for album in `cat albums.json | jq -r '.id'`; do
echo "$album"
./photoslibrary1_paginated.sh \
--target-array mediaItems \
--command "media-items search -r . album-id=$album" \
--output-name "albums/$album" --page-token-arg r
done
Retrieve a list of media items in each shared album
For each shared album, retrieve a list of media items. Save to shared-albums/ALBUM_ID.json
.
mkdir shared-albums
for album in `cat shared-albums.json | jq -r '.id'`; do
echo "$album"
./photoslibrary1_paginated.sh \
--target-array mediaItems \
--command "media-items search -r . album-id=$album" \
--output-name "shared-albums/$album" --page-token-arg r
done
Map media items to albums containing them
For each media item, if one or more albums contain the media item, create a file listing those albums. Save to media-item-to-albums/MEDIA_ITEM_ID.json
.
mkdir media-item-to-albums
for fname in albums/*.json; do
album_id=`echo $fname | sed -e 's@\.json$@@' -e 's@^albums/@@'`
echo "$album_id"
for media_id in `cat $fname | jq -r '.id'`; do
touch "media-item-to-albums/${media_id}.json"
grep "$album_id" albums.json >> "media-item-to-albums/${media_id}.json"
done
done
Map media items to shared albums containing them
For each media item, if one or more shared albums contain the media item, create a file listing those albums. Save to media-item-to-shared-albums/MEDIA_ITEM_ID.json
.
mkdir media-item-to-shared-albums
for fname in shared-albums/*.json; do
album_id=`echo $fname | sed -e 's@\.json$@@' -e 's@^shared-albums/@@'`
echo "$album_id"
for media_id in `cat $fname | jq -r '.id'`; do
touch "media-item-to-shared-albums/${media_id}.json"
grep "$album_id" shared-albums.json >> "media-item-to-shared-albums/${media_id}.json"
done
done
And that’s all!