Python: Backup files to Google Drive using API

Purpose:
Backing up a file from a hosting server to google drive as a contingency plan.

Prerequisites:
Google service account key. (Create a Google Service Account and an Key for API access)

Step 1.) Install python and necessary packages.

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth

Step 2.) Set Variables
SCRIPT_DIRECTORY = “/home/user/docker_planka”
SERVICE_ACCOUNT_FILE = “/home/user/GoogleDrive-serviceAccount.json”
DRIVE_FOLDER_ID = “googleDriveFolderID”
FILE_SUFFIX = “filename.tgz” (Used to detect file for upload and deletion)

The script will upload the single file and remove the old file as long as the name’s are no identical.

import os
import glob
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.oauth2 import service_account

# ====== CONFIGURATION =====
# Change working directory for cron compatibility
SCRIPT_DIRECTORY = "/home/user/docker_planka"
os.chdir(SCRIPT_DIRECTORY)

# Google Service Account Key
SERVICE_ACCOUNT_FILE = "/home/user/GoogleDrive-serviceAccount.json"

# Google Drive folder ID
DRIVE_FOLDER_ID = "1NXqKQi69mOx3FpgnXmcdjhZfjE-xQfaL"

# File name's ending (suffix)
FILE_SUFFIX = "planka.tgz"

SCOPES = ['https://www.googleapis.com/auth/drive.file']

def get_latest_backup_file(suffix):
    files = glob.glob(f"*{suffix}")
    if not files:
        raise FileNotFoundError(f"No files matching '*{suffix}' found in current directory.")
    latest_file = max(files, key=os.path.getmtime)
    return latest_file

def upload_to_drive(service, local_file_path, drive_folder_id):
    file_metadata = {'name': os.path.basename(local_file_path)}
    if drive_folder_id:
        file_metadata['parents'] = [drive_folder_id]
    media = MediaFileUpload(local_file_path, resumable=True)
    file = service.files().create(
        body=file_metadata,
        media_body=media,
        fields='id, name'
    ).execute()
    print(f"Uploaded '{local_file_path}' as '{file.get('name')}' (ID: {file.get('id')})")
    return file.get('id'), file.get('name')

def delete_old_backups_in_drive(service, folder_id, suffix, exclude_name=None):
    query = f"'{folder_id}' in parents and name contains '{suffix}' and trashed = false"
    results = service.files().list(q=query, fields="files(id, name)").execute()
    files = results.get('files', [])
    for file in files:
        if file['name'] != exclude_name:
            print(f"Deleting old backup '{file['name']}' (ID: {file['id']}) from Google Drive.")
            service.files().delete(fileId=file['id']).execute()

def main():
    credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES
    )
    service = build('drive', 'v3', credentials=credentials)

    # Step 1: Find latest backup file
    backup_file = get_latest_backup_file(FILE_SUFFIX)

    # Step 2: Upload the latest backup
    uploaded_file_id, uploaded_file_name = upload_to_drive(service, backup_file, DRIVE_FOLDER_ID)

    # Step 3: Delete old backups from Drive, except the just-uploaded one
    delete_old_backups_in_drive(service, DRIVE_FOLDER_ID, FILE_SUFFIX, exclude_name=uploaded_file_name)

if __name__ == "__main__":
    main()