Provider: Google Photos #12

Open
opened 2026-03-27 21:56:32 +00:00 by antialias · 0 comments
Owner

Google Photos provider using the Google Photos Library API with OAuth2.

Config Schema

{
  "client_id": { "type": "string", "description": "Google OAuth2 client ID" },
  "client_secret": { "type": "string", "secret": true },
  "album_id": { "type": "string", "description": "Specific album to pull from (empty = all photos)" },
  "max_photos": { "type": "integer", "default": 500, "description": "Max photos to index" }
}

Runtime state (stored separately, not user-configured):

  • access_token, refresh_token, token_expiry

Auth Flow

  1. User creates a Google Cloud project and enables the Photos Library API
  2. User creates OAuth2 credentials (web application type) with redirect URI https://photos.haunt.house/api/providers/{id}/oauth/callback
  3. User enters client_id and client_secret in the provider config form
  4. User clicks "Authorize" → redirected to Google consent screen
  5. On approval, callback receives auth code → exchanged for access + refresh tokens
  6. Tokens stored in provider instance config
  7. Access tokens auto-refreshed using the refresh token

Scopes needed: https://www.googleapis.com/auth/photoslibrary.readonly

Implementation Notes

  • Use google-auth and requests (not the full Google client library — too heavy)
  • list_photos() calls mediaItems.list or mediaItems.search (if album_id set), paginates to max_photos
  • get_photo() fetches from the baseUrl + =w{width}-h{height} parameter (Google serves resized versions)
  • get_thumbnail() fetches baseUrl + =w300-h300-c (cropped thumbnail, served by Google — fast)
  • PhotoRef.date = mediaMetadata.creationTime
  • PhotoRef.width/height = mediaMetadata.width/height
  • Important: baseUrl expires after ~60 minutes. The list_photos() cache TTL must respect this. Either re-fetch URLs before they expire, or fetch the URL on-demand in get_photo().

Album Selection UI

After OAuth authorization, the web UI should:

  1. Fetch the user's album list via albums.list
  2. Present a dropdown/picker to select an album (or "All Photos")
  3. Save the selected album_id to provider config

Dependencies

  • google-auth added to requirements.txt

Gotchas

  • Google Photos Library API is read-only for third-party apps (no uploads, no deletes)
  • API quota: 10,000 requests/day (shared across all users of the OAuth client). Plenty for a photo frame.
  • baseUrl expiration means we can't cache photo URLs long-term — only cache the mediaItem.id and re-resolve URLs when needed
  • The API does NOT support filtering by date range or media type in list — only in search. For "all photos" mode, we paginate through everything.

Depends on #9 (core architecture).

Google Photos provider using the Google Photos Library API with OAuth2. ## Config Schema ```json { "client_id": { "type": "string", "description": "Google OAuth2 client ID" }, "client_secret": { "type": "string", "secret": true }, "album_id": { "type": "string", "description": "Specific album to pull from (empty = all photos)" }, "max_photos": { "type": "integer", "default": 500, "description": "Max photos to index" } } ``` Runtime state (stored separately, not user-configured): - `access_token`, `refresh_token`, `token_expiry` ## Auth Flow 1. User creates a Google Cloud project and enables the Photos Library API 2. User creates OAuth2 credentials (web application type) with redirect URI `https://photos.haunt.house/api/providers/{id}/oauth/callback` 3. User enters `client_id` and `client_secret` in the provider config form 4. User clicks "Authorize" → redirected to Google consent screen 5. On approval, callback receives auth code → exchanged for access + refresh tokens 6. Tokens stored in provider instance config 7. Access tokens auto-refreshed using the refresh token Scopes needed: `https://www.googleapis.com/auth/photoslibrary.readonly` ## Implementation Notes - Use `google-auth` and `requests` (not the full Google client library — too heavy) - `list_photos()` calls `mediaItems.list` or `mediaItems.search` (if album_id set), paginates to `max_photos` - `get_photo()` fetches from the `baseUrl` + `=w{width}-h{height}` parameter (Google serves resized versions) - `get_thumbnail()` fetches `baseUrl` + `=w300-h300-c` (cropped thumbnail, served by Google — fast) - `PhotoRef.date` = `mediaMetadata.creationTime` - `PhotoRef.width/height` = `mediaMetadata.width/height` - **Important**: `baseUrl` expires after ~60 minutes. The `list_photos()` cache TTL must respect this. Either re-fetch URLs before they expire, or fetch the URL on-demand in `get_photo()`. ## Album Selection UI After OAuth authorization, the web UI should: 1. Fetch the user's album list via `albums.list` 2. Present a dropdown/picker to select an album (or "All Photos") 3. Save the selected `album_id` to provider config ## Dependencies - `google-auth` added to `requirements.txt` ## Gotchas - Google Photos Library API is **read-only** for third-party apps (no uploads, no deletes) - API quota: 10,000 requests/day (shared across all users of the OAuth client). Plenty for a photo frame. - `baseUrl` expiration means we can't cache photo URLs long-term — only cache the `mediaItem.id` and re-resolve URLs when needed - The API does NOT support filtering by date range or media type in `list` — only in `search`. For "all photos" mode, we paginate through everything. Depends on #9 (core architecture).
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: antialias/eink-photo-frame#12