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: