cutter: Allow job to specify upload location

This lays the groundwork for being able to cut to many upload locations.
Right now, only a single location can be configured, and only youtube is supported.
pull/100/head
Mike Lang 5 years ago
parent 9ed8facce8
commit 15f879682d

@ -72,15 +72,15 @@ class Cutter(object):
ERROR_RETRY_INTERVAL = 5 ERROR_RETRY_INTERVAL = 5
RETRYABLE_UPLOAD_ERROR_WAIT_INTERVAL = 5 RETRYABLE_UPLOAD_ERROR_WAIT_INTERVAL = 5
def __init__(self, youtube, dbmanager, stop, name, segments_path): def __init__(self, upload_locations, dbmanager, stop, name, segments_path):
"""youtube is an authenticated and initialized youtube api client. """upload_locations is a map {location name: upload location backend}
Conn is a database connection. Conn is a database connection.
Stop is an Event triggering graceful shutdown when set. Stop is an Event triggering graceful shutdown when set.
Name is this uploader's unique name. Name is this uploader's unique name.
Segments path is where to look for segments. Segments path is where to look for segments.
""" """
self.name = name self.name = name
self.youtube = youtube self.upload_locations = upload_locations
self.dbmanager = dbmanager self.dbmanager = dbmanager
self.stop = stop self.stop = stop
self.segments_path = segments_path self.segments_path = segments_path
@ -171,15 +171,18 @@ class Cutter(object):
def list_candidates(self): def list_candidates(self):
"""Return a list of all available candidates that we might be able to cut.""" """Return a list of all available candidates that we might be able to cut."""
# We only accept candidates if they haven't excluded us by whitelist,
# and we are capable of uploading to their desired upload location.
built_query = sql.SQL(""" built_query = sql.SQL("""
SELECT id, {} SELECT id, {}
FROM events FROM events
WHERE state = 'EDITED' WHERE state = 'EDITED'
AND (uploader_whitelist IS NULL OR %(name)s = ANY (uploader_whitelist)) AND (uploader_whitelist IS NULL OR %(name)s = ANY (uploader_whitelist))
AND upload_location = ANY (%(upload_locations)s)
""").format( """).format(
sql.SQL(", ").join(sql.Identifier(key) for key in CUT_JOB_PARAMS) sql.SQL(", ").join(sql.Identifier(key) for key in CUT_JOB_PARAMS)
) )
result = query(self.conn, built_query, name=self.name) result = query(self.conn, built_query, name=self.name, upload_locations=self.upload_locations.keys())
return result.fetchall() return result.fetchall()
def check_candidate(self, candidate): def check_candidate(self, candidate):
@ -242,9 +245,9 @@ class Cutter(object):
at which point it will re-sync with DB as best it can. at which point it will re-sync with DB as best it can.
This situation almost certainly requires operator intervention. This situation almost certainly requires operator intervention.
""" """
# TODO handle multiple upload locations. Currently everything's hard-coded to youtube.
self.logger.info("Cutting and uploading job {}".format(format_job(job))) upload_backend = self.upload_locations[job.upload_location]
self.logger.info("Cutting and uploading job {} to {}".format(format_job(job), upload_backend))
cut = cut_segments(job.segments, job.video_start, job.video_end) cut = cut_segments(job.segments, job.video_start, job.video_end)
# This flag tracks whether we've told requests to finalize the upload, # This flag tracks whether we've told requests to finalize the upload,
@ -322,7 +325,7 @@ class Cutter(object):
# from requests.post() are not recoverable. # from requests.post() are not recoverable.
try: try:
video_id = self.youtube.upload_video( video_id = upload_backend.upload_video(
title=job.video_title, title=job.video_title,
description=job.video_description, description=job.video_description,
tags=[], # TODO tags=[], # TODO
@ -434,7 +437,7 @@ class TranscodeChecker(object):
def __init__(self, youtube, dbmanager, stop): def __init__(self, youtube, dbmanager, stop):
""" """
youtube is an authenticated and initialized youtube api client. youtube is an authenticated and initialized youtube upload backend.
Conn is a database connection. Conn is a database connection.
Stop is an Event triggering graceful shutdown when set. Stop is an Event triggering graceful shutdown when set.
""" """
@ -495,12 +498,13 @@ class TranscodeChecker(object):
return result.rowcount return result.rowcount
def main(dbconnect, youtube_creds_file, name=None, base_dir=".", metrics_port=8003, backdoor_port=0): def main(dbconnect, youtube_creds_file, name=None, base_dir=".", metrics_port=8003, backdoor_port=0, upload_location=""):
"""dbconnect should be a postgres connection string, which is either a space-separated """dbconnect should be a postgres connection string, which is either a space-separated
list of key=value pairs, or a URI like: list of key=value pairs, or a URI like:
postgresql://USER:PASSWORD@HOST/DBNAME?KEY=VALUE postgresql://USER:PASSWORD@HOST/DBNAME?KEY=VALUE
youtube_creds_file should be a json file containing keys 'client_id', 'client_secret' and 'refresh_token'. youtube_creds_file should be a json file containing keys 'client_id', 'client_secret' and 'refresh_token'.
upload_location is the name of the upload location this youtube creds file gives access to.
name defaults to hostname. name defaults to hostname.
""" """
@ -538,7 +542,7 @@ def main(dbconnect, youtube_creds_file, name=None, base_dir=".", metrics_port=80
client_secret=youtube_creds['client_secret'], client_secret=youtube_creds['client_secret'],
refresh_token=youtube_creds['refresh_token'], refresh_token=youtube_creds['refresh_token'],
) )
cutter = Cutter(youtube, dbmanager, stop, name, base_dir) cutter = Cutter({upload_location: youtube}, dbmanager, stop, name, base_dir)
transcode_checker = TranscodeChecker(youtube, dbmanager, stop) transcode_checker = TranscodeChecker(youtube, dbmanager, stop)
jobs = [ jobs = [
gevent.spawn(cutter.run), gevent.spawn(cutter.run),

Loading…
Cancel
Save