Merged in brunnels updated initscript/pidfile handling & adehub fix in base.html

This commit is contained in:
rembo10
2012-12-25 01:01:50 -05:00
6 changed files with 451 additions and 273 deletions
+5 -1
View File
@@ -50,4 +50,8 @@ Thumbs.db
obj/ obj/
[Rr]elease*/ [Rr]elease*/
_ReSharper*/ _ReSharper*/
[Tt]est[Rr]esult* [Tt]est[Rr]esult*
/cache
/logs
.project
.pydevproject
+48 -26
View File
@@ -16,6 +16,7 @@
import os, sys, locale import os, sys, locale
import time import time
import signal
from lib.configobj import ConfigObj from lib.configobj import ConfigObj
@@ -27,7 +28,10 @@ try:
import argparse import argparse
except ImportError: except ImportError:
import lib.argparse as argparse import lib.argparse as argparse
signal.signal(signal.SIGINT, headphones.sig_handler)
signal.signal(signal.SIGTERM, headphones.sig_handler)
def main(): def main():
@@ -36,10 +40,10 @@ def main():
headphones.FULL_PATH = os.path.abspath(sys.executable) headphones.FULL_PATH = os.path.abspath(sys.executable)
else: else:
headphones.FULL_PATH = os.path.abspath(__file__) headphones.FULL_PATH = os.path.abspath(__file__)
headphones.PROG_DIR = os.path.dirname(headphones.FULL_PATH) headphones.PROG_DIR = os.path.dirname(headphones.FULL_PATH)
headphones.ARGS = sys.argv[1:] headphones.ARGS = sys.argv[1:]
# From sickbeard # From sickbeard
headphones.SYS_PLATFORM = sys.platform headphones.SYS_PLATFORM = sys.platform
headphones.SYS_ENCODING = None headphones.SYS_ENCODING = None
@@ -53,7 +57,7 @@ def main():
# for OSes that are poorly configured I'll just force UTF-8 # for OSes that are poorly configured I'll just force UTF-8
if not headphones.SYS_ENCODING or headphones.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'): if not headphones.SYS_ENCODING or headphones.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
headphones.SYS_ENCODING = 'UTF-8' headphones.SYS_ENCODING = 'UTF-8'
# Set up and gather command line arguments # Set up and gather command line arguments
parser = argparse.ArgumentParser(description='Music add-on for SABnzbd+') parser = argparse.ArgumentParser(description='Music add-on for SABnzbd+')
@@ -65,55 +69,73 @@ def main():
parser.add_argument('--config', help='Specify a config file to use') parser.add_argument('--config', help='Specify a config file to use')
parser.add_argument('--nolaunch', action='store_true', help='Prevent browser from launching on startup') parser.add_argument('--nolaunch', action='store_true', help='Prevent browser from launching on startup')
parser.add_argument('--pidfile', help='Create a pid file (only relevant when running as a daemon)') parser.add_argument('--pidfile', help='Create a pid file (only relevant when running as a daemon)')
args = parser.parse_args() args = parser.parse_args()
if args.verbose: if args.verbose:
headphones.VERBOSE = 2 headphones.VERBOSE = 2
elif args.quiet: elif args.quiet:
headphones.VERBOSE = 0 headphones.VERBOSE = 0
if args.daemon: if args.daemon:
headphones.DAEMON=True if sys.platform == 'win32':
headphones.VERBOSE = 0 print "Daemonize not supported under Windows, starting normally"
if args.pidfile : else:
headphones.PIDFILE = args.pidfile headphones.DAEMON=True
headphones.VERBOSE = False
if args.pidfile:
headphones.PIDFILE = str(args.pidfile)
# If the pidfile already exists, headphones may still be running, so exit
if os.path.exists(headphones.PIDFILE):
sys.exit("PID file '" + headphones.PIDFILE + "' already exists. Exiting.")
# The pidfile is only useful in daemon mode, make sure we can write the file properly
if headphones.DAEMON:
headphones.CREATEPID = True
try:
file(headphones.PIDFILE, 'w').write("pid\n")
except IOError, e:
raise SystemExit("Unable to write PID file: %s [%d]" % (e.strerror, e.errno))
else:
logger.warn("Not running in daemon mode. PID file creation disabled.")
if args.datadir: if args.datadir:
headphones.DATA_DIR = args.datadir headphones.DATA_DIR = args.datadir
else: else:
headphones.DATA_DIR = headphones.PROG_DIR headphones.DATA_DIR = headphones.PROG_DIR
if args.config: if args.config:
headphones.CONFIG_FILE = args.config headphones.CONFIG_FILE = args.config
else: else:
headphones.CONFIG_FILE = os.path.join(headphones.DATA_DIR, 'config.ini') headphones.CONFIG_FILE = os.path.join(headphones.DATA_DIR, 'config.ini')
# Try to create the DATA_DIR if it doesn't exist # Try to create the DATA_DIR if it doesn't exist
if not os.path.exists(headphones.DATA_DIR): if not os.path.exists(headphones.DATA_DIR):
try: try:
os.makedirs(headphones.DATA_DIR) os.makedirs(headphones.DATA_DIR)
except OSError: except OSError:
raise SystemExit('Could not create data directory: ' + headphones.DATA_DIR + '. Exiting....') raise SystemExit('Could not create data directory: ' + headphones.DATA_DIR + '. Exiting....')
# Make sure the DATA_DIR is writeable # Make sure the DATA_DIR is writeable
if not os.access(headphones.DATA_DIR, os.W_OK): if not os.access(headphones.DATA_DIR, os.W_OK):
raise SystemExit('Cannot write to the data directory: ' + headphones.DATA_DIR + '. Exiting...') raise SystemExit('Cannot write to the data directory: ' + headphones.DATA_DIR + '. Exiting...')
# Put the database in the DATA_DIR # Put the database in the DATA_DIR
headphones.DB_FILE = os.path.join(headphones.DATA_DIR, 'headphones.db') headphones.DB_FILE = os.path.join(headphones.DATA_DIR, 'headphones.db')
headphones.CFG = ConfigObj(headphones.CONFIG_FILE, encoding='utf-8') headphones.CFG = ConfigObj(headphones.CONFIG_FILE, encoding='utf-8')
# Read config & start logging # Read config & start logging
headphones.initialize() headphones.initialize()
if headphones.DAEMON: if headphones.DAEMON:
if sys.platform == "win32": if sys.platform == "win32":
print "Daemonize not supported under Windows, starting normally" print "Daemonize not supported under Windows, starting normally"
else: else:
headphones.daemonize() headphones.daemonize()
#configure the connection to the musicbrainz database #configure the connection to the musicbrainz database
headphones.mb.startmb() headphones.mb.startmb()
@@ -123,8 +145,8 @@ def main():
logger.info('Starting Headphones on forced port: %i' % http_port) logger.info('Starting Headphones on forced port: %i' % http_port)
else: else:
http_port = int(headphones.HTTP_PORT) http_port = int(headphones.HTTP_PORT)
# Try to start the server. # Try to start the server.
webstart.initialize({ webstart.initialize({
'http_port': http_port, 'http_port': http_port,
'http_host': headphones.HTTP_HOST, 'http_host': headphones.HTTP_HOST,
@@ -133,15 +155,15 @@ def main():
'http_username': headphones.HTTP_USERNAME, 'http_username': headphones.HTTP_USERNAME,
'http_password': headphones.HTTP_PASSWORD, 'http_password': headphones.HTTP_PASSWORD,
}) })
logger.info('Starting Headphones on port: %i' % http_port) logger.info('Starting Headphones on port: %i' % http_port)
if headphones.LAUNCH_BROWSER and not args.nolaunch: if headphones.LAUNCH_BROWSER and not args.nolaunch:
headphones.launch_browser(headphones.HTTP_HOST, http_port, headphones.HTTP_ROOT) headphones.launch_browser(headphones.HTTP_HOST, http_port, headphones.HTTP_ROOT)
# Start the background threads # Start the background threads
headphones.start() headphones.start()
while True: while True:
if not headphones.SIGNAL: if not headphones.SIGNAL:
try: try:
@@ -156,9 +178,9 @@ def main():
headphones.shutdown(restart=True) headphones.shutdown(restart=True)
else: else:
headphones.shutdown(restart=True, update=True) headphones.shutdown(restart=True, update=True)
headphones.SIGNAL = None headphones.SIGNAL = None
return return
if __name__ == "__main__": if __name__ == "__main__":
+12 -12
View File
@@ -11,19 +11,19 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Headphones - ${title}</title> <title>Headphones - ${title}</title>
<meta name="description" content="Headphones 'default' interface - made by Elmar Kouwenhoven"> <meta name="description" content="Headphones 'default' interface - made by Elmar Kouwenhoven">
<meta name="author" content="Elmar Kouwenhoven"> <meta name="author" content="Elmar Kouwenhoven">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="images/favicon.ico"> <link rel="shortcut icon" href="images/favicon.ico">
<link rel="apple-touch-icon" href="images/headphoneslogo.png"> <link rel="apple-touch-icon" href="images/headphoneslogo.png">
<link rel="stylesheet" href="interfaces/default/css/style.css"> <link rel="stylesheet" href="interfaces/default/css/style.css">
<link rel="stylesheet" href="interfaces/default/css/jquery-ui.css"> <link rel="stylesheet" href="interfaces/default/css/jquery-ui.css">
${next.headIncludes()} ${next.headIncludes()}
<script src="js/libs/modernizr-1.7.min.js"></script> <script src="js/libs/modernizr-1.7.min.js"></script>
</head> </head>
<body> <body>
@@ -31,16 +31,16 @@
<div id="ajaxMsg"></div> <div id="ajaxMsg"></div>
% if not headphones.CURRENT_VERSION: % if not headphones.CURRENT_VERSION:
<div id="updatebar"> <div id="updatebar">
You're running an unknown version of Headphones. <a href="update">Update</a> or You're running an unknown version of Headphones. <a href="update">Update</a> or
<a href="#" onclick="$('#updatebar').slideUp('slow');">Close</a> <a href="#" onclick="$('#updatebar').slideUp('slow');">Close</a>
</div> </div>
% elif headphones.CURRENT_VERSION != headphones.LATEST_VERSION and headphones.INSTALL_TYPE != 'win': % elif headphones.CURRENT_VERSION != headphones.LATEST_VERSION and headphones.INSTALL_TYPE != 'win':
<div id="updatebar"> <div id="updatebar">
A <a href="https://github.com/rembo10/headphones/compare/${headphones.CURRENT_VERSION}...${headphones.LATEST_VERSION}"> newer version</a> is available. You're ${headphones.COMMITS_BEHIND} commits behind. <a href="update">Update</a> or <a href="#" onclick="$('#updatebar').slideUp('slow');">Close</a> A <a href="https://github.com/${headphones.GIT_USER}/headphones/compare/${headphones.CURRENT_VERSION}...${headphones.LATEST_VERSION}"> newer version</a> is available. You're ${headphones.COMMITS_BEHIND} commits behind. <a href="update">Update</a> or <a href="#" onclick="$('#updatebar').slideUp('slow');">Close</a>
</div> </div>
% endif % endif
<header> <header>
<div class="wrapper"> <div class="wrapper">
<div id="logo"> <div id="logo">
<a href="home"><img src="images/headphoneslogo.png" alt="headphones"></a> <a href="home"><img src="images/headphoneslogo.png" alt="headphones"></a>
@@ -64,7 +64,7 @@
<input type="submit" value="Add"/> <input type="submit" value="Add"/>
</form> </form>
</div> </div>
</div> </div>
</header> </header>
@@ -91,16 +91,16 @@
%if version.HEADPHONES_VERSION != 'master': %if version.HEADPHONES_VERSION != 'master':
(${version.HEADPHONES_VERSION}) (${version.HEADPHONES_VERSION})
%endif %endif
</div> </div>
</footer> </footer>
<a href="#main" id="toTop"><span>Back to top</span></a> <a href="#main" id="toTop"><span>Back to top</span></a>
</div> </div>
<script src="js/libs/jquery-1.7.2.min.js"></script> <script src="js/libs/jquery-1.7.2.min.js"></script>
<script src="js/libs/jquery-ui.min.js"></script> <script src="js/libs/jquery-ui.min.js"></script>
${next.javascriptIncludes()} ${next.javascriptIncludes()}
<script src="js/plugins.js"></script> <script src="js/plugins.js"></script>
<script src="interfaces/default/js/script.js"></script> <script src="interfaces/default/js/script.js"></script>
<!--[if lt IE 7 ]> <!--[if lt IE 7 ]>
+154 -141
View File
@@ -41,6 +41,7 @@ SYS_ENCODING = None
VERBOSE = 1 VERBOSE = 1
DAEMON = False DAEMON = False
CREATEPID = False
PIDFILE= None PIDFILE= None
SCHED = Scheduler() SCHED = Scheduler()
@@ -74,6 +75,8 @@ API_ENABLED = False
API_KEY = None API_KEY = None
GIT_PATH = None GIT_PATH = None
GIT_USER = None
GIT_BRANCH =None
INSTALL_TYPE = None INSTALL_TYPE = None
CURRENT_VERSION = None CURRENT_VERSION = None
LATEST_VERSION = None LATEST_VERSION = None
@@ -262,9 +265,9 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True):
def initialize(): def initialize():
with INIT_LOCK: with INIT_LOCK:
global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, SYS_PLATFORM, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \ global __INITIALIZED__, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, SYS_PLATFORM, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, \
HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, \ HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, HTTP_PROXY, LAUNCH_BROWSER, API_ENABLED, API_KEY, GIT_PATH, GIT_USER, GIT_BRANCH, \
CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \ CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, MUSIC_DIR, DESTINATION_DIR, \
LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, \ LOSSLESS_DESTINATION_DIR, PREFERRED_QUALITY, PREFERRED_BITRATE, DETECT_BITRATE, ADD_ARTISTS, CORRECT_METADATA, MOVE_FILES, \
RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, KEEP_TORRENT_FILES, \ RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, KEEP_TORRENT_FILES, \
@@ -280,10 +283,10 @@ def initialize():
MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \ MIRROR, CUSTOMHOST, CUSTOMPORT, CUSTOMSLEEP, HPUSER, HPPASS, XBMC_ENABLED, XBMC_HOST, XBMC_USERNAME, XBMC_PASSWORD, XBMC_UPDATE, \
XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \ XBMC_NOTIFY, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, SYNOINDEX_ENABLED, ALBUM_COMPLETION_PCT, PREFERRED_BITRATE_HIGH_BUFFER, \
PREFERRED_BITRATE_LOW_BUFFER,CACHE_SIZEMB PREFERRED_BITRATE_LOW_BUFFER,CACHE_SIZEMB
if __INITIALIZED__: if __INITIALIZED__:
return False return False
# Make sure all the config sections exist # Make sure all the config sections exist
CheckSection('General') CheckSection('General')
CheckSection('SABnzbd') CheckSection('SABnzbd')
@@ -301,18 +304,18 @@ def initialize():
CheckSection('NMA') CheckSection('NMA')
CheckSection('Synoindex') CheckSection('Synoindex')
CheckSection('Advanced') CheckSection('Advanced')
# Set global variables based on config file or use defaults # Set global variables based on config file or use defaults
CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0') CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0')
try: try:
HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181) HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181)
except: except:
HTTP_PORT = 8181 HTTP_PORT = 8181
if HTTP_PORT < 21 or HTTP_PORT > 65535: if HTTP_PORT < 21 or HTTP_PORT > 65535:
HTTP_PORT = 8181 HTTP_PORT = 8181
HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0') HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0')
HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '') HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '')
HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '') HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '')
@@ -322,13 +325,15 @@ def initialize():
API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0)) API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0))
API_KEY = check_setting_str(CFG, 'General', 'api_key', '') API_KEY = check_setting_str(CFG, 'General', 'api_key', '')
GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '')
GIT_USER = check_setting_str(CFG, 'General', 'git_user', 'rembo10')
GIT_BRANCH = check_setting_str(CFG, 'General', 'git_branch', 'master')
LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '') LOG_DIR = check_setting_str(CFG, 'General', 'log_dir', '')
CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', '') CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', '')
CHECK_GITHUB = bool(check_setting_int(CFG, 'General', 'check_github', 1)) CHECK_GITHUB = bool(check_setting_int(CFG, 'General', 'check_github', 1))
CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, 'General', 'check_github_on_startup', 1)) CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, 'General', 'check_github_on_startup', 1))
CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360) CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360)
MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '') MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '')
DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '') DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '')
LOSSLESS_DESTINATION_DIR = check_setting_str(CFG, 'General', 'lossless_destination_dir', '') LOSSLESS_DESTINATION_DIR = check_setting_str(CFG, 'General', 'lossless_destination_dir', '')
@@ -356,12 +361,12 @@ def initialize():
AUTOWANT_UPCOMING = bool(check_setting_int(CFG, 'General', 'autowant_upcoming', 1)) AUTOWANT_UPCOMING = bool(check_setting_int(CFG, 'General', 'autowant_upcoming', 1))
AUTOWANT_ALL = bool(check_setting_int(CFG, 'General', 'autowant_all', 0)) AUTOWANT_ALL = bool(check_setting_int(CFG, 'General', 'autowant_all', 0))
KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0)) KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0))
SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440) SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440)
LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1)) LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1))
LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300) LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300)
DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5) DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5)
TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '') TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '')
NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10')
ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0)) ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0))
@@ -372,7 +377,7 @@ def initialize():
WAFFLES = bool(check_setting_int(CFG, 'Waffles', 'waffles', 0)) WAFFLES = bool(check_setting_int(CFG, 'Waffles', 'waffles', 0))
WAFFLES_UID = check_setting_str(CFG, 'Waffles', 'waffles_uid', '') WAFFLES_UID = check_setting_str(CFG, 'Waffles', 'waffles_uid', '')
WAFFLES_PASSKEY = check_setting_str(CFG, 'Waffles', 'waffles_passkey', '') WAFFLES_PASSKEY = check_setting_str(CFG, 'Waffles', 'waffles_passkey', '')
RUTRACKER = bool(check_setting_int(CFG, 'Rutracker', 'rutracker', 0)) RUTRACKER = bool(check_setting_int(CFG, 'Rutracker', 'rutracker', 0))
RUTRACKER_USER = check_setting_str(CFG, 'Rutracker', 'rutracker_user', '') RUTRACKER_USER = check_setting_str(CFG, 'Rutracker', 'rutracker_user', '')
RUTRACKER_PASSWORD = check_setting_str(CFG, 'Rutracker', 'rutracker_password', '') RUTRACKER_PASSWORD = check_setting_str(CFG, 'Rutracker', 'rutracker_password', '')
@@ -386,20 +391,20 @@ def initialize():
SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '') SAB_PASSWORD = check_setting_str(CFG, 'SABnzbd', 'sab_password', '')
SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '') SAB_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '')
SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '') SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '')
NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0)) NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0))
NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '') NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '')
NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '') NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '')
NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0))
NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '')
NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '') NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '')
NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1)) NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1))
# Need to pack the extra newznabs back into a list of tuples # Need to pack the extra newznabs back into a list of tuples
flattened_newznabs = check_setting_str(CFG, 'Newznab', 'extra_newznabs', [], log=False) flattened_newznabs = check_setting_str(CFG, 'Newznab', 'extra_newznabs', [], log=False)
EXTRA_NEWZNABS = list(itertools.izip(*[itertools.islice(flattened_newznabs, i, None, 3) for i in range(3)])) EXTRA_NEWZNABS = list(itertools.izip(*[itertools.islice(flattened_newznabs, i, None, 3) for i in range(3)]))
NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0)) NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0))
NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '')
NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '')
@@ -407,18 +412,18 @@ def initialize():
NEWZBIN = bool(check_setting_int(CFG, 'Newzbin', 'newzbin', 0)) NEWZBIN = bool(check_setting_int(CFG, 'Newzbin', 'newzbin', 0))
NEWZBIN_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '') NEWZBIN_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '')
NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '') NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '')
NZBSRUS = bool(check_setting_int(CFG, 'NZBsRus', 'nzbsrus', 0)) NZBSRUS = bool(check_setting_int(CFG, 'NZBsRus', 'nzbsrus', 0))
NZBSRUS_UID = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_uid', '') NZBSRUS_UID = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_uid', '')
NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '') NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '')
LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '') LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '')
INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default') INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default')
FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755') FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755')
ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '') ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '')
ENCODER_PATH = check_setting_str(CFG, 'General', 'encoder_path', '') ENCODER_PATH = check_setting_str(CFG, 'General', 'encoder_path', '')
ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg') ENCODER = check_setting_str(CFG, 'General', 'encoder', 'ffmpeg')
XLDPROFILE = check_setting_str(CFG, 'General', 'xldprofile', '') XLDPROFILE = check_setting_str(CFG, 'General', 'xldprofile', '')
BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192) BITRATE = check_setting_int(CFG, 'General', 'bitrate', 192)
@@ -433,28 +438,28 @@ def initialize():
PROWL_ENABLED = bool(check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0)) PROWL_ENABLED = bool(check_setting_int(CFG, 'Prowl', 'prowl_enabled', 0))
PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '') PROWL_KEYS = check_setting_str(CFG, 'Prowl', 'prowl_keys', '')
PROWL_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0)) PROWL_ONSNATCH = bool(check_setting_int(CFG, 'Prowl', 'prowl_onsnatch', 0))
PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0) PROWL_PRIORITY = check_setting_int(CFG, 'Prowl', 'prowl_priority', 0)
XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0)) XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0))
XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '') XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '')
XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '') XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '')
XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '') XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '')
XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0)) XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0))
XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0)) XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0))
NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0)) NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0))
NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '') NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '')
NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0) NMA_PRIORITY = check_setting_int(CFG, 'NMA', 'nma_priority', 0)
NMA_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_onsnatch', 0)) NMA_ONSNATCH = bool(check_setting_int(CFG, 'NMA', 'nma_onsnatch', 0))
SYNOINDEX_ENABLED = bool(check_setting_int(CFG, 'Synoindex', 'synoindex_enabled', 0)) SYNOINDEX_ENABLED = bool(check_setting_int(CFG, 'Synoindex', 'synoindex_enabled', 0))
PUSHOVER_ENABLED = bool(check_setting_int(CFG, 'Pushover', 'pushover_enabled', 0)) PUSHOVER_ENABLED = bool(check_setting_int(CFG, 'Pushover', 'pushover_enabled', 0))
PUSHOVER_KEYS = check_setting_str(CFG, 'Pushover', 'pushover_keys', '') PUSHOVER_KEYS = check_setting_str(CFG, 'Pushover', 'pushover_keys', '')
PUSHOVER_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_onsnatch', 0)) PUSHOVER_ONSNATCH = bool(check_setting_int(CFG, 'Pushover', 'pushover_onsnatch', 0))
PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0) PUSHOVER_PRIORITY = check_setting_int(CFG, 'Pushover', 'pushover_priority', 0)
MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org') MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org')
CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost') CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost')
CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000) CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000)
@@ -463,9 +468,9 @@ def initialize():
HPPASS = check_setting_str(CFG, 'General', 'hppass', '') HPPASS = check_setting_str(CFG, 'General', 'hppass', '')
CACHE_SIZEMB = check_setting_int(CFG,'Advanced','cache_sizemb',32) CACHE_SIZEMB = check_setting_int(CFG,'Advanced','cache_sizemb',32)
ALBUM_COMPLETION_PCT = check_setting_int(CFG, 'Advanced', 'album_completion_pct', 80) ALBUM_COMPLETION_PCT = check_setting_int(CFG, 'Advanced', 'album_completion_pct', 80)
# update folder formats in the config & bump up config version # update folder formats in the config & bump up config version
if CONFIG_VERSION == '0': if CONFIG_VERSION == '0':
from headphones.helpers import replace_all from headphones.helpers import replace_all
@@ -473,9 +478,9 @@ def initialize():
folder_values = { 'artist' : 'Artist', 'album':'Album', 'year' : 'Year', 'releasetype' : 'Type', 'first' : 'First', 'lowerfirst' : 'first' } folder_values = { 'artist' : 'Artist', 'album':'Album', 'year' : 'Year', 'releasetype' : 'Type', 'first' : 'First', 'lowerfirst' : 'first' }
FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
CONFIG_VERSION = '1' CONFIG_VERSION = '1'
if CONFIG_VERSION == '1': if CONFIG_VERSION == '1':
from headphones.helpers import replace_all from headphones.helpers import replace_all
@@ -501,32 +506,32 @@ def initialize():
'year': '$year', 'year': '$year',
'type': '$type', 'type': '$type',
'first': '$first' 'first': '$first'
} }
FILE_FORMAT = replace_all(FILE_FORMAT, file_values) FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values) FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
CONFIG_VERSION = '2' CONFIG_VERSION = '2'
if CONFIG_VERSION == '2': if CONFIG_VERSION == '2':
# Update the config to use direct path to the encoder rather than the encoder folder # Update the config to use direct path to the encoder rather than the encoder folder
if ENCODERFOLDER: if ENCODERFOLDER:
ENCODER_PATH = os.path.join(ENCODERFOLDER, ENCODER) ENCODER_PATH = os.path.join(ENCODERFOLDER, ENCODER)
CONFIG_VERSION = '3' CONFIG_VERSION = '3'
if not LOG_DIR: if not LOG_DIR:
LOG_DIR = os.path.join(DATA_DIR, 'logs') LOG_DIR = os.path.join(DATA_DIR, 'logs')
if not os.path.exists(LOG_DIR): if not os.path.exists(LOG_DIR):
try: try:
os.makedirs(LOG_DIR) os.makedirs(LOG_DIR)
except OSError: except OSError:
if VERBOSE: if VERBOSE:
print 'Unable to create the log directory. Logging to screen only.' print 'Unable to create the log directory. Logging to screen only.'
# Start the logger, silence console logging if we need to # Start the logger, silence console logging if we need to
logger.headphones_log.initLogger(verbose=VERBOSE) logger.headphones_log.initLogger(verbose=VERBOSE)
if not CACHE_DIR: if not CACHE_DIR:
# Put the cache dir in the data dir for now # Put the cache dir in the data dir for now
CACHE_DIR = os.path.join(DATA_DIR, 'cache') CACHE_DIR = os.path.join(DATA_DIR, 'cache')
@@ -535,23 +540,23 @@ def initialize():
os.makedirs(CACHE_DIR) os.makedirs(CACHE_DIR)
except OSError: except OSError:
logger.error('Could not create cache dir. Check permissions of datadir: ' + DATA_DIR) logger.error('Could not create cache dir. Check permissions of datadir: ' + DATA_DIR)
# Sanity check for search interval. Set it to at least 6 hours # Sanity check for search interval. Set it to at least 6 hours
if SEARCH_INTERVAL < 360: if SEARCH_INTERVAL < 360:
logger.info("Search interval too low. Resetting to 6 hour minimum") logger.info("Search interval too low. Resetting to 6 hour minimum")
SEARCH_INTERVAL = 360 SEARCH_INTERVAL = 360
# Initialize the database # Initialize the database
logger.info('Checking to see if the database has all tables....') logger.info('Checking to see if the database has all tables....')
try: try:
dbcheck() dbcheck()
except Exception, e: except Exception, e:
logger.error("Can't connect to the database: %s" % e) logger.error("Can't connect to the database: %s" % e)
# Get the currently installed version - returns None, 'win32' or the git hash # Get the currently installed version - returns None, 'win32' or the git hash
# Also sets INSTALL_TYPE variable to 'win', 'git' or 'source' # Also sets INSTALL_TYPE variable to 'win', 'git' or 'source'
CURRENT_VERSION = versioncheck.getVersion() CURRENT_VERSION = versioncheck.getVersion()
# Check for new versions # Check for new versions
if CHECK_GITHUB_ON_STARTUP: if CHECK_GITHUB_ON_STARTUP:
try: try:
@@ -563,62 +568,62 @@ def initialize():
__INITIALIZED__ = True __INITIALIZED__ = True
return True return True
def daemonize(): def daemonize():
if threading.activeCount() != 1: if threading.activeCount() != 1:
logger.warn('There are %r active threads. Daemonizing may cause \ logger.warn('There are %r active threads. Daemonizing may cause \
strange behavior.' % threading.enumerate()) strange behavior.' % threading.enumerate())
sys.stdout.flush() sys.stdout.flush()
sys.stderr.flush() sys.stderr.flush()
# Do first fork # Do first fork
try: try:
pid = os.fork() pid = os.fork() # @UndefinedVariable - only available in UNIX
if pid == 0: if pid != 0:
pass sys.exit(0)
else:
# Exit the parent process
logger.debug('Forking once...')
os._exit(0)
except OSError, e: except OSError, e:
sys.exit("1st fork failed: %s [%d]" % (e.strerror, e.errno)) raise RuntimeError("1st fork failed: %s [%d]" % (e.strerror, e.errno))
os.setsid() os.setsid()
# Do second fork # Make sure I can read my own files and shut out others
try: prev = os.umask(0) # @UndefinedVariable - only available in UNIX
pid = os.fork() os.umask(prev and int('077', 8))
if pid > 0:
logger.debug('Forking twice...') # Make the child a session-leader by detaching from the terminal
os._exit(0) # Exit second parent process try:
except OSError, e: pid = os.fork() # @UndefinedVariable - only available in UNIX
sys.exit("2nd fork failed: %s [%d]" % (e.strerror, e.errno)) 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())
os.chdir("/")
os.umask(0)
si = open('/dev/null', "r") si = open('/dev/null', "r")
so = open('/dev/null', "a+") so = open('/dev/null', "a+")
se = open('/dev/null', "a+") se = open('/dev/null', "a+")
os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno()) os.dup2(se.fileno(), sys.stderr.fileno())
pid = os.getpid() pid = str(os.getpid())
logger.info('Daemonized to PID: %s' % pid) logger.info('Daemonized to PID: %s' % pid)
if PIDFILE:
logger.info('Writing PID %s to %s' % (pid, PIDFILE)) if CREATEPID:
logger.info("Writing PID " + pid + " to " + str(PIDFILE))
file(PIDFILE, 'w').write("%s\n" % pid) file(PIDFILE, 'w').write("%s\n" % pid)
def launch_browser(host, port, root): def launch_browser(host, port, root):
if host == '0.0.0.0': if host == '0.0.0.0':
host = 'localhost' host = 'localhost'
try: try:
webbrowser.open('http://%s:%i%s' % (host, port, root)) webbrowser.open('http://%s:%i%s' % (host, port, root))
except Exception, e: except Exception, e:
logger.error('Could not launch browser: %s' % e) logger.error('Could not launch browser: %s' % e)
@@ -642,7 +647,9 @@ def config_write():
new_config['General']['log_dir'] = LOG_DIR new_config['General']['log_dir'] = LOG_DIR
new_config['General']['cache_dir'] = CACHE_DIR new_config['General']['cache_dir'] = CACHE_DIR
new_config['General']['git_path'] = GIT_PATH new_config['General']['git_path'] = GIT_PATH
new_config['General']['git_user'] = GIT_USER
new_config['General']['git_branch'] = GIT_BRANCH
new_config['General']['check_github'] = int(CHECK_GITHUB) new_config['General']['check_github'] = int(CHECK_GITHUB)
new_config['General']['check_github_on_startup'] = int(CHECK_GITHUB_ON_STARTUP) new_config['General']['check_github_on_startup'] = int(CHECK_GITHUB_ON_STARTUP)
new_config['General']['check_github_interval'] = CHECK_GITHUB_INTERVAL new_config['General']['check_github_interval'] = CHECK_GITHUB_INTERVAL
@@ -674,7 +681,7 @@ def config_write():
new_config['General']['autowant_upcoming'] = int(AUTOWANT_UPCOMING) new_config['General']['autowant_upcoming'] = int(AUTOWANT_UPCOMING)
new_config['General']['autowant_all'] = int(AUTOWANT_ALL) new_config['General']['autowant_all'] = int(AUTOWANT_ALL)
new_config['General']['keep_torrent_files'] = int(KEEP_TORRENT_FILES) new_config['General']['keep_torrent_files'] = int(KEEP_TORRENT_FILES)
new_config['General']['numberofseeders'] = NUMBEROFSEEDERS new_config['General']['numberofseeders'] = NUMBEROFSEEDERS
new_config['General']['torrentblackhole_dir'] = TORRENTBLACKHOLE_DIR new_config['General']['torrentblackhole_dir'] = TORRENTBLACKHOLE_DIR
new_config['General']['isohunt'] = int(ISOHUNT) new_config['General']['isohunt'] = int(ISOHUNT)
@@ -686,7 +693,7 @@ def config_write():
new_config['Waffles']['waffles'] = int(WAFFLES) new_config['Waffles']['waffles'] = int(WAFFLES)
new_config['Waffles']['waffles_uid'] = WAFFLES_UID new_config['Waffles']['waffles_uid'] = WAFFLES_UID
new_config['Waffles']['waffles_passkey'] = WAFFLES_PASSKEY new_config['Waffles']['waffles_passkey'] = WAFFLES_PASSKEY
new_config['Rutracker'] = {} new_config['Rutracker'] = {}
new_config['Rutracker']['rutracker'] = int(RUTRACKER) new_config['Rutracker']['rutracker'] = int(RUTRACKER)
new_config['Rutracker']['rutracker_user'] = RUTRACKER_USER new_config['Rutracker']['rutracker_user'] = RUTRACKER_USER
@@ -724,30 +731,30 @@ def config_write():
for newznab in EXTRA_NEWZNABS: for newznab in EXTRA_NEWZNABS:
for item in newznab: for item in newznab:
flattened_newznabs.append(item) flattened_newznabs.append(item)
new_config['Newznab']['extra_newznabs'] = flattened_newznabs new_config['Newznab']['extra_newznabs'] = flattened_newznabs
new_config['NZBsorg'] = {} new_config['NZBsorg'] = {}
new_config['NZBsorg']['nzbsorg'] = int(NZBSORG) new_config['NZBsorg']['nzbsorg'] = int(NZBSORG)
new_config['NZBsorg']['nzbsorg_uid'] = NZBSORG_UID new_config['NZBsorg']['nzbsorg_uid'] = NZBSORG_UID
new_config['NZBsorg']['nzbsorg_hash'] = NZBSORG_HASH new_config['NZBsorg']['nzbsorg_hash'] = NZBSORG_HASH
new_config['Newzbin'] = {} new_config['Newzbin'] = {}
new_config['Newzbin']['newzbin'] = int(NEWZBIN) new_config['Newzbin']['newzbin'] = int(NEWZBIN)
new_config['Newzbin']['newzbin_uid'] = NEWZBIN_UID new_config['Newzbin']['newzbin_uid'] = NEWZBIN_UID
new_config['Newzbin']['newzbin_password'] = NEWZBIN_PASSWORD new_config['Newzbin']['newzbin_password'] = NEWZBIN_PASSWORD
new_config['NZBsRus'] = {} new_config['NZBsRus'] = {}
new_config['NZBsRus']['nzbsrus'] = int(NZBSRUS) new_config['NZBsRus']['nzbsrus'] = int(NZBSRUS)
new_config['NZBsRus']['nzbsrus_uid'] = NZBSRUS_UID new_config['NZBsRus']['nzbsrus_uid'] = NZBSRUS_UID
new_config['NZBsRus']['nzbsrus_apikey'] = NZBSRUS_APIKEY new_config['NZBsRus']['nzbsrus_apikey'] = NZBSRUS_APIKEY
new_config['Prowl'] = {} new_config['Prowl'] = {}
new_config['Prowl']['prowl_enabled'] = int(PROWL_ENABLED) new_config['Prowl']['prowl_enabled'] = int(PROWL_ENABLED)
new_config['Prowl']['prowl_keys'] = PROWL_KEYS new_config['Prowl']['prowl_keys'] = PROWL_KEYS
new_config['Prowl']['prowl_onsnatch'] = int(PROWL_ONSNATCH) new_config['Prowl']['prowl_onsnatch'] = int(PROWL_ONSNATCH)
new_config['Prowl']['prowl_priority'] = int(PROWL_PRIORITY) new_config['Prowl']['prowl_priority'] = int(PROWL_PRIORITY)
new_config['XBMC'] = {} new_config['XBMC'] = {}
new_config['XBMC']['xbmc_enabled'] = int(XBMC_ENABLED) new_config['XBMC']['xbmc_enabled'] = int(XBMC_ENABLED)
new_config['XBMC']['xbmc_host'] = XBMC_HOST new_config['XBMC']['xbmc_host'] = XBMC_HOST
@@ -755,7 +762,7 @@ def config_write():
new_config['XBMC']['xbmc_password'] = XBMC_PASSWORD new_config['XBMC']['xbmc_password'] = XBMC_PASSWORD
new_config['XBMC']['xbmc_update'] = int(XBMC_UPDATE) new_config['XBMC']['xbmc_update'] = int(XBMC_UPDATE)
new_config['XBMC']['xbmc_notify'] = int(XBMC_NOTIFY) new_config['XBMC']['xbmc_notify'] = int(XBMC_NOTIFY)
new_config['NMA'] = {} new_config['NMA'] = {}
new_config['NMA']['nma_enabled'] = int(NMA_ENABLED) new_config['NMA']['nma_enabled'] = int(NMA_ENABLED)
new_config['NMA']['nma_apikey'] = NMA_APIKEY new_config['NMA']['nma_apikey'] = NMA_APIKEY
@@ -767,10 +774,10 @@ def config_write():
new_config['Pushover']['pushover_keys'] = PUSHOVER_KEYS new_config['Pushover']['pushover_keys'] = PUSHOVER_KEYS
new_config['Pushover']['pushover_onsnatch'] = int(PUSHOVER_ONSNATCH) new_config['Pushover']['pushover_onsnatch'] = int(PUSHOVER_ONSNATCH)
new_config['Pushover']['pushover_priority'] = int(PUSHOVER_PRIORITY) new_config['Pushover']['pushover_priority'] = int(PUSHOVER_PRIORITY)
new_config['Synoindex'] = {} new_config['Synoindex'] = {}
new_config['Synoindex']['synoindex_enabled'] = int(SYNOINDEX_ENABLED) new_config['Synoindex']['synoindex_enabled'] = int(SYNOINDEX_ENABLED)
new_config['General']['lastfm_username'] = LASTFM_USERNAME new_config['General']['lastfm_username'] = LASTFM_USERNAME
new_config['General']['interface'] = INTERFACE new_config['General']['interface'] = INTERFACE
new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS
@@ -787,43 +794,48 @@ def config_write():
new_config['General']['encodervbrcbr'] = ENCODERVBRCBR new_config['General']['encodervbrcbr'] = ENCODERVBRCBR
new_config['General']['encoderlossless'] = int(ENCODERLOSSLESS) new_config['General']['encoderlossless'] = int(ENCODERLOSSLESS)
new_config['General']['delete_lossless_files'] = int(DELETE_LOSSLESS_FILES) new_config['General']['delete_lossless_files'] = int(DELETE_LOSSLESS_FILES)
new_config['General']['mirror'] = MIRROR new_config['General']['mirror'] = MIRROR
new_config['General']['customhost'] = CUSTOMHOST new_config['General']['customhost'] = CUSTOMHOST
new_config['General']['customport'] = CUSTOMPORT new_config['General']['customport'] = CUSTOMPORT
new_config['General']['customsleep'] = CUSTOMSLEEP new_config['General']['customsleep'] = CUSTOMSLEEP
new_config['General']['hpuser'] = HPUSER new_config['General']['hpuser'] = HPUSER
new_config['General']['hppass'] = HPPASS new_config['General']['hppass'] = HPPASS
new_config['Advanced'] = {} new_config['Advanced'] = {}
new_config['Advanced']['album_completion_pct'] = ALBUM_COMPLETION_PCT new_config['Advanced']['album_completion_pct'] = ALBUM_COMPLETION_PCT
new_config['Advanced']['cache_sizemb'] = CACHE_SIZEMB new_config['Advanced']['cache_sizemb'] = CACHE_SIZEMB
new_config.write() new_config.write()
def start(): def start():
global __INITIALIZED__, started global __INITIALIZED__, started
if __INITIALIZED__: if __INITIALIZED__:
# Start our scheduled background tasks # Start our scheduled background tasks
from headphones import updater, searcher, librarysync, postprocessor from headphones import updater, searcher, librarysync, postprocessor
SCHED.add_interval_job(updater.dbUpdate, hours=24) SCHED.add_interval_job(updater.dbUpdate, hours=24)
SCHED.add_interval_job(searcher.searchforalbum, minutes=SEARCH_INTERVAL) SCHED.add_interval_job(searcher.searchforalbum, minutes=SEARCH_INTERVAL)
SCHED.add_interval_job(librarysync.libraryScan, minutes=LIBRARYSCAN_INTERVAL, kwargs={'cron':True}) SCHED.add_interval_job(librarysync.libraryScan, minutes=LIBRARYSCAN_INTERVAL, kwargs={'cron':True})
if CHECK_GITHUB: if CHECK_GITHUB:
SCHED.add_interval_job(versioncheck.checkGithub, minutes=CHECK_GITHUB_INTERVAL) SCHED.add_interval_job(versioncheck.checkGithub, minutes=CHECK_GITHUB_INTERVAL)
SCHED.add_interval_job(postprocessor.checkFolder, minutes=DOWNLOAD_SCAN_INTERVAL) SCHED.add_interval_job(postprocessor.checkFolder, minutes=DOWNLOAD_SCAN_INTERVAL)
SCHED.start() SCHED.start()
started = True started = True
def sig_handler(signum=None, frame=None):
if type(signum) != type(None):
logger.info("Signal %i caught, saving and exiting..." % int(signum))
shutdown()
def dbcheck(): def dbcheck():
conn=sqlite3.connect(DB_FILE) conn=sqlite3.connect(DB_FILE)
@@ -842,37 +854,37 @@ def dbcheck():
c.execute('CREATE TABLE IF NOT EXISTS releases (ReleaseID TEXT, ReleaseGroupID TEXT, UNIQUE(ReleaseID, ReleaseGroupID))') c.execute('CREATE TABLE IF NOT EXISTS releases (ReleaseID TEXT, ReleaseGroupID TEXT, UNIQUE(ReleaseID, ReleaseGroupID))')
c.execute('CREATE INDEX IF NOT EXISTS tracks_albumid ON tracks(AlbumID ASC)') c.execute('CREATE INDEX IF NOT EXISTS tracks_albumid ON tracks(AlbumID ASC)')
c.execute('CREATE INDEX IF NOT EXISTS album_artistid_reldate ON albums(ArtistID ASC, ReleaseDate DESC)') c.execute('CREATE INDEX IF NOT EXISTS album_artistid_reldate ON albums(ArtistID ASC, ReleaseDate DESC)')
try: try:
c.execute('SELECT IncludeExtras from artists') c.execute('SELECT IncludeExtras from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN IncludeExtras INTEGER DEFAULT 0') c.execute('ALTER TABLE artists ADD COLUMN IncludeExtras INTEGER DEFAULT 0')
try: try:
c.execute('SELECT LatestAlbum from artists') c.execute('SELECT LatestAlbum from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN LatestAlbum TEXT') c.execute('ALTER TABLE artists ADD COLUMN LatestAlbum TEXT')
try: try:
c.execute('SELECT ReleaseDate from artists') c.execute('SELECT ReleaseDate from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN ReleaseDate TEXT') c.execute('ALTER TABLE artists ADD COLUMN ReleaseDate TEXT')
try: try:
c.execute('SELECT AlbumID from artists') c.execute('SELECT AlbumID from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN AlbumID TEXT') c.execute('ALTER TABLE artists ADD COLUMN AlbumID TEXT')
try: try:
c.execute('SELECT HaveTracks from artists') c.execute('SELECT HaveTracks from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN HaveTracks INTEGER DEFAULT 0') c.execute('ALTER TABLE artists ADD COLUMN HaveTracks INTEGER DEFAULT 0')
try: try:
c.execute('SELECT TotalTracks from artists') c.execute('SELECT TotalTracks from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN TotalTracks INTEGER DEFAULT 0') c.execute('ALTER TABLE artists ADD COLUMN TotalTracks INTEGER DEFAULT 0')
try: try:
c.execute('SELECT Type from albums') c.execute('SELECT Type from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
@@ -882,108 +894,108 @@ def dbcheck():
c.execute('SELECT TrackNumber from tracks') c.execute('SELECT TrackNumber from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN TrackNumber INTEGER') c.execute('ALTER TABLE tracks ADD COLUMN TrackNumber INTEGER')
try: try:
c.execute('SELECT FolderName from snatched') c.execute('SELECT FolderName from snatched')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE snatched ADD COLUMN FolderName TEXT') c.execute('ALTER TABLE snatched ADD COLUMN FolderName TEXT')
try: try:
c.execute('SELECT Location from tracks') c.execute('SELECT Location from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN Location TEXT') c.execute('ALTER TABLE tracks ADD COLUMN Location TEXT')
try: try:
c.execute('SELECT Location from have') c.execute('SELECT Location from have')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE have ADD COLUMN Location TEXT') c.execute('ALTER TABLE have ADD COLUMN Location TEXT')
try: try:
c.execute('SELECT BitRate from tracks') c.execute('SELECT BitRate from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN BitRate INTEGER') c.execute('ALTER TABLE tracks ADD COLUMN BitRate INTEGER')
try: try:
c.execute('SELECT CleanName from tracks') c.execute('SELECT CleanName from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN CleanName TEXT') c.execute('ALTER TABLE tracks ADD COLUMN CleanName TEXT')
try: try:
c.execute('SELECT CleanName from have') c.execute('SELECT CleanName from have')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE have ADD COLUMN CleanName TEXT') c.execute('ALTER TABLE have ADD COLUMN CleanName TEXT')
# Add the Format column # Add the Format column
try: try:
c.execute('SELECT Format from have') c.execute('SELECT Format from have')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE have ADD COLUMN Format TEXT DEFAULT NULL') c.execute('ALTER TABLE have ADD COLUMN Format TEXT DEFAULT NULL')
try: try:
c.execute('SELECT Format from tracks') c.execute('SELECT Format from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN Format TEXT DEFAULT NULL') c.execute('ALTER TABLE tracks ADD COLUMN Format TEXT DEFAULT NULL')
try: try:
c.execute('SELECT LastUpdated from artists') c.execute('SELECT LastUpdated from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN LastUpdated TEXT DEFAULT NULL') c.execute('ALTER TABLE artists ADD COLUMN LastUpdated TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ArtworkURL from artists') c.execute('SELECT ArtworkURL from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN ArtworkURL TEXT DEFAULT NULL') c.execute('ALTER TABLE artists ADD COLUMN ArtworkURL TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ArtworkURL from albums') c.execute('SELECT ArtworkURL from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE albums ADD COLUMN ArtworkURL TEXT DEFAULT NULL') c.execute('ALTER TABLE albums ADD COLUMN ArtworkURL TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ThumbURL from artists') c.execute('SELECT ThumbURL from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE artists ADD COLUMN ThumbURL TEXT DEFAULT NULL') c.execute('ALTER TABLE artists ADD COLUMN ThumbURL TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ThumbURL from albums') c.execute('SELECT ThumbURL from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE albums ADD COLUMN ThumbURL TEXT DEFAULT NULL') c.execute('ALTER TABLE albums ADD COLUMN ThumbURL TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ArtistID from descriptions') c.execute('SELECT ArtistID from descriptions')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE descriptions ADD COLUMN ArtistID TEXT DEFAULT NULL') c.execute('ALTER TABLE descriptions ADD COLUMN ArtistID TEXT DEFAULT NULL')
try: try:
c.execute('SELECT LastUpdated from descriptions') c.execute('SELECT LastUpdated from descriptions')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE descriptions ADD COLUMN LastUpdated TEXT DEFAULT NULL') c.execute('ALTER TABLE descriptions ADD COLUMN LastUpdated TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ReleaseID from albums') c.execute('SELECT ReleaseID from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE albums ADD COLUMN ReleaseID TEXT DEFAULT NULL') c.execute('ALTER TABLE albums ADD COLUMN ReleaseID TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ReleaseFormat from albums') c.execute('SELECT ReleaseFormat from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE albums ADD COLUMN ReleaseFormat TEXT DEFAULT NULL') c.execute('ALTER TABLE albums ADD COLUMN ReleaseFormat TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ReleaseCountry from albums') c.execute('SELECT ReleaseCountry from albums')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE albums ADD COLUMN ReleaseCountry TEXT DEFAULT NULL') c.execute('ALTER TABLE albums ADD COLUMN ReleaseCountry TEXT DEFAULT NULL')
try: try:
c.execute('SELECT ReleaseID from tracks') c.execute('SELECT ReleaseID from tracks')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE tracks ADD COLUMN ReleaseID TEXT DEFAULT NULL') c.execute('ALTER TABLE tracks ADD COLUMN ReleaseID TEXT DEFAULT NULL')
try: try:
c.execute('SELECT Matched from have') c.execute('SELECT Matched from have')
except sqlite3.OperationalError: except sqlite3.OperationalError:
c.execute('ALTER TABLE have ADD COLUMN Matched TEXT DEFAULT NULL') c.execute('ALTER TABLE have ADD COLUMN Matched TEXT DEFAULT NULL')
try: try:
c.execute('SELECT Extras from artists') c.execute('SELECT Extras from artists')
except sqlite3.OperationalError: except sqlite3.OperationalError:
@@ -1010,27 +1022,28 @@ def dbcheck():
conn.commit() conn.commit()
c.close() c.close()
def shutdown(restart=False, update=False): def shutdown(restart=False, update=False):
cherrypy.engine.exit() cherrypy.engine.exit()
SCHED.shutdown(wait=False) SCHED.shutdown(wait=False)
config_write() config_write()
if not restart and not update: if not restart and not update:
logger.info('Headphones is shutting down...') logger.info('Headphones is shutting down...')
if update: if update:
logger.info('Headphones is updating...') logger.info('Headphones is updating...')
try: try:
versioncheck.update() versioncheck.update()
except Exception, e: except Exception, e:
logger.warn('Headphones failed to update: %s. Restarting.' % e) logger.warn('Headphones failed to update: %s. Restarting.' % e)
if PIDFILE : if CREATEPID :
logger.info ('Removing pidfile %s' % PIDFILE) logger.info ('Removing pidfile %s' % PIDFILE)
os.remove(PIDFILE) os.remove(PIDFILE)
if restart: if restart:
logger.info('Headphones is restarting...') logger.info('Headphones is restarting...')
popen_list = [sys.executable, FULL_PATH] popen_list = [sys.executable, FULL_PATH]
@@ -1039,5 +1052,5 @@ def shutdown(restart=False, update=False):
popen_list += ['--nolaunch'] popen_list += ['--nolaunch']
logger.info('Restarting Headphones with ' + str(popen_list)) logger.info('Restarting Headphones with ' + str(popen_list))
subprocess.Popen(popen_list, cwd=os.getcwd()) subprocess.Popen(popen_list, cwd=os.getcwd())
os._exit(0) os._exit(0)
+57 -59
View File
@@ -17,29 +17,27 @@ import platform, subprocess, re, os, urllib2, tarfile
import headphones import headphones
from headphones import logger, version from headphones import logger, version
from headphones.exceptions import ex
import lib.simplejson as simplejson import lib.simplejson as simplejson
user = "rembo10"
branch = "master"
def runGit(args): def runGit(args):
if headphones.GIT_PATH: if headphones.GIT_PATH:
git_locations = ['"'+headphones.GIT_PATH+'"'] git_locations = ['"'+headphones.GIT_PATH+'"']
else: else:
git_locations = ['git'] git_locations = ['git']
if platform.system().lower() == 'darwin': if platform.system().lower() == 'darwin':
git_locations.append('/usr/local/git/bin/git') git_locations.append('/usr/local/git/bin/git')
output = err = None output = err = None
for cur_git in git_locations: for cur_git in git_locations:
cmd = cur_git+' '+args cmd = cur_git+' '+args
try: try:
logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR) logger.debug('Trying to execute: "' + cmd + '" with shell in ' + headphones.PROG_DIR)
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=headphones.PROG_DIR) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, cwd=headphones.PROG_DIR)
@@ -48,7 +46,7 @@ def runGit(args):
except OSError: except OSError:
logger.debug('Command ' + cmd + ' didn\'t work, couldn\'t find git') logger.debug('Command ' + cmd + ' didn\'t work, couldn\'t find git')
continue continue
if 'not found' in output or "not recognized as an internal or external command" in output: if 'not found' in output or "not recognized as an internal or external command" in output:
logger.debug('Unable to find git with command ' + cmd) logger.debug('Unable to find git with command ' + cmd)
output = None output = None
@@ -57,58 +55,58 @@ def runGit(args):
output = None output = None
elif output: elif output:
break break
return (output, err) return (output, err)
def getVersion(): def getVersion():
if version.HEADPHONES_VERSION.startswith('win32build'): if version.HEADPHONES_VERSION.startswith('win32build'):
headphones.INSTALL_TYPE = 'win' headphones.INSTALL_TYPE = 'win'
# Don't have a way to update exe yet, but don't want to set VERSION to None # Don't have a way to update exe yet, but don't want to set VERSION to None
return 'Windows Install' return 'Windows Install'
elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')): elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')):
headphones.INSTALL_TYPE = 'git' headphones.INSTALL_TYPE = 'git'
output, err = runGit('rev-parse HEAD') output, err = runGit('rev-parse HEAD')
if not output: if not output:
logger.error('Couldn\'t find latest installed version.') logger.error('Couldn\'t find latest installed version.')
return None return None
cur_commit_hash = output.strip() cur_commit_hash = output.strip()
if not re.match('^[a-z0-9]+$', cur_commit_hash): if not re.match('^[a-z0-9]+$', cur_commit_hash):
logger.error('Output doesn\'t look like a hash, not using it') logger.error('Output doesn\'t look like a hash, not using it')
return None return None
return cur_commit_hash return cur_commit_hash
else: else:
headphones.INSTALL_TYPE = 'source' headphones.INSTALL_TYPE = 'source'
version_file = os.path.join(headphones.PROG_DIR, 'version.txt') version_file = os.path.join(headphones.PROG_DIR, 'version.txt')
if not os.path.isfile(version_file): if not os.path.isfile(version_file):
return None return None
fp = open(version_file, 'r') fp = open(version_file, 'r')
current_version = fp.read().strip(' \n\r') current_version = fp.read().strip(' \n\r')
fp.close() fp.close()
if current_version: if current_version:
return current_version return current_version
else: else:
return None return None
def checkGithub(): def checkGithub():
# Get the latest commit available from github # Get the latest commit available from github
url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (user, branch) url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (headphones.GIT_USER, headphones.GIT_BRANCH)
logger.info ('Retrieving latest version information from github') logger.info('Retrieving latest version information from github')
try: try:
result = urllib2.urlopen(url).read() result = urllib2.urlopen(url).read()
git = simplejson.JSONDecoder().decode(result) git = simplejson.JSONDecoder().decode(result)
@@ -117,12 +115,12 @@ def checkGithub():
logger.warn('Could not get the latest commit from github') logger.warn('Could not get the latest commit from github')
headphones.COMMITS_BEHIND = 0 headphones.COMMITS_BEHIND = 0
return headphones.CURRENT_VERSION return headphones.CURRENT_VERSION
# See how many commits behind we are # See how many commits behind we are
if headphones.CURRENT_VERSION: if headphones.CURRENT_VERSION:
logger.info('Comparing currently installed version with latest github version') logger.info('Comparing currently installed version with latest github version')
url = 'https://api.github.com/repos/%s/headphones/compare/%s...%s' % (user, headphones.CURRENT_VERSION, headphones.LATEST_VERSION) url = 'https://api.github.com/repos/%s/headphones/compare/%s...%s' % (headphones.GIT_USER, headphones.CURRENT_VERSION, headphones.LATEST_VERSION)
try: try:
result = urllib2.urlopen(url).read() result = urllib2.urlopen(url).read()
git = simplejson.JSONDecoder().decode(result) git = simplejson.JSONDecoder().decode(result)
@@ -131,99 +129,99 @@ def checkGithub():
logger.warn('Could not get commits behind from github') logger.warn('Could not get commits behind from github')
headphones.COMMITS_BEHIND = 0 headphones.COMMITS_BEHIND = 0
return headphones.CURRENT_VERSION return headphones.CURRENT_VERSION
if headphones.COMMITS_BEHIND >= 1: if headphones.COMMITS_BEHIND >= 1:
logger.info('New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND) logger.info('New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND)
elif headphones.COMMITS_BEHIND == 0: elif headphones.COMMITS_BEHIND == 0:
logger.info('Headphones is up to date') logger.info('Headphones is up to date')
elif headphones.COMMITS_BEHIND == -1: elif headphones.COMMITS_BEHIND == -1:
logger.info('You are running an unknown version of Headphones. Run the updater to identify your version') logger.info('You are running an unknown version of Headphones. Run the updater to identify your version')
else: else:
logger.info('You are running an unknown version of Headphones. Run the updater to identify your version') logger.info('You are running an unknown version of Headphones. Run the updater to identify your version')
return headphones.LATEST_VERSION return headphones.LATEST_VERSION
def update(): def update():
if headphones.INSTALL_TYPE == 'win': if headphones.INSTALL_TYPE == 'win':
logger.info('Windows .exe updating not supported yet.') logger.info('Windows .exe updating not supported yet.')
pass pass
elif headphones.INSTALL_TYPE == 'git': elif headphones.INSTALL_TYPE == 'git':
output, err = runGit('pull origin ' + version.HEADPHONES_VERSION) output, err = runGit('pull origin ' + version.HEADPHONES_VERSION)
if not output: if not output:
logger.error('Couldn\'t download latest version') logger.error('Couldn\'t download latest version')
for line in output.split('\n'): for line in output.split('\n'):
if 'Already up-to-date.' in line: if 'Already up-to-date.' in line:
logger.info('No update available, not updating') logger.info('No update available, not updating')
logger.info('Output: ' + str(output)) logger.info('Output: ' + str(output))
elif line.endswith('Aborting.'): elif line.endswith('Aborting.'):
logger.error('Unable to update from git: '+line) logger.error('Unable to update from git: '+line)
logger.info('Output: ' + str(output)) logger.info('Output: ' + str(output))
else: else:
tar_download_url = 'https://github.com/%s/headphones/tarball/%s' % (user, branch) tar_download_url = 'https://github.com/%s/headphones/tarball/%s' % (headphones.GIT_USER, headphones.GIT_BRANCH)
update_dir = os.path.join(headphones.PROG_DIR, 'update') update_dir = os.path.join(headphones.PROG_DIR, 'update')
version_path = os.path.join(headphones.PROG_DIR, 'version.txt') version_path = os.path.join(headphones.PROG_DIR, 'version.txt')
try: try:
logger.info('Downloading update from: '+tar_download_url) logger.info('Downloading update from: '+tar_download_url)
data = urllib2.urlopen(tar_download_url) data = urllib2.urlopen(tar_download_url)
except (IOError, URLError): except (IOError, URLError):
logger.error("Unable to retrieve new version from "+tar_download_url+", can't update") logger.error("Unable to retrieve new version from "+tar_download_url+", can't update")
return return
download_name = data.geturl().split('/')[-1] download_name = data.geturl().split('/')[-1]
tar_download_path = os.path.join(headphones.PROG_DIR, download_name) tar_download_path = os.path.join(headphones.PROG_DIR, download_name)
# Save tar to disk # Save tar to disk
f = open(tar_download_path, 'wb') f = open(tar_download_path, 'wb')
f.write(data.read()) f.write(data.read())
f.close() f.close()
# Extract the tar to update folder # Extract the tar to update folder
logger.info('Extracing file' + tar_download_path) logger.info('Extracing file' + tar_download_path)
tar = tarfile.open(tar_download_path) tar = tarfile.open(tar_download_path)
tar.extractall(update_dir) tar.extractall(update_dir)
tar.close() tar.close()
# Delete the tar.gz # Delete the tar.gz
logger.info('Deleting file' + tar_download_path) logger.info('Deleting file' + tar_download_path)
os.remove(tar_download_path) os.remove(tar_download_path)
# Find update dir name # Find update dir name
update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))] update_dir_contents = [x for x in os.listdir(update_dir) if os.path.isdir(os.path.join(update_dir, x))]
if len(update_dir_contents) != 1: if len(update_dir_contents) != 1:
logger.error(u"Invalid update data, update failed: "+str(update_dir_contents)) logger.error("Invalid update data, update failed: "+str(update_dir_contents))
return return
content_dir = os.path.join(update_dir, update_dir_contents[0]) content_dir = os.path.join(update_dir, update_dir_contents[0])
# walk temp folder and move files to main folder # walk temp folder and move files to main folder
for dirname, dirnames, filenames in os.walk(content_dir): for dirname, dirnames, filenames in os.walk(content_dir):
dirname = dirname[len(content_dir)+1:] dirname = dirname[len(content_dir)+1:]
for curfile in filenames: for curfile in filenames:
old_path = os.path.join(content_dir, dirname, curfile) old_path = os.path.join(content_dir, dirname, curfile)
new_path = os.path.join(headphones.PROG_DIR, dirname, curfile) new_path = os.path.join(headphones.PROG_DIR, dirname, curfile)
if os.path.isfile(new_path): if os.path.isfile(new_path):
os.remove(new_path) os.remove(new_path)
os.renames(old_path, new_path) os.renames(old_path, new_path)
# Update version.txt # Update version.txt
try: try:
ver_file = open(version_path, 'w') ver_file = open(version_path, 'w')
ver_file.write(headphones.LATEST_VERSION) ver_file.write(headphones.LATEST_VERSION)
ver_file.close() ver_file.close()
except IOError, e: except IOError, e:
logger.error(u"Unable to write current version to version.txt, update not complete: "+ex(e)) logger.error("Unable to write current version to version.txt, update not complete: "+ex(e))
return return
Regular → Executable
+175 -34
View File
@@ -1,5 +1,44 @@
#! /bin/sh #!/bin/sh
#
## Don't edit this file
## Edit user configuation in /etc/default/headphones to change
##
## Make sure init script is executable
## sudo chmod +x /opt/headphones/init.ubuntu
##
## Install the init script
## sudo ln -s /opt/headphones/init.ubuntu /etc/init.d/headphones
##
## Create the headphones daemon user:
## sudo adduser --system --no-create-home headphones
##
## Make sure /opt/headphones is owned by the headphones user
## sudo chown headphones:nogroup -R /opt/headphones
##
## Touch the default file to stop the warning message when starting
## sudo touch /etc/default/headphones
##
## To start Headphones automatically
## sudo update-rc.d headphones defaults
##
## To start/stop/restart Headphones
## sudo service headphones start
## sudo service headphones stop
## sudo service headphones restart
##
## HP_USER= #$RUN_AS, username to run headphones under, the default is headphones
## HP_HOME= #$APP_PATH, the location of Headphones.py, the default is /opt/headphones
## HP_DATA= #$DATA_DIR, the location of headphones.db, cache, logs, the default is /opt/headphones
## HP_PIDFILE= #$PID_FILE, the location of headphones.pid, the default is /var/run/headphones/headphones.pid
## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python
## HP_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for headphones, i.e. " --config=/home/headphones/config.ini"
## SSD_OPTS= #$EXTRA_SSD_OPTS, extra start-stop-daemon option like " --group=users"
## HP_PORT= #$PORT_OPTS, hardcoded port for the webserver, overrides value in config.ini
##
## EXAMPLE if want to run as different user
## add HP_USER=username to /etc/default/headphones
## otherwise default headphones is used
#
### BEGIN INIT INFO ### BEGIN INIT INFO
# Provides: headphones # Provides: headphones
# Required-Start: $local_fs $network $remote_fs # Required-Start: $local_fs $network $remote_fs
@@ -12,50 +51,152 @@
# Description: starts instance of Headphones using start-stop-daemon # Description: starts instance of Headphones using start-stop-daemon
### END INIT INFO ### END INIT INFO
############### EDIT ME ################## # Script name
# path to app
APP_PATH=/usr/local/sbin/headphones
# path to python bin
DAEMON=/usr/bin/python
# startup args
DAEMON_OPTS=" Headphones.py -q"
# script name
NAME=headphones NAME=headphones
# app name # App name
DESC=headphones DESC=Headphones
# user SETTINGS_LOADED=FALSE
RUN_AS=root
PID_FILE=/var/run/headphones.pid . /lib/lsb/init-functions
############### END EDIT ME ################## # Source Headphones configuration
if [ -f /etc/default/headphones ]; then
SETTINGS=/etc/default/headphones
else
log_warning_msg "/etc/default/headphones not found using default settings.";
fi
test -x $DAEMON || exit 0 check_retval() {
if [ $? -eq 0 ]; then
log_end_msg 0
return 0
else
log_end_msg 1
exit 1
fi
}
set -e load_settings() {
if [ $SETTINGS_LOADED != "TRUE" ]; then
. $SETTINGS
## The defaults
# Run as username
RUN_AS=${HP_USER-headphones}
# Path to app HP_HOME=path_to_app_Headphones.py
APP_PATH=${HP_HOME-/opt/headphones}
# Data directory where headphones.db, cache and logs are stored
DATA_DIR=${HP_DATA-/opt/headphones}
# Path to store PID file
PID_FILE=${HP_PIDFILE-/var/run/headphones/headphones.pid}
# Path to python bin
DAEMON=${PYTHON_BIN-/usr/bin/python}
# Extra daemon option like: HP_OPTS=" --config=/home/headphones/config.ini"
EXTRA_DAEMON_OPTS=${HP_OPTS-}
# Extra start-stop-daemon option like START_OPTS=" --group=users"
EXTRA_SSD_OPTS=${SSD_OPTS-}
# Hardcoded port to run on, overrides config.ini settings
[ -n "$HP_PORT" ] && {
PORT_OPTS=" --port=${HP_PORT} "
}
DAEMON_OPTS=" Headphones.py --quiet --daemon --nolaunch --pidfile=${PID_FILE} --datadir=${DATA_DIR} ${PORT_OPTS}${EXTRA_DAEMON_OPTS}"
SETTINGS_LOADED=TRUE
fi
[ -x $DAEMON ] || {
log_warning_msg "$DESC: Can't execute daemon, aborting. See $DAEMON";
return 1;}
return 0
}
load_settings || exit 0
is_running () {
# returns 1 when running, else 0.
if [ -e $PID_FILE ]; then
PID=`cat $PID_FILE`
RET=$?
[ $RET -gt 1 ] && exit 1 || return $RET
else
return 1
fi
}
handle_pid () {
PID_PATH=`dirname $PID_FILE`
[ -d $PID_PATH ] || mkdir -p $PID_PATH && chown -R $RUN_AS $PID_PATH > /dev/null || {
log_warning_msg "$DESC: Could not create $PID_FILE, See $SETTINGS, aborting.";
return 1;}
if [ -e $PID_FILE ]; then
PID=`cat $PID_FILE`
if ! kill -0 $PID > /dev/null 2>&1; then
log_warning_msg "Removing stale $PID_FILE"
rm $PID_FILE
fi
fi
}
handle_datadir () {
[ -d $DATA_DIR ] || mkdir -p $DATA_DIR && chown -R $RUN_AS $DATA_DIR > /dev/null || {
log_warning_msg "$DESC: Could not create $DATA_DIR, See $SETTINGS, aborting.";
return 1;}
}
handle_updates () {
chown -R $RUN_AS $APP_PATH > /dev/null || {
log_warning_msg "$DESC: $APP_PATH not writable by $RUN_AS for web-updates";
return 0; }
}
start_headphones () {
handle_pid
handle_datadir
handle_updates
if ! is_running; then
log_daemon_msg "Starting $DESC"
start-stop-daemon -o -d $APP_PATH -c $RUN_AS --start $EXTRA_SSD_OPTS --pidfile $PID_FILE --exec $DAEMON -- $DAEMON_OPTS
check_retval
else
log_success_msg "$DESC: already running (pid $PID)"
fi
}
stop_headphones () {
if is_running; then
log_daemon_msg "Stopping $DESC"
start-stop-daemon -o --stop --pidfile $PID_FILE --retry 15
check_retval
else
log_success_msg "$DESC: not running"
fi
}
case "$1" in case "$1" in
start) start)
echo "Starting $DESC" start_headphones
start-stop-daemon -d $APP_PATH -c $RUN_AS --start --background --pidfile $PID_FILE --make-pidfile --exec $DAEMON -- $DAEMON_OPTS
;; ;;
stop) stop)
echo "Stopping $DESC" stop_headphones
start-stop-daemon --stop --pidfile $PID_FILE
;; ;;
restart|force-reload)
restart|force-reload) stop_headphones
echo "Restarting $DESC" start_headphones
start-stop-daemon --stop --pidfile $PID_FILE
sleep 15
start-stop-daemon -d $APP_PATH -c $RUN_AS --start --background --pidfile $PID_FILE --make-pidfile --exec $DAEMON -- $DAEMON_OPTS
;; ;;
*) *)
N=/etc/init.d/$NAME N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload}" >&2 echo "Usage: $N {start|stop|restart|force-reload}" >&2
exit 1 exit 1