mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-10 23:42:37 -07:00
593 lines
No EOL
20 KiB
Python
593 lines
No EOL
20 KiB
Python
# This file is part of PlexPy.
|
|
#
|
|
# PlexPy is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# PlexPy is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import threading
|
|
import webbrowser
|
|
import sqlite3
|
|
import cherrypy
|
|
import datetime
|
|
import uuid
|
|
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
from apscheduler.triggers.interval import IntervalTrigger
|
|
|
|
from plexpy import versioncheck, logger, monitor, plextv
|
|
import plexpy.config
|
|
|
|
PROG_DIR = None
|
|
FULL_PATH = None
|
|
|
|
ARGS = None
|
|
SIGNAL = None
|
|
|
|
SYS_PLATFORM = None
|
|
SYS_ENCODING = None
|
|
|
|
QUIET = False
|
|
VERBOSE = True
|
|
DAEMON = False
|
|
CREATEPID = False
|
|
PIDFILE = None
|
|
|
|
SCHED = BackgroundScheduler()
|
|
SCHED_LOCK = threading.Lock()
|
|
|
|
INIT_LOCK = threading.Lock()
|
|
_INITIALIZED = False
|
|
started = False
|
|
|
|
DATA_DIR = None
|
|
|
|
CONFIG = None
|
|
|
|
DB_FILE = None
|
|
|
|
LOG_LIST = []
|
|
|
|
INSTALL_TYPE = None
|
|
CURRENT_VERSION = None
|
|
LATEST_VERSION = None
|
|
COMMITS_BEHIND = None
|
|
|
|
UMASK = None
|
|
|
|
|
|
def initialize(config_file):
|
|
with INIT_LOCK:
|
|
|
|
global CONFIG
|
|
global _INITIALIZED
|
|
global CURRENT_VERSION
|
|
global LATEST_VERSION
|
|
global UMASK
|
|
|
|
CONFIG = plexpy.config.Config(config_file)
|
|
|
|
assert CONFIG is not None
|
|
|
|
if _INITIALIZED:
|
|
return False
|
|
|
|
if CONFIG.HTTP_PORT < 21 or CONFIG.HTTP_PORT > 65535:
|
|
plexpy.logger.warn(
|
|
'HTTP_PORT out of bounds: 21 < %s < 65535', CONFIG.HTTP_PORT)
|
|
CONFIG.HTTP_PORT = 8181
|
|
|
|
if CONFIG.HTTPS_CERT == '':
|
|
CONFIG.HTTPS_CERT = os.path.join(DATA_DIR, 'server.crt')
|
|
if CONFIG.HTTPS_KEY == '':
|
|
CONFIG.HTTPS_KEY = os.path.join(DATA_DIR, 'server.key')
|
|
|
|
if not CONFIG.LOG_DIR:
|
|
CONFIG.LOG_DIR = os.path.join(DATA_DIR, 'logs')
|
|
|
|
if not os.path.exists(CONFIG.LOG_DIR):
|
|
try:
|
|
os.makedirs(CONFIG.LOG_DIR)
|
|
except OSError:
|
|
CONFIG.LOG_DIR = None
|
|
|
|
if not QUIET:
|
|
sys.stderr.write("Unable to create the log directory. " \
|
|
"Logging to screen only.\n")
|
|
|
|
# Start the logger, disable console if needed
|
|
logger.initLogger(console=not QUIET, log_dir=CONFIG.LOG_DIR,
|
|
verbose=VERBOSE)
|
|
|
|
if not CONFIG.CACHE_DIR:
|
|
# Put the cache dir in the data dir for now
|
|
CONFIG.CACHE_DIR = os.path.join(DATA_DIR, 'cache')
|
|
if not os.path.exists(CONFIG.CACHE_DIR):
|
|
try:
|
|
os.makedirs(CONFIG.CACHE_DIR)
|
|
except OSError as e:
|
|
logger.error("Could not create cache dir '%s': %s", DATA_DIR, e)
|
|
|
|
# Initialize the database
|
|
logger.info('Checking to see if the database has all tables....')
|
|
try:
|
|
dbcheck()
|
|
except Exception as e:
|
|
logger.error("Can't connect to the database: %s", e)
|
|
|
|
# Check if PlexPy has a uuid
|
|
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
|
|
my_uuid = generate_uuid()
|
|
CONFIG.__setattr__('PMS_UUID', my_uuid)
|
|
CONFIG.write()
|
|
|
|
# Get the currently installed version. Returns None, 'win32' or the git
|
|
# hash.
|
|
CURRENT_VERSION, CONFIG.GIT_BRANCH = versioncheck.getVersion()
|
|
|
|
# Write current version to a file, so we know which version did work.
|
|
# This allowes one to restore to that version. The idea is that if we
|
|
# arrive here, most parts of PlexPy seem to work.
|
|
if CURRENT_VERSION:
|
|
version_lock_file = os.path.join(DATA_DIR, "version.lock")
|
|
|
|
try:
|
|
with open(version_lock_file, "w") as fp:
|
|
fp.write(CURRENT_VERSION)
|
|
except IOError as e:
|
|
logger.error("Unable to write current version to file '%s': %s",
|
|
version_lock_file, e)
|
|
|
|
# Check for new versions
|
|
if CONFIG.CHECK_GITHUB_ON_STARTUP and CONFIG.CHECK_GITHUB:
|
|
try:
|
|
LATEST_VERSION = versioncheck.checkGithub()
|
|
except:
|
|
logger.exception("Unhandled exception")
|
|
LATEST_VERSION = CURRENT_VERSION
|
|
else:
|
|
LATEST_VERSION = CURRENT_VERSION
|
|
|
|
# Get the real PMS urls for SSL and remote access
|
|
if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT:
|
|
plextv.get_real_pms_url()
|
|
|
|
# Refresh the users list on startup
|
|
if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP:
|
|
plextv.refresh_users()
|
|
|
|
# Store the original umask
|
|
UMASK = os.umask(0)
|
|
os.umask(UMASK)
|
|
|
|
_INITIALIZED = True
|
|
return True
|
|
|
|
|
|
def daemonize():
|
|
if threading.activeCount() != 1:
|
|
logger.warn(
|
|
'There are %r active threads. Daemonizing may cause'
|
|
' strange behavior.',
|
|
threading.enumerate())
|
|
|
|
sys.stdout.flush()
|
|
sys.stderr.flush()
|
|
|
|
# Do first fork
|
|
try:
|
|
pid = os.fork() # @UndefinedVariable - only available in UNIX
|
|
if pid != 0:
|
|
sys.exit(0)
|
|
except OSError, e:
|
|
raise RuntimeError("1st fork failed: %s [%d]", e.strerror, e.errno)
|
|
|
|
os.setsid()
|
|
|
|
# Make sure I can read my own files and shut out others
|
|
prev = os.umask(0) # @UndefinedVariable - only available in UNIX
|
|
os.umask(prev and int('077', 8))
|
|
|
|
# Make the child a session-leader by detaching from the terminal
|
|
try:
|
|
pid = os.fork() # @UndefinedVariable - only available in UNIX
|
|
if pid != 0:
|
|
sys.exit(0)
|
|
except OSError, e:
|
|
raise RuntimeError("2nd fork failed: %s [%d]", e.strerror, e.errno)
|
|
|
|
dev_null = file('/dev/null', 'r')
|
|
os.dup2(dev_null.fileno(), sys.stdin.fileno())
|
|
|
|
si = open('/dev/null', "r")
|
|
so = open('/dev/null', "a+")
|
|
se = open('/dev/null', "a+")
|
|
|
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
|
|
|
pid = os.getpid()
|
|
logger.info('Daemonized to PID: %d', pid)
|
|
|
|
if CREATEPID:
|
|
logger.info("Writing PID %d to %s", pid, PIDFILE)
|
|
with file(PIDFILE, 'w') as fp:
|
|
fp.write("%s\n" % pid)
|
|
|
|
|
|
def launch_browser(host, port, root):
|
|
if host == '0.0.0.0':
|
|
host = 'localhost'
|
|
|
|
if CONFIG.ENABLE_HTTPS:
|
|
protocol = 'https'
|
|
else:
|
|
protocol = 'http'
|
|
|
|
try:
|
|
webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root))
|
|
except Exception as e:
|
|
logger.error('Could not launch browser: %s', e)
|
|
|
|
|
|
def initialize_scheduler():
|
|
"""
|
|
Start the scheduled background tasks. Re-schedule if interval settings changed.
|
|
"""
|
|
|
|
|
|
|
|
with SCHED_LOCK:
|
|
|
|
# Check if scheduler should be started
|
|
start_jobs = not len(SCHED.get_jobs())
|
|
|
|
# Update check
|
|
if CONFIG.CHECK_GITHUB_INTERVAL and CONFIG.CHECK_GITHUB:
|
|
minutes = CONFIG.CHECK_GITHUB_INTERVAL
|
|
else:
|
|
minutes = 0
|
|
schedule_job(versioncheck.checkGithub, 'Check GitHub for updates', hours=0, minutes=minutes)
|
|
|
|
# Start checking for new sessions at set interval
|
|
if CONFIG.MONITORING_INTERVAL:
|
|
# Our interval should never be less than 30 seconds
|
|
if CONFIG.MONITORING_INTERVAL > 30:
|
|
seconds = CONFIG.MONITORING_INTERVAL
|
|
else:
|
|
seconds = 30
|
|
else:
|
|
seconds = 0
|
|
|
|
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
|
|
schedule_job(plextv.get_real_pms_url, 'Refresh Plex Server URLs', hours=12, minutes=0, seconds=0)
|
|
schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=seconds)
|
|
|
|
# Refresh the users list
|
|
if CONFIG.REFRESH_USERS_INTERVAL:
|
|
hours = CONFIG.REFRESH_USERS_INTERVAL
|
|
else:
|
|
hours = 0
|
|
|
|
if CONFIG.PMS_TOKEN:
|
|
schedule_job(plextv.refresh_users, 'Refresh users list', hours=hours, minutes=0, seconds=0)
|
|
|
|
# Start scheduler
|
|
if start_jobs and len(SCHED.get_jobs()):
|
|
try:
|
|
SCHED.start()
|
|
except Exception as e:
|
|
logger.info(e)
|
|
|
|
# Debug
|
|
#SCHED.print_jobs()
|
|
|
|
|
|
def schedule_job(function, name, hours=0, minutes=0, seconds=0):
|
|
"""
|
|
Start scheduled job if starting or restarting plexpy.
|
|
Reschedule job if Interval Settings have changed.
|
|
Remove job if if Interval Settings changed to 0
|
|
|
|
"""
|
|
|
|
job = SCHED.get_job(name)
|
|
if job:
|
|
if hours == 0 and minutes == 0 and seconds == 0:
|
|
SCHED.remove_job(name)
|
|
logger.info("Removed background task: %s", name)
|
|
elif job.trigger.interval != datetime.timedelta(hours=hours, minutes=minutes):
|
|
SCHED.reschedule_job(name, trigger=IntervalTrigger(
|
|
hours=hours, minutes=minutes, seconds=seconds))
|
|
logger.info("Re-scheduled background task: %s", name)
|
|
elif hours > 0 or minutes > 0 or seconds > 0:
|
|
SCHED.add_job(function, id=name, trigger=IntervalTrigger(
|
|
hours=hours, minutes=minutes, seconds=seconds))
|
|
logger.info("Scheduled background task: %s", name)
|
|
|
|
|
|
def start():
|
|
global started
|
|
|
|
if _INITIALIZED:
|
|
initialize_scheduler()
|
|
started = True
|
|
|
|
|
|
def sig_handler(signum=None, frame=None):
|
|
if signum is not None:
|
|
logger.info("Signal %i caught, saving and exiting...", signum)
|
|
shutdown()
|
|
|
|
|
|
def dbcheck():
|
|
conn_db = sqlite3.connect(DB_FILE)
|
|
c_db = conn_db.cursor()
|
|
|
|
# sessions table :: This is a temp table that logs currently active sessions
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
|
'session_key INTEGER, rating_key INTEGER, media_type TEXT, started INTEGER, '
|
|
'paused_counter INTEGER DEFAULT 0, state TEXT, user_id INTEGER, user TEXT, friendly_name TEXT, '
|
|
'ip_address TEXT, machine_id TEXT, player TEXT, platform TEXT, title TEXT, parent_title TEXT, '
|
|
'grandparent_title TEXT, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
|
'view_offset INTEGER DEFAULT 0, duration INTEGER, video_decision TEXT, audio_decision TEXT, '
|
|
'width INTEGER, height INTEGER, container TEXT, video_codec TEXT, audio_codec TEXT, '
|
|
'bitrate INTEGER, video_resolution TEXT, video_framerate TEXT, aspect_ratio TEXT, '
|
|
'audio_channels INTEGER, transcode_protocol TEXT, transcode_container TEXT, '
|
|
'transcode_video_codec TEXT, transcode_audio_codec TEXT, transcode_audio_channels INTEGER,'
|
|
'transcode_width INTEGER, transcode_height INTEGER)'
|
|
)
|
|
|
|
# session_history table :: This is a history table which logs essential stream details
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS session_history (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
|
'started INTEGER, stopped INTEGER, rating_key INTEGER, user_id INTEGER, user TEXT, '
|
|
'ip_address TEXT, paused_counter INTEGER DEFAULT 0, player TEXT, platform TEXT, machine_id TEXT, '
|
|
'parent_rating_key INTEGER, grandparent_rating_key INTEGER, media_type TEXT, view_offset INTEGER DEFAULT 0)'
|
|
)
|
|
|
|
# session_history_media_info table :: This is a table which logs each session's media info
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS session_history_media_info (id INTEGER PRIMARY KEY, '
|
|
'rating_key INTEGER, video_decision TEXT, audio_decision TEXT, duration INTEGER DEFAULT 0, width INTEGER, '
|
|
'height INTEGER, container TEXT, video_codec TEXT, audio_codec TEXT, bitrate INTEGER, video_resolution TEXT, '
|
|
'video_framerate TEXT, aspect_ratio TEXT, audio_channels INTEGER, transcode_protocol TEXT, '
|
|
'transcode_container TEXT, transcode_video_codec TEXT, transcode_audio_codec TEXT, '
|
|
'transcode_audio_channels INTEGER, transcode_width INTEGER, transcode_height INTEGER)'
|
|
)
|
|
|
|
# session_history_metadata table :: This is a table which logs each session's media metadata
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS session_history_metadata (id INTEGER PRIMARY KEY, '
|
|
'rating_key INTEGER, parent_rating_key INTEGER, grandparent_rating_key INTEGER, '
|
|
'title TEXT, parent_title TEXT, grandparent_title TEXT, full_title TEXT, media_index INTEGER, '
|
|
'parent_media_index INTEGER, thumb TEXT, parent_thumb TEXT, grandparent_thumb TEXT, art TEXT, media_type TEXT, '
|
|
'year INTEGER, originally_available_at TEXT, added_at INTEGER, updated_at INTEGER, last_viewed_at INTEGER, '
|
|
'content_rating TEXT, summary TEXT, rating TEXT, duration INTEGER DEFAULT 0, guid TEXT, '
|
|
'directors TEXT, writers TEXT, actors TEXT, genres TEXT, studio TEXT)'
|
|
''
|
|
)
|
|
|
|
# users table :: This table keeps record of the friends list
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
|
'user_id INTEGER DEFAULT NULL UNIQUE, username TEXT NOT NULL UNIQUE, '
|
|
'friendly_name TEXT, thumb TEXT, email TEXT, is_home_user INTEGER DEFAULT NULL, '
|
|
'is_allow_sync INTEGER DEFAULT NULL, is_restricted INTEGER DEFAULT NULL, do_notify INTEGER DEFAULT 1, '
|
|
'keep_history INTEGER DEFAULT 1)'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT started from sessions')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN started INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN paused_counter INTEGER DEFAULT 0'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN state TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN user TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN machine_id TEXT'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT title from sessions')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN title TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN parent_title TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN grandparent_title TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN friendly_name TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN player TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN user_id INTEGER'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT ip_address from sessions')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN ip_address TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN platform TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN parent_rating_key INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN grandparent_rating_key INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN view_offset INTEGER DEFAULT 0'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN duration INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN video_decision TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN audio_decision TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN width INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN height INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN container TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN video_codec TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN audio_codec TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN bitrate INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN video_resolution TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN video_framerate TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN aspect_ratio TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN audio_channels INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_protocol TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_container TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_video_codec TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_audio_codec TEXT'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_audio_channels INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_width INTEGER'
|
|
)
|
|
c_db.execute(
|
|
'ALTER TABLE sessions ADD COLUMN transcode_height INTEGER'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT full_title from session_history_metadata')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE session_history_metadata ADD COLUMN full_title TEXT'
|
|
)
|
|
|
|
# notify_log table :: This is a table which logs notifications sent
|
|
c_db.execute(
|
|
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
|
'session_key INTEGER, rating_key INTEGER, user_id INTEGER, user TEXT, '
|
|
'agent_id INTEGER, agent_name TEXT, on_play INTEGER, on_stop INTEGER, on_watched INTEGER)'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT do_notify from users')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE users ADD COLUMN do_notify INTEGER DEFAULT 1'
|
|
)
|
|
|
|
# Upgrade sessions table from earlier versions
|
|
try:
|
|
c_db.execute('SELECT keep_history from users')
|
|
except sqlite3.OperationalError:
|
|
logger.debug(u"Altering database. Updating database table sessions.")
|
|
c_db.execute(
|
|
'ALTER TABLE users ADD COLUMN keep_history INTEGER DEFAULT 1'
|
|
)
|
|
|
|
conn_db.commit()
|
|
c_db.close()
|
|
|
|
def shutdown(restart=False, update=False):
|
|
cherrypy.engine.exit()
|
|
SCHED.shutdown(wait=False)
|
|
|
|
# Clear any sessions in the db - Not sure yet if we should do this. More testing required
|
|
# logger.debug(u'Clearing Plex sessions.')
|
|
# monitor.drop_session_db()
|
|
|
|
CONFIG.write()
|
|
|
|
if not restart and not update:
|
|
logger.info('PlexPy is shutting down...')
|
|
|
|
if update:
|
|
logger.info('PlexPy is updating...')
|
|
try:
|
|
versioncheck.update()
|
|
except Exception as e:
|
|
logger.warn('PlexPy failed to update: %s. Restarting.', e)
|
|
|
|
if CREATEPID:
|
|
logger.info('Removing pidfile %s', PIDFILE)
|
|
os.remove(PIDFILE)
|
|
|
|
if restart:
|
|
logger.info('PlexPy is restarting...')
|
|
popen_list = [sys.executable, FULL_PATH]
|
|
popen_list += ARGS
|
|
if '--nolaunch' not in popen_list:
|
|
popen_list += ['--nolaunch']
|
|
logger.info('Restarting PlexPy with %s', popen_list)
|
|
subprocess.Popen(popen_list, cwd=os.getcwd())
|
|
|
|
os._exit(0)
|
|
|
|
def generate_uuid():
|
|
logger.debug(u"Generating UUID...")
|
|
return uuid.uuid4().hex |