It assumes that you have a folder in Google Drive where you want the videos to go. You need to edit the Drive folder ID by opening it in a browser and copying it from the end of the URL, then paste it in the code. There are some other assumptions in the script relating to your local storage directories and the video file format, so please read the comments carefully and edit as appropriate if you wish to use it.
Code: Select all
#!/usr/bin/env python3
#
# Syncs ZoneMinder event videos to Google Drive
import os
import sys
import time
from googleapiclient.errors import HttpError
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
def get_drive_files(drive, folder_id):
'''Returns a dict of files in a Google Drive folder by filename:id'''
filedict = {}
try:
files = drive.ListFile({'q': "'{:s}' in parents and trashed=false" \
.format(folder_id)}).GetList()
except HttpError as err:
sys.stderr.write(err + "\n")
return filedict
# Return just the title and id in a dict
for file in files:
fname = file['title']
fid = file['id']
filedict[fname] = fid
return filedict
def upload_file(drive, folder_id, file_path):
'''Uploads a file to the Google Drive folder'''
filename = os.path.basename(file_path)
try:
f = drive.CreateFile({'title': filename, 'parents': [{'id': folder_id}]})
f.SetContentFile(file_path)
f.Upload()
f = None
except HttpError as err:
sys.stderr.write(err + "\n")
def delete_file(drive, file_id):
'''Deletes a file by ID from Google Drive'''
f = drive.CreateFile({'id': file_id})
try:
f.Delete()
except HttpError as err:
sys.stderr.write(err + "\n")
if __name__ == "__main__":
# The ID is in the url when opening the folder in the browser
drive_folder_id = "EDIT ME"
# How often to check for new files (in seconds)
cycle_time = 20
# Top-level ZoneMinder events directory
events_dir = os.path.join("/var", "cache", "zoneminder", "events")
# Subdirectories to search (recursively) for new events
events_subdirs = ["1", "2", "3", "4", "5", "6", "7", "8"]
# Authentication to Google Drive API
gauth = GoogleAuth()
# Rather than using local webserver authentication, which requires user interaction
# every time, we're using the settings.yaml method to automatically authenticate.
# See: https://pythonhosted.org/PyDrive/oauth.html#authentication-in-two-lines
#gauth.LocalWebserverAuth()
# Google Drive object
drive = GoogleDrive(gauth)
# Dict of files in the Drive folder
drive_files = get_drive_files(drive, drive_folder_id)
# Check for new files and upload them
time_last = time.time()
while True:
# Update current time and time elapsed since last cycle
time_now = time.time()
deltatime = time_now - time_last
# Sleep for the remaining portion of the cycle time
if deltatime < cycle_time:
time.sleep(cycle_time-deltatime)
# Update last time checked now. If the subsequent uploads take longer than the cycle time,
# it will check for new files immediately on the next loop iteration.
time_last = time.time()
# Search for new video files and upload
any_uploaded = False
local_files = []
for subdir in events_subdirs:
for root, dirs, files in os.walk(os.path.join(events_dir, subdir)):
for file in files:
if file.endswith(".mp4"):
local_files.append(file)
# If the modification time is less than 5 seconds ago, don't upload it
# yet, because the event may still be going on.
file_path = os.path.join(root, file)
mtime = os.path.getmtime(file_path)
if time.time() - mtime < 5.0:
ename = file.split("-")[0]
print("Event {:s} may still be in progress. Skipping.".format(ename))
sys.stdout.flush()
continue
if not file in list(drive_files.keys()):
# Upload new video file
sys.stdout.write("Uploading {:s}...".format(file))
sys.stdout.flush()
upload_file(drive, drive_folder_id, file_path)
sys.stdout.write("Done.\n")
sys.stdout.flush()
any_uploaded = True
# Remove any files from Google Drive that are no longer present in local storage
any_deleted = False
for fname, fid in drive_files.items():
if not fname in local_files:
sys.stdout.write("Deleting {:s}...".format(fname))
sys.stdout.flush()
delete_file(drive, fid)
sys.stdout.write("Done.\n")
sys.stdout.flush()
any_deleted = True
# Refresh the list of files on Google Drive
if any_uploaded or any_deleted:
drive_files = get_drive_files(drive, drive_folder_id)