|
|
@ -72,7 +72,7 @@ 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, upload_locations, dbmanager, stop, name, segments_path):
|
|
|
|
def __init__(self, upload_locations, dbmanager, stop, name, segments_path, tags, title_header, description_footer):
|
|
|
|
"""upload_locations is a map {location name: upload location backend}
|
|
|
|
"""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.
|
|
|
@ -84,6 +84,9 @@ class Cutter(object):
|
|
|
|
self.dbmanager = dbmanager
|
|
|
|
self.dbmanager = dbmanager
|
|
|
|
self.stop = stop
|
|
|
|
self.stop = stop
|
|
|
|
self.segments_path = segments_path
|
|
|
|
self.segments_path = segments_path
|
|
|
|
|
|
|
|
self.tags = tags
|
|
|
|
|
|
|
|
self.title_header = title_header
|
|
|
|
|
|
|
|
self.description_footer = description_footer
|
|
|
|
self.logger = logging.getLogger(type(self).__name__)
|
|
|
|
self.logger = logging.getLogger(type(self).__name__)
|
|
|
|
self.refresh_conn()
|
|
|
|
self.refresh_conn()
|
|
|
|
|
|
|
|
|
|
|
@ -341,11 +344,16 @@ class Cutter(object):
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
video_id = upload_backend.upload_video(
|
|
|
|
video_id = upload_backend.upload_video(
|
|
|
|
title=job.video_title,
|
|
|
|
title=(
|
|
|
|
description=job.video_description,
|
|
|
|
"{} - {}".format(self.title_header, job.video_title)
|
|
|
|
tags=[], # TODO
|
|
|
|
if self.title_header else job.video_title
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
description=(
|
|
|
|
|
|
|
|
"{}\n\n{}".format(job.video_description, self.description_footer)
|
|
|
|
|
|
|
|
if self.description_footer else job.video_description
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
tags=self.tags,
|
|
|
|
data=upload_wrapper(),
|
|
|
|
data=upload_wrapper(),
|
|
|
|
hidden=True, # TODO remove when not testing
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
except JobConsistencyError:
|
|
|
|
except JobConsistencyError:
|
|
|
|
raise # this ensures it's not caught in the next except block
|
|
|
|
raise # this ensures it's not caught in the next except block
|
|
|
@ -515,7 +523,18 @@ class TranscodeChecker(object):
|
|
|
|
return result.rowcount
|
|
|
|
return result.rowcount
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(dbconnect, config, creds_file, name=None, base_dir=".", metrics_port=8003, backdoor_port=0):
|
|
|
|
def main(
|
|
|
|
|
|
|
|
dbconnect,
|
|
|
|
|
|
|
|
config,
|
|
|
|
|
|
|
|
creds_file,
|
|
|
|
|
|
|
|
name=None,
|
|
|
|
|
|
|
|
base_dir=".",
|
|
|
|
|
|
|
|
tags='',
|
|
|
|
|
|
|
|
title_header="",
|
|
|
|
|
|
|
|
description_footer="",
|
|
|
|
|
|
|
|
metrics_port=8003,
|
|
|
|
|
|
|
|
backdoor_port=0,
|
|
|
|
|
|
|
|
):
|
|
|
|
"""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
|
|
|
@ -534,6 +553,19 @@ def main(dbconnect, config, creds_file, name=None, base_dir=".", metrics_port=80
|
|
|
|
creds_file should contain any required credentials for the upload backends, as JSON.
|
|
|
|
creds_file should contain any required credentials for the upload backends, as JSON.
|
|
|
|
|
|
|
|
|
|
|
|
name defaults to hostname.
|
|
|
|
name defaults to hostname.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tags should be a comma-seperated list of tags to attach to all videos.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
title_header will be prepended to all video titles, seperated by a " - ".
|
|
|
|
|
|
|
|
description_footer will be added as a seperate paragraph at the end of all video descriptions.
|
|
|
|
|
|
|
|
For example, with --title-header foo --description-footer 'A video of foo.',
|
|
|
|
|
|
|
|
then a video with title 'bar' and a description 'Bar with baz' would actually have:
|
|
|
|
|
|
|
|
title: foo - bar
|
|
|
|
|
|
|
|
description:
|
|
|
|
|
|
|
|
Bar with baz
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A video of foo.
|
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
common.PromLogCountsHandler.install()
|
|
|
|
common.PromLogCountsHandler.install()
|
|
|
|
common.install_stacksampler()
|
|
|
|
common.install_stacksampler()
|
|
|
@ -545,6 +577,8 @@ def main(dbconnect, config, creds_file, name=None, base_dir=".", metrics_port=80
|
|
|
|
if name is None:
|
|
|
|
if name is None:
|
|
|
|
name = socket.gethostname()
|
|
|
|
name = socket.gethostname()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tags = tags.split(',') if tags else []
|
|
|
|
|
|
|
|
|
|
|
|
stop = gevent.event.Event()
|
|
|
|
stop = gevent.event.Event()
|
|
|
|
gevent.signal(signal.SIGTERM, stop.set) # shut down on sigterm
|
|
|
|
gevent.signal(signal.SIGTERM, stop.set) # shut down on sigterm
|
|
|
|
|
|
|
|
|
|
|
@ -583,7 +617,7 @@ def main(dbconnect, config, creds_file, name=None, base_dir=".", metrics_port=80
|
|
|
|
if backend.needs_transcode and not no_transcode_check:
|
|
|
|
if backend.needs_transcode and not no_transcode_check:
|
|
|
|
needs_transcode_check.append(backend)
|
|
|
|
needs_transcode_check.append(backend)
|
|
|
|
|
|
|
|
|
|
|
|
cutter = Cutter(upload_locations, dbmanager, stop, name, base_dir)
|
|
|
|
cutter = Cutter(upload_locations, dbmanager, stop, name, base_dir, tags, title_header, description_footer)
|
|
|
|
transcode_checkers = [
|
|
|
|
transcode_checkers = [
|
|
|
|
TranscodeChecker(backend, dbmanager, stop)
|
|
|
|
TranscodeChecker(backend, dbmanager, stop)
|
|
|
|
for backend in needs_transcode_check
|
|
|
|
for backend in needs_transcode_check
|
|
|
|