A Revver command line video upload tool
Update: It seems the script had gone missing at some point. It's back .
As you may or may not have noticed, I do a bunch of stuff for Revver. I ended up writing a sort of a tutorial to the Revver API, and as I like to collect all kinds of code samples here, I thought I should crossblog it here. The original is on the Revver developer blog .
One day, I was on a slow internet connection and wanted to upload a few files. I wanted something more batch-oriented than the web-based upload, and I have a personal bias against most current Java runtimes. So I decided to use the cool new API and write a video upload client , and will walk you through what it does in this blog entry. Feel free to "just" use the tool, but hopefully this will also help you in writing your own API clients.
First of all, I wanted to write something that's usable just about
everywhere. I tend to use Python
, so that's what the tool is written
in. The Python standard library didn't seem to be able to do HTTP POST
file upload (think web forms) of large files, so I ended up using
curl
for that. This should work on any Linux/OS X/etc box with Python
and curl installed. All you Ubuntu
/Debian
people just get to say
sudo apt-get install curl
and that's it.
So, let's dive right in. The tool is imaginatively named
revver-upload-video
. The first bit is the command line
parser. Don't be intimidated by the length, this is pretty much
boilerplate code, the actual API-using bits are really small. The
full file is 155 lines, total.
There are basically three kinds of options: mandatory, optional and for developer use. Mandatory options are enforced later on, and developer options are mostly meant for playing with the staging environment and reusing upload tokens from previous, failed, uploads.
#!/usr/bin/python
"""
Guerrilla command line video upload tool.
"""
import optparse, getpass, urlparse, urllib, xmlrpclib, subprocess
def getParser():
parser = optparse.OptionParser(
usage='%prog --title=TEXT --age-rating=NUM [OPTIONS] FILE..',
description='Upload videos to Revver')
parser.set_defaults(
api_url='https://api.revver.com/xml/1.0',
upload_url='http://httpupload.revver.com/',
login=getpass.getuser(),
)
parser.add_option('--login',
help='login name to use (default: %s)' %
parser.defaults['login'])
parser.add_option('--passphrase-file',
help='read passphrase from (prompt if not given)',
metavar='FILE')
parser.add_option('--age-rating',
help='MPAA age rating (mandatory)',
type='int')
parser.add_option('--title',
help='title for the video (mandatory)',
metavar='TEXT')
parser.add_option('--tag',
help='tags (mandatory, repeat for more tags)',
metavar='KEYWORD',
action='append')
parser.add_option('--author',
help='author of the video',
metavar='FULLNAME')
parser.add_option('--url',
help='website for extra info')
parser.add_option('--credits',
help='extra credits',
metavar='TEXT')
parser.add_option('--description',
help='a brief description',
metavar='TEXT')
parser.add_option('--api-url',
help='API URL to contact (developers only)')
parser.add_option('--upload-url',
help='Upload URL to send the file to (developers only)')
parser.add_option('--upload-token',
help='use preallocated token (developers only)',
metavar='HEX',
action='append')
return parser
If you've used optparse
before, there's not much interesting
there. It just instantiates a parser object and returns it, for the
main function to use. Nothing there touches the Revver API yet.
Next up, we have some utility functions. getPassphrase
will read a
passphrase form the file given to --passphrase-file=
, or prompt
the user for one. getAPI
instantiates an XML-RPC client object
with the login and passphrase, and caches it in options
so if you
call getAPI
more than once, you're still only prompted for the
passphrase at most once. Nothing in revver-upload-video
uses that,
but these are meant to be reusable functions.
def getPassphrase(filename=None):
if filename is not None:
f = file(filename)
passphrase = f.readline().rstrip('\n')
f.close()
else:
passphrase = getpass.getpass('Passphrase for video upload: ')
return passphrase
def getAPI(options):
api = getattr(options, 'api', None)
if api is None:
passphrase = getPassphrase(filename=options.passphrase_file)
(scheme, netloc, path, query, fragment) = \
urlparse.urlsplit(options.api_url,
allow_fragments=False)
query = urllib.urlencode([('login', options.login),
('passwd', passphrase)])
url = urlparse.urlunsplit((scheme, netloc, path, query, fragment))
api = xmlrpclib.Server(url)
options.api = api
return api
All right, now we're getting to the actual meat. getToken
calls
the API method video.getUploadTokens
to allocate an upload token
, that lets you upload a file to the Revver archive.
def getToken(api):
url, tokens = api.video.getUploadTokens(1)
assert len(tokens)==1
token = tokens[0]
return url, token
createMedia
creates a new video in the archive from your uploaded
file by calling video.create
in the API. It also adds metadata
like your website URL to the video. Finally, it returns the media id
of the newly-created video.
def createMedia(options, token):
data = {}
if options.credits is not None:
data['credits'] = options.credits
if options.url is not None:
data['url'] = options.url
if options.description is not None:
data['description'] = options.description
if options.author is not None:
data['author'] = options.author
api = getAPI(options)
media_id = api.video.create(token,
options.title,
options.tag,
options.age_rating,
data)
return media_id
Finally, we have the main
function, and the bits that call it when
you run the tool. Here, we actually parse the command line arguments,
enforce the presence of the mandatory options, and bail out unless you
gave it actual files to upload.
For each file given on the command line, we either use one of the
tokens given to us with --upload-token=
, or get one from the API
with getToken
. Then we join the upload URL and the token to get
the place to upload the file to, and run curl
as a subprocess to
do the actual upload. Checking that curl
worked takes 8 lines, and
then we use createMedia
to actually create the video. And that's
it!
def main(progname, args):
parser = getParser()
(options, args) = parser.parse_args()
if options.login is None:
parser.error('You must pass --login=LOGIN')
if options.title is None:
parser.error('You must pass --title=TEXT')
if not options.tag:
parser.error('You must pass --tag=KEYWORD')
if options.age_rating is None:
parser.error('You must pass --age-rating=NUM')
if not args:
parser.error('Pass files to upload on command line')
for filename in args:
if options.upload_token:
token = options.upload_token.pop(0)
url = options.upload_url
else:
api = getAPI(options)
url, token = getToken(api)
print '%s: allocated token %s' % (progname, token)
upload_url = urlparse.urljoin(url, token)
retcode = subprocess.call(['curl',
'-F', '[email protected]%s' % filename,
'--',
upload_url,
])
if retcode < 0:
print >>sys.stderr, '%s: upload aborted by signal %d' % (
progname, -retcode)
sys.exit(1)
elif retcode > 0:
print >>sys.stderr, '%s: upload failed with code %d' % (
progname, retcode)
sys.exit(1)
print '%s: used token %s for %s' % (progname, token, filename)
media_id = createMedia(options, token)
print '%s: created media %r from %r' % (progname,
media_id,
filename)
if __name__ == '__main__':
import os, sys
main(progname=os.path.basename(sys.argv[0]),
args=sys.argv[1:])
At this point, we have all we need to do the same thing as the web-based upload, or the Java upload client. And you can do something similar, by yourself. This file is copyright Revver, Inc, but licensed under the MIT license -- that means you can use it as a base for writing your software, without any real restrictions. Download the whole thing here: revver-upload-video .