A personal toolkit for photo metadata automation, Plex synchronization, Immich workflows, and photo library inventory management.
This repository brings together a set of Python scripts designed to keep photo collections consistent across Plex, Immich, XMP sidecars, and local disk storage.
- Plex photo library :
- Sync Plex ratings with local XMP metadata
- Compare and clean up Plex playlists
- Immich favorite = XMP 5 stars rating :
- Mark Immich assets as favorites based on rating rules
- Apply ratings to Immich assets automatically
- Inventory photo folders into SQLite databases
- Detect duplicate XMP sidecars and naming inconsistencies
- Reuse SQL-based file selection for copying or organizing media
Managing a large personal photo library often means juggling several systems:
- Plex for browsing media (I previously used it to browse piictures, these scripts helped me to migrate to Immich)
- Immich for browsing pictures
- XMP sidecars for preserving metadata on disk
- Google Takeout or local folders for exported media archives
This project helps automate the repetitive tasks between those systems and keeps metadata aligned.
- Plex
- ComparePlaylists.py: compares two Plex playlists and reports differences.
- RatePlaylist.py: applies a chosen rating to all photos in a Plex playlist.
- PlexFavoritesToXmp.py: compares Plex ratings with XMP metadata and updates the sidecar when needed.
- Immich
- ImmichFavoriteFromRating5.py: marks non-favorited assets with a 5-star rating as favorites.
- ImmichFavoritesToXmp.py: updates favorite assets that do not yet have a 5-star rating.
- Helpers/utility libs
- PlexHelper.py: utility functions to traverse Plex albums and identify file paths.
- ImmichHelper.py: helper for querying and updating Immich assets via the API.
- metadataLib.py: reads and writes ratings with XMP and ExifTool support.
- SimpleLog.py: lightweight logging wrapper for console, GitHub Actions, and Telegram output.
- GooglePhotos/ListPhotoToSQLite.py: scans a folder tree and indexes files in SQLite.
- GooglePhotos/CopyFilesFromSQLiteQuery.py: copies files based on SQL query results.
- GooglePhotos/MoveModifiéInSubFolder.py: reorganizes modified files into a dedicated subfolder.
- XmpFixer/ListXmpToSQLite.py: inventories XMP sidecars in a SQLite database.
- XmpFixer/RenameExtToStdXmp.py: renames XMP files from xxx.ext.xmp to xxx.xmp.
- XmpFixer/RenameStdToExtXmp.py: renames XMP files from xxx.xmp to xxx.ext.xmp.
- XmpFixer/ListDuplicateXmpToSQLite.py: finds duplicate XMP sidecar pairs.
- Python 3.10+
- pip installed
- Windows-oriented local setup for the scripts that rely on file paths and Plex access
pip install -r requirements.txtCreate a local Connexion.py file in the project root:
baseurl = "http://localhost:32400"
token = "YOUR_PLEX_TOKEN"Create a .env file in the project root:
IMMICH_BASE_URL=https://your-immich-instance
IMMICH_API_KEY=your_api_keySome metadata operations rely on ExifTool and require a valid local binary path in metadataLib.py.
Use PlexFavoritesToXmp.py to keep Plex ratings aligned with the metadata written to the photo files.
Edit the settings in RatePlaylist.py:
playlistName = "2024.03 - China"
rating = 6.0Run:
python RatePlaylist.pyEdit the settings in ComparePlaylists.py:
playlist1Name = "2024.03 - China"
playlist2Name = "2024.03 - China +"Run:
python ComparePlaylists.pypython ImmichFavoriteFromRating5.py
python ImmichFavoritesToXmp.pypython XmpFixer/ListXmpToSQLite.pyWhen prompted, enter the folder to scan.
This repository includes a scheduled workflow at .github/workflows/immich_daily.yml that runs every night at 02:00 UTC.
It automates the two daily Immich jobs:
- mark non-favorited assets with a 5-star rating as favorites
- set a 5-star rating on favorite assets that do not already have it
The workflow:
- checks out the repository
- installs Python dependencies
- runs ImmichFavoriteFromRating5.py
- runs ImmichFavoritesToXmp.py
This is useful if you want a simple, hands-off nightly sync for your own Immich instance.
In your GitHub repository, go to Settings → Secrets and variables → Actions and add:
IMMICH_BASE_URL: your Immich URL, for examplehttps://photos.example.comIMMICH_API_KEY: a valid API key with access to your libraryTELEGRAM_TOKEN: optional, if you want Telegram notificationsTELEGRAM_CHAT_ID: optional, if you want Telegram notifications
You do not need to change the Python code for this to work in your fork; the workflow reads those values from GitHub secrets.
- Fork this repository.
- Go to the GitHub Actions tab.
- Enable workflows if needed.
- Add the secrets listed above.
- Save the workflow and let it run on schedule, or trigger it manually with
workflow_dispatch.
The cron is currently:
cron: '0 2 * * *'If you want a different time, edit the schedule in .github/workflows/immich_daily.yml.
This is designed so people can fork the repo, keep the same automation logic, and plug in their own Immich instance and GitHub secrets without modifying the scripts themselves.
- This repository is built around a personal local workflow and may require manual path adjustments.
- The Plex scripts expect valid local credentials and a reachable server.
- XMP-sidecar operations can affect metadata on real files, so backups are strongly recommended.
- Some scripts process very large libraries and may take a while to complete.
- Test on a small subset before running on a full library.
- Backup media before renaming or moving sidecars.
- Verify the ExifTool path before production jobs.
- Keep secrets like Immich tokens in a local
.envfile, not in version control. - Prefer a dry run or small sample before bulk operations.
This project is a personal automation toolkit and is intended for local, self-managed use. It is not a production SaaS application and may evolve depending on your personal workflow.