![]() |
| Photo from my pro football officiating days. I had to leave the game at age 5 due to penalty flag-induced carpal tunnel. |
Summary
I'm going to cover personal use-case in this post around making a large number of family photos securely accessible to family members. I've been maintaining a website for years for this purpose. I decided recently that maintaining that site was more work than was really necessary. Google recently terminated their Photo application, but Drive works just fine for sharing photos. I had a large enough collection of photos to upload to Drive that it made sense to go to code to do it.
Architecture
Drive has a documented Python API. I set up a Google Cloud project with a Service Account that allows access to Drive. I used that Service Account for all my API calls to Drive.
The diagram below depicts the transfer scenario. The local images are stored in a year, year-month hierarchy. That hierarchy is replicated on Drive.
Code
Main Loop
I have my photos stored locally in a folder hierarchy that follows this: Year -> Year-Month. The loop below iterates through all the local year and year-month folders to upload files to Drive.
def upload_all_images(self):
years = os.listdir(LOCAL_ROOT)
for year in years:
print('Uploading year: ' + year)
year_path = os.path.join(LOCAL_ROOT, year)
year_months = os.listdir(year_path)
for year_month in year_months:
print('Uploading year_month: ' + year_month)
self.upload_folder_images(year, year_month)
Photo Folder Upload
The function below creates the necessary year and year-month folders on Drive if they don't already exist. It then iterates through the local year-month folder to upload each image file to Drive.
def upload_folder_images(self,
year,
year_month):
year_month_path = os.path.join(os.path.join(LOCAL_ROOT, year), year_month)
if (os.path.isdir(year_month_path)):
year_folder_id = self.get_folder_id(year)
if (not year_folder_id):
year_folder_id = self.create_folder(year, self.root_folder_id)
year_month_folder_id = self.get_folder_id(year_month)
if (not year_month_folder_id):
year_month_folder_id = self.create_folder(year_month, year_folder_id)
for file in os.listdir(year_month_path):
local_file_path = os.path.join(year_month_path,file)
if (os.path.isfile(local_file_path)):
try:
self.upload_file(local_file_path, year_month_folder_id)
except Exception as e:
print(e)
File Upload
The code below checks to see if the file already exists on Drive. If not, then it calls necessary Drive API functions to upload the image. def upload_file(self,
local_file_path,
folder_id):
file_name = os.path.basename(local_file_path)
#check if file already exists on gdrive. if not, create the file on google drive.
results = self.service.files().list(q="'" + folder_id + "' in parents and name = '" + file_name + "'",
spaces='drive',
fields='files(id)').execute(num_retries=NUM_TRIES)
items = results.get('files', [])
if not items:
print('Uploading: ' + file_name)
try:
outfile = self.resize(local_file_path)
media = MediaFileUpload(outfile)
file_metadata = {'name': file_name, 'parents': [folder_id]}
self.service.files().create(body=file_metadata,
media_body=media,
fields='id').execute(num_retries=NUM_TRIES)
os.remove(outfile)
except Exception as e:
print(e)
else:
print('File already exists on gdrive: ' + file_name)
return
Image Resizing
I use the PIL library to reduce the resolution (and thus size) of each image file to reduce my Drive space.
def resize(self,
infile):
outfile = os.path.join('./', os.path.basename(infile))
im = Image.open(infile)
if max(im.size) < 1000:
size = im.size
else:
size = (1000,1000)
im.thumbnail(size, Image.ANTIALIAS)
im.save(outfile, optimize=True, quality=85)
return outfile
Source
Copyright ©1993-2024 Joey E Whelan, All rights reserved.


