Project

General

Profile

Download (5.65 KB) Statistics
| Branch: | Tag: | Revision:
#!/usr/bin/python3
import datetime
import logging
import os
import subprocess
import sys
import threading
import time

from hbkcd.config import *
from hbkcd.command_server import StoppableHTTPServer, CommandHandler
from hbkcd.queue import ENCODE_QUEUE

#
# HbkCD - Handbrake Control Daemon
#

def __test_executable(exe_name, exe_path):
""" Helper function to cut down on code duplication.
"""
# Make sure specified exe path exists and is a file
if not os.path.isfile(exe_path):
logging.error('{:s} does not exist at path: {:s}'
.format(exe_name, exe_path))
return False
# Make sure the specified exe file is executable
if not os.access(exe_path, os.X_OK):
logging.error('{:s} exists but is not executable ({:s})'
.format(exe_name, exe_path))
return False
return True

def check_configuration():
""" Check runtime parameters for correctness before attempting to use them.
"""
# Check for both the Handbrake and ffprobe executables
for exe in [('Handbrake', HANDBRAKE_PATH), ('ffprobe', FFPROBE_PATH)]:
if not __test_executable(exe[0], exe[1]):
return False
logging.debug('Runtime configuration checks OKAY')
return True
def datetime_diff(dt_start, dt_end):
""" Helper function to calculate the elapsed time between to datetime
objects and return in a readable "HH::MM:SS" string format.
"""
elapsed = dt_start - dt_end
hours, remainder = divmod(elapsed.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
elapsed_str = '{:02}:{:02}:{:02}'
elapsed_str = elapsed_str.format(int(hours), int(minutes),
int(seconds))
return elapsed_str

def main():

# Configure logging before attempting anything serious
logging.basicConfig(format=LOG_FORMAT_STR,
datefmt=LOG_DATE_FORMAT_STR,
filename=LOGFILE_PATH,
level=DEFAULT_LOG_LEVEL)
logging.info('hbkcd started')
# Validate runtime configuration before proceeding
if not check_configuration():
return -1
# Create the command server
logging.info('Starting command server')
server = StoppableHTTPServer(('', COMMAND_SERVER_PORT), CommandHandler)
# Start the command server in a separate "thread"
thread = threading.Thread(None, server.run)
thread.start()
logging.info('Command server running')
# Run the command server until CTRL-C'ed
try:
while True:
time.sleep(1)
item = ENCODE_QUEUE.get_next()
if item is None:
continue
# Mark next item as in progress
item.in_progress = True
item.encode_started = datetime.datetime.now()
# Start Handbrake process
cmd = item.build_hbk_cmd()
hbk_proc = subprocess.Popen(cmd,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
encoding='utf-8')
# Create an interator to the stdout of the process so we can
# monitor status
proc_stdout = iter(hbk_proc.stdout.readline, '')
status_thread = threading.Thread(target=item.update_status,
args=(proc_stdout,))
status_thread.start()
# Let the HandBrake process run and print a message to the log
# every 5 minutes
logging.info('Start encode of {:s}'.format(item.path))
ctr = 0
while hbk_proc.poll() is None:
ctr += 1
if ctr % 300 == 0:
logging.info('Encode in progress... {:s}'.format(item.status))
ctr = 0
time.sleep(1)
item.encode_finished = datetime.datetime.now()
status_thread.join()
item.in_progress = False
# Create encode log
ts_str = item.encode_started.strftime('%Y%m%d_%H%M%S')
filename = 'encode_{:s}.log'.format(ts_str)
log_path = os.path.join(LOG_DIR, filename)
with open(log_path, 'w') as log_file:
log_file.write(hbk_proc.stderr.read())
logging.info('Write encode log file: {:s}'.format(log_path))
# Calculate elapsed time of encode
elapsed_str = datetime_diff(item.encode_finished, item.encode_started)
# Calculated queued time
queued_str = datetime_diff(item.encode_started, item.time_added)
# Print success or failure message to the log depending on the
# HandBrake process's return code
if hbk_proc.returncode == 0:
fmt_str = 'Encode of {:s} completed in {:s} (queued for: {:s})'
logging.info(fmt_str.format(item.path, elapsed_str, queued_str))
else:
fmt_str = 'Error while encoding {:s} (queued for: {:s})'
logging.error(fmt_str.format(item.path, queued_str))
# Remove the item from the queue
ENCODE_QUEUE.remove(0)
except KeyboardInterrupt:
logging.warn('Command server interrupted')
finally:
# Shutdown server
server.shutdown()
thread.join()
logging.info('Command server stopped')
logging.info('hbkcd stopping')
return 0
if __name__ == '__main__':
sys.exit(main())
(4-4/5)