Showing posts with label google drive. Show all posts
Showing posts with label google drive. Show all posts

2015-06-14

Motion Google Drive Uploader for OAuth 2.0

Three years ago I wrote the original script to upload video to Google Drive as a trigger from Motion. Unfortunately Google recently removed support for the old security model and you now have to use OAuth 2.0. Also the gdata libraries have been superseded by the Google API Python Client. A few people have written alternatives to my original script quicker than I did, but here's my new version.

Note: I'm not using any third party libraries like PyDrive for example, this script goes straight to the Google APIs. (PyDrive has not been touched for a long time by its author and is missing features).

Motion Google Drive Uploader on Github

Installation

Google setup:


  1. Go to https://code.google.com/apis/console - make sure you're logged in as the correct user for the Drive you want to use.
  2. Use the drop-down at the top of the page to create a project called 'Uploader'.
  3. Click on "Enable an API" then "Drive API" and then click the "Enable API" button
  4. Next go to "APIs & auth -> Credentials" menu and click "Create new Client ID".
  5. Set Application type to "Installed application" and click "Configure Consent Screen"
  6. Set the Product Name to "Uploader"
  7. You'll be returned back to the dialog. Make sure "Installed application" and "other" are selected and then click "Create Client ID".
  8. Download the JSON file.
  9. Rename it to client_secrets.json and put it somewhere like /home/pi/.

Script setup:

  1. Go to /home/pi/ and get the uploader.py from github: git clone https://github.com/jerbly/motion-uploader.git
  2. Update/install Google Python API: sudo pip install --upgrade google-api-python-client
  3. Make uploader.py executable: chmod a+x uploader.py

Configuration:

  1. If you used the git clone command you'll find the example uploader.cfg file in the motion-uploader directory. This now has a couple more options which need setting up. 
  2. oauth/folder - set this to the directory where you have put the client_secrets.json file and where the script can write a credentials. e.g. /home/pi/
  3. docs/snapshot-folder - set this to a public folder name in your drive if you wish to use this feature (explained below).

Initial authentication:

  1. From the command line run the script by hand with your config file and a test avi file e.g. ./uploader.py /home/pi/uploader.cfg /home/pi/test.avi
  2. Copy the URL to your clipboard and paste it into a browser where you are already logged in to Google as the correct user.
  3. Accept and copy the authentication code to the clipboard.
  4. Paste it back in to the command line and hit enter.
  5. This will authenticate you and create a credentials file which will be used for future logins.
Now, finally, you can run up Motion and it should work like it used to.

New feature: Public Snapshot

Motion comes with a feature to periodically take a snapshot regardless of whether motion has been detected. This is a nice feature if you want to have a web site with the latest view from your webcam. You can use Google Drive to host this image rather than installing a web server on your Pi and opening firewalls etc.
  1. Create a public folder in your Google Drive: 
    1. Create a new folder called 'public'
    2. Double click on it
    3. Go to the sharing menu (person icon with + sign)
    4. Click "Advanced" and then "Change..."
    5. Set it to "On - Public on the Web"
  2. Configure your uploader.cfg so docs/snapshot-folder is set to this folder 'public'.
  3. Configure motion.conf to take a snapshot every n seconds named lastsnap.jpg and upload it:
    1. snapshot_interval 300
    2. snapshot_filename lastsnap
    3. on_picture_save /home/pi/motion-uploader/uploader.py /home/pi/uploader.cfg %f snap
To find the public URL that you can bookmark and embed in other pages run the command line with the 'snapurl' option: ./uploader.py /home/pi/uploader.cfg /home/pi/lastsnap.jpg snapurl

It will print something like this: https://googledrive.com/host/{your-folder-id-here}/lastsnap.jpg


2012-06-13

Motion Google Drive Uploader and Emailer

***** UPDATE: The script in this article no longer works due to Google authentication changes. Please use the new script described here: Motion Google Drive Uploader for OAuth 2.0



I'm using the brilliant Motion software with my Raspberry Pi to capture goings-on around my house. This blog post: Battery powered, Wireless, Motion detecting Raspberry Pi and this blog post: Raspberry Pi Webcam explain how.

I set up Lighttpd to point at the directory where Motion was creating video files so that I could go and check periodically to see if any new events had been captured. This works well - I just set up my home router so I could access the http over the Internet and then download the AVIs to my laptop or whatever. The down side to this is that you have to pro-actively look to see if there are new videos and secondly it puts additional strain on the Raspberry Pi to host the files for repeated download.

So, I have created a Python script to upload the AVI to Google Drive, get a URL to view the video on line and then email this using the same GMail account to an address. To keep the Raspberry Pi tidy the script then deletes the local file.

If you have the Google Drive Sync application running too you can see the files as they arrive which is fun:

Source


#!/usr/bin/python2
'''
Created on 6 Jun 2012

@author: Jeremy Blythe

Motion Uploader - uploads videos to Google Drive

Read the blog entry at http://jeremyblythe.blogspot.com for more information
'''

import smtplib
from datetime import datetime

import os.path
import sys

import gdata.data
import gdata.docs.data
import gdata.docs.client
import ConfigParser

class MotionUploader:
    def __init__(self, config_file_path):
        # Load config
        config = ConfigParser.ConfigParser()
        config.read(config_file_path)
        
        # GMail account credentials
        self.username = config.get('gmail', 'user')
        self.password = config.get('gmail', 'password')
        self.from_name = config.get('gmail', 'name')
        self.sender = config.get('gmail', 'sender')
        
        # Recipient email address (could be same as from_addr)
        self.recipient = config.get('gmail', 'recipient')        
        
        # Subject line for email
        self.subject = config.get('gmail', 'subject')
        
        # First line of email message
        self.message = config.get('gmail', 'message')
                
        # Folder (or collection) in Docs where you want the videos to go
        self.folder = config.get('docs', 'folder')
        
        # Options
        self.delete_after_upload = config.getboolean('options', 'delete-after-upload')
        self.send_email = config.getboolean('options', 'send-email')
        
        self._create_gdata_client()

    def _create_gdata_client(self):
        """Create a Documents List Client."""
        self.client = gdata.docs.client.DocsClient(source='motion_uploader')
        self.client.http_client.debug = False
        self.client.client_login(self.username, self.password, service=self.client.auth_service, source=self.client.source)
               
    def _get_folder_resource(self):
        """Find and return the resource whose title matches the given folder."""
        col = None
        for resource in self.client.GetAllResources(uri='/feeds/default/private/full/-/folder'):
            if resource.title.text == self.folder:
                col = resource
                break    
        return col
    
    def _send_email(self,msg):
        '''Send an email using the GMail account.'''
        senddate=datetime.strftime(datetime.now(), '%Y-%m-%d')
        m="Date: %s\r\nFrom: %s <%s>\r\nTo: %s\r\nSubject: %s\r\nX-Mailer: My-Mail\r\n\r\n" % (senddate, self.from_name, self.sender, self.recipient, self.subject)
        server = smtplib.SMTP('smtp.gmail.com:587')
        server.starttls()
        server.login(self.username, self.password)
        server.sendmail(self.sender, self.recipient, m+msg)
        server.quit()    

    def _upload(self, video_file_path, folder_resource):
        '''Upload the video and return the doc'''
        doc = gdata.docs.data.Resource(type='video', title=os.path.basename(video_file_path))
        media = gdata.data.MediaSource()
        media.SetFileHandle(video_file_path, 'video/avi')
        doc = self.client.CreateResource(doc, media=media, collection=folder_resource)
        return doc
    
    def upload_video(self, video_file_path):
        """Upload a video to the specified folder. Then optionally send an email and optionally delete the local file."""
        folder_resource = self._get_folder_resource()
        if not folder_resource:
            raise Exception('Could not find the %s folder' % self.folder)

        doc = self._upload(video_file_path, folder_resource)
                      
        if self.send_email:
            video_link = None
            for link in doc.link:
                if 'video.google.com' in link.href:
                    video_link = link.href
                    break
            # Send an email with the link if found
            msg = self.message
            if video_link:
                msg += '\n\n' + video_link                
            self._send_email(msg)    

        if self.delete_after_upload:
            os.remove(video_file_path)

if __name__ == '__main__':         
    try:
        if len(sys.argv) < 3:
            exit('Motion Uploader - uploads videos to Google Drive\n   by Jeremy Blythe (http://jeremyblythe.blogspot.com)\n\n   Usage: uploader.py {config-file-path} {video-file-path}')
        cfg_path = sys.argv[1]
        vid_path = sys.argv[2]    
        if not os.path.exists(cfg_path):
            exit('Config file does not exist [%s]' % cfg_path)    
        if not os.path.exists(vid_path):
            exit('Video file does not exist [%s]' % vid_path)    
        MotionUploader(cfg_path).upload_video(vid_path)        
    except gdata.client.BadAuthentication:
        exit('Invalid user credentials given.')
    except gdata.client.Error:
        exit('Login Error')
    except Exception as e:
        exit('Error: [%s]' % e)


Installation

If you haven't already got Python and Pip installed then do it now. On my Arch Linux Raspberry Pi I did this:
pacman -S python2
pacman -S python2-pip
Note: This script has been tested on Python 2.7.3
Next get the Google gdata library:
pip2 install gdata
Now download the two files above to somewhere on your machine. Make uploader.py executable:
chmod +x uploader.py
Open uploader.cfg to enter your settings:
[gmail]
# GMail account credentials
name = My Name
user = gmailusername
password = gmailpassword
sender = me@gmail.com

# Recipient email address (could be same as from_addr)
recipient = me@gmail.com

# Subject line for email
subject = Motion detected

# First line of email message
message = Video uploaded

[docs]
# Folder (or collection) in Docs where you want the videos to go
folder = motion

[options]
# Delete the local video file after the upload
delete-after-upload = true

# Send an email after the upload
send-email = true
Make sure you create a folder in your Google Drive to match the setting in the uploader.cfg file. This is the folder where the videos will go.
At this point it's worth testing the script e.g.
./uploader.py /etc/motion/uploader.cfg /srv/http/motion/cam1/85-20120608194940.avi
If all's well you can now change the Motion setting like so:
on_movie_end /root/py/uploader.py /etc/motion/uploader.cfg %f

Enjoy!

***** UPDATE: The script in this article no longer works due to Google authentication changes. Please use the new script described here: Motion Google Drive Uploader for OAuth 2.0