Theme
View
Hero effect
All entries
2025 · #pipeline

Shrinking 90 GB of Google Photos videos to 8.5 GB

Moved my photo library off Google and made the videos 90% smaller, without losing dates or locations.

Result
89.93 GB → 8.51 GB
Context
Personal project
Stack
Python · FFmpeg (H.265) · ExifTool
Measured on
909 videos

The problem

My Google Photos storage was full, and most of it was videos, years of phone videos going back to 2013. The easy way out was to simply upgrade my Google Photos subscription tier and pay more. But that wasn’t what I really wanted to do. I already had a mini-pc and Immich server set up, so I thought I’d export the main files from Google Photos, and then simply have them on Immich server on my HDD NAS, and instead have the converted smaller-sized versions re-uploaded to Google Photos.

Why not just re-encode and upload again

Takeout gives you the videos, but the date and the location of each video sit in a separate JSON file next to it. If you only compress the video and upload it back, that information is gone and the timeline gets messed up. And the JSON files are not even named consistently, Google cuts long file names, so the same kind of file can end with .supplemental-metadata.json, .supp.json or a few versions in between.

One compression setting also didn’t fit everything. Small clips were not worth touching, and the really big 4K videos needed much more than the rest.

What I did

I wrote a Python script around FFmpeg and ExifTool. Nothing special, sure, but it does a few things that made the difference:

  • It picks a compression level by file size. Under 15 MB the file is just copied. Between 15 MB and 3 GB it goes to H.265 at 1080p, CRF 28. Over 3 GB it goes to H.265 at 720p, CRF 32.
  • It reads the Takeout JSON for every video, tries all the truncated file names, and writes the date and GPS back into the new file with ExifTool. Videos without a JSON keep their own metadata.
  • It skips files that are already done, so I could stop it and start it again later. Also handy when new videos come in.
  • It writes a CSV log with the size before and after, the time and the status for every file, plus a summary at the end.

I ran it on my laptop with Pop!_OS.

Result

Videos 909
Size before 89.93 GB
Size after 8.51 GB
Space saved 81.41 GB (90.53%)
Copied / normal / aggressive 427 / 481 / 1
Failed 0
Total time 6 h 43 min, about 27 s per video

After that the compressed videos went back to Google Photos, and the originals went to Immich server, and I didn’t need the bigger plan.

What I’d do differently

I judged the quality by eye only, on some videos, and it looked fine to me. Going through the code again later, I noticed that the scaling sets the height to 1080, so maybe not all videos were resized or compressed properly (downscaling, upscaling). Next time I would probably make this part of the process a bit more dynamic and more based on the video specs themselves.

What’s next

The script did its job, but I want to make it better:

Next case study →Legacy search: 50 seconds to under 4