mirror of
https://github.com/rembo10/headphones.git
synced 2026-03-20 19:59:26 +00:00
Merged in brunnels updated initscript/pidfile handling & adehub fix in base.html
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -50,4 +50,8 @@ Thumbs.db
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
[Tt]est[Rr]esult*
|
||||
[Tt]est[Rr]esult*
|
||||
/cache
|
||||
/logs
|
||||
.project
|
||||
.pydevproject
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import os, sys, locale
|
||||
import time
|
||||
import signal
|
||||
|
||||
from lib.configobj import ConfigObj
|
||||
|
||||
@@ -27,7 +28,10 @@ try:
|
||||
import argparse
|
||||
except ImportError:
|
||||
import lib.argparse as argparse
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, headphones.sig_handler)
|
||||
signal.signal(signal.SIGTERM, headphones.sig_handler)
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
@@ -36,10 +40,10 @@ def main():
|
||||
headphones.FULL_PATH = os.path.abspath(sys.executable)
|
||||
else:
|
||||
headphones.FULL_PATH = os.path.abspath(__file__)
|
||||
|
||||
|
||||
headphones.PROG_DIR = os.path.dirname(headphones.FULL_PATH)
|
||||
headphones.ARGS = sys.argv[1:]
|
||||
|
||||
|
||||
# From sickbeard
|
||||
headphones.SYS_PLATFORM = sys.platform
|
||||
headphones.SYS_ENCODING = None
|
||||
@@ -53,7 +57,7 @@ def main():
|
||||
# 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'):
|
||||
headphones.SYS_ENCODING = 'UTF-8'
|
||||
|
||||
|
||||
# Set up and gather command line arguments
|
||||
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('--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)')
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
headphones.VERBOSE = 2
|
||||
elif args.quiet:
|
||||
headphones.VERBOSE = 0
|
||||
|
||||
|
||||
if args.daemon:
|
||||
headphones.DAEMON=True
|
||||
headphones.VERBOSE = 0
|
||||
if args.pidfile :
|
||||
headphones.PIDFILE = args.pidfile
|
||||
if sys.platform == 'win32':
|
||||
print "Daemonize not supported under Windows, starting normally"
|
||||
else:
|
||||
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:
|
||||
headphones.DATA_DIR = args.datadir
|
||||
else:
|
||||
headphones.DATA_DIR = headphones.PROG_DIR
|
||||
|
||||
|
||||
if args.config:
|
||||
headphones.CONFIG_FILE = args.config
|
||||
else:
|
||||
headphones.CONFIG_FILE = os.path.join(headphones.DATA_DIR, 'config.ini')
|
||||
|
||||
|
||||
# Try to create the DATA_DIR if it doesn't exist
|
||||
if not os.path.exists(headphones.DATA_DIR):
|
||||
try:
|
||||
os.makedirs(headphones.DATA_DIR)
|
||||
except OSError:
|
||||
raise SystemExit('Could not create data directory: ' + headphones.DATA_DIR + '. Exiting....')
|
||||
|
||||
|
||||
# Make sure the DATA_DIR is writeable
|
||||
if not os.access(headphones.DATA_DIR, os.W_OK):
|
||||
raise SystemExit('Cannot write to the data directory: ' + headphones.DATA_DIR + '. Exiting...')
|
||||
|
||||
|
||||
# Put the database in the DATA_DIR
|
||||
headphones.DB_FILE = os.path.join(headphones.DATA_DIR, 'headphones.db')
|
||||
|
||||
|
||||
headphones.CFG = ConfigObj(headphones.CONFIG_FILE, encoding='utf-8')
|
||||
|
||||
|
||||
# Read config & start logging
|
||||
headphones.initialize()
|
||||
|
||||
|
||||
if headphones.DAEMON:
|
||||
if sys.platform == "win32":
|
||||
print "Daemonize not supported under Windows, starting normally"
|
||||
else:
|
||||
headphones.daemonize()
|
||||
|
||||
|
||||
#configure the connection to the musicbrainz database
|
||||
headphones.mb.startmb()
|
||||
|
||||
@@ -123,8 +145,8 @@ def main():
|
||||
logger.info('Starting Headphones on forced port: %i' % http_port)
|
||||
else:
|
||||
http_port = int(headphones.HTTP_PORT)
|
||||
|
||||
# Try to start the server.
|
||||
|
||||
# Try to start the server.
|
||||
webstart.initialize({
|
||||
'http_port': http_port,
|
||||
'http_host': headphones.HTTP_HOST,
|
||||
@@ -133,15 +155,15 @@ def main():
|
||||
'http_username': headphones.HTTP_USERNAME,
|
||||
'http_password': headphones.HTTP_PASSWORD,
|
||||
})
|
||||
|
||||
|
||||
logger.info('Starting Headphones on port: %i' % http_port)
|
||||
|
||||
|
||||
if headphones.LAUNCH_BROWSER and not args.nolaunch:
|
||||
headphones.launch_browser(headphones.HTTP_HOST, http_port, headphones.HTTP_ROOT)
|
||||
|
||||
|
||||
# Start the background threads
|
||||
headphones.start()
|
||||
|
||||
|
||||
while True:
|
||||
if not headphones.SIGNAL:
|
||||
try:
|
||||
@@ -156,9 +178,9 @@ def main():
|
||||
headphones.shutdown(restart=True)
|
||||
else:
|
||||
headphones.shutdown(restart=True, update=True)
|
||||
|
||||
|
||||
headphones.SIGNAL = None
|
||||
|
||||
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -11,19 +11,19 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
|
||||
|
||||
<title>Headphones - ${title}</title>
|
||||
<meta name="description" content="Headphones 'default' interface - made by Elmar Kouwenhoven">
|
||||
<meta name="author" content="Elmar Kouwenhoven">
|
||||
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
|
||||
<link rel="shortcut icon" href="images/favicon.ico">
|
||||
<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/jquery-ui.css">
|
||||
${next.headIncludes()}
|
||||
|
||||
|
||||
<script src="js/libs/modernizr-1.7.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -31,16 +31,16 @@
|
||||
<div id="ajaxMsg"></div>
|
||||
% if not headphones.CURRENT_VERSION:
|
||||
<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>
|
||||
</div>
|
||||
% elif headphones.CURRENT_VERSION != headphones.LATEST_VERSION and headphones.INSTALL_TYPE != 'win':
|
||||
<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>
|
||||
% endif
|
||||
|
||||
<header>
|
||||
|
||||
<header>
|
||||
<div class="wrapper">
|
||||
<div id="logo">
|
||||
<a href="home"><img src="images/headphoneslogo.png" alt="headphones"></a>
|
||||
@@ -64,7 +64,7 @@
|
||||
<input type="submit" value="Add"/>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -91,16 +91,16 @@
|
||||
%if version.HEADPHONES_VERSION != 'master':
|
||||
(${version.HEADPHONES_VERSION})
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<a href="#main" id="toTop"><span>Back to top</span></a>
|
||||
</div>
|
||||
|
||||
<script src="js/libs/jquery-1.7.2.min.js"></script>
|
||||
<script src="js/libs/jquery-ui.min.js"></script>
|
||||
|
||||
|
||||
${next.javascriptIncludes()}
|
||||
|
||||
|
||||
<script src="js/plugins.js"></script>
|
||||
<script src="interfaces/default/js/script.js"></script>
|
||||
<!--[if lt IE 7 ]>
|
||||
|
||||
@@ -41,6 +41,7 @@ SYS_ENCODING = None
|
||||
|
||||
VERBOSE = 1
|
||||
DAEMON = False
|
||||
CREATEPID = False
|
||||
PIDFILE= None
|
||||
|
||||
SCHED = Scheduler()
|
||||
@@ -74,6 +75,8 @@ API_ENABLED = False
|
||||
API_KEY = None
|
||||
|
||||
GIT_PATH = None
|
||||
GIT_USER = None
|
||||
GIT_BRANCH =None
|
||||
INSTALL_TYPE = None
|
||||
CURRENT_VERSION = None
|
||||
LATEST_VERSION = None
|
||||
@@ -262,9 +265,9 @@ def check_setting_str(config, cfg_name, item_name, def_val, log=True):
|
||||
def initialize():
|
||||
|
||||
with INIT_LOCK:
|
||||
|
||||
|
||||
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, \
|
||||
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, \
|
||||
@@ -280,10 +283,10 @@ def initialize():
|
||||
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, \
|
||||
PREFERRED_BITRATE_LOW_BUFFER,CACHE_SIZEMB
|
||||
|
||||
|
||||
if __INITIALIZED__:
|
||||
return False
|
||||
|
||||
|
||||
# Make sure all the config sections exist
|
||||
CheckSection('General')
|
||||
CheckSection('SABnzbd')
|
||||
@@ -301,18 +304,18 @@ def initialize():
|
||||
CheckSection('NMA')
|
||||
CheckSection('Synoindex')
|
||||
CheckSection('Advanced')
|
||||
|
||||
|
||||
# Set global variables based on config file or use defaults
|
||||
CONFIG_VERSION = check_setting_str(CFG, 'General', 'config_version', '0')
|
||||
|
||||
|
||||
try:
|
||||
HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8181)
|
||||
except:
|
||||
HTTP_PORT = 8181
|
||||
|
||||
|
||||
if HTTP_PORT < 21 or HTTP_PORT > 65535:
|
||||
HTTP_PORT = 8181
|
||||
|
||||
|
||||
HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0')
|
||||
HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '')
|
||||
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_KEY = check_setting_str(CFG, 'General', 'api_key', '')
|
||||
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', '')
|
||||
CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', '')
|
||||
|
||||
|
||||
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_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360)
|
||||
|
||||
|
||||
MUSIC_DIR = check_setting_str(CFG, 'General', 'music_dir', '')
|
||||
DESTINATION_DIR = check_setting_str(CFG, 'General', '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_ALL = bool(check_setting_int(CFG, 'General', 'autowant_all', 0))
|
||||
KEEP_TORRENT_FILES = bool(check_setting_int(CFG, 'General', 'keep_torrent_files', 0))
|
||||
|
||||
|
||||
SEARCH_INTERVAL = check_setting_int(CFG, 'General', 'search_interval', 1440)
|
||||
LIBRARYSCAN = bool(check_setting_int(CFG, 'General', 'libraryscan', 1))
|
||||
LIBRARYSCAN_INTERVAL = check_setting_int(CFG, 'General', 'libraryscan_interval', 300)
|
||||
DOWNLOAD_SCAN_INTERVAL = check_setting_int(CFG, 'General', 'download_scan_interval', 5)
|
||||
|
||||
|
||||
TORRENTBLACKHOLE_DIR = check_setting_str(CFG, 'General', 'torrentblackhole_dir', '')
|
||||
NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10')
|
||||
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_UID = check_setting_str(CFG, 'Waffles', 'waffles_uid', '')
|
||||
WAFFLES_PASSKEY = check_setting_str(CFG, 'Waffles', 'waffles_passkey', '')
|
||||
|
||||
|
||||
RUTRACKER = bool(check_setting_int(CFG, 'Rutracker', 'rutracker', 0))
|
||||
RUTRACKER_USER = check_setting_str(CFG, 'Rutracker', 'rutracker_user', '')
|
||||
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_APIKEY = check_setting_str(CFG, 'SABnzbd', 'sab_apikey', '')
|
||||
SAB_CATEGORY = check_setting_str(CFG, 'SABnzbd', 'sab_category', '')
|
||||
|
||||
|
||||
NZBMATRIX = bool(check_setting_int(CFG, 'NZBMatrix', 'nzbmatrix', 0))
|
||||
NZBMATRIX_USERNAME = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_username', '')
|
||||
NZBMATRIX_APIKEY = check_setting_str(CFG, 'NZBMatrix', 'nzbmatrix_apikey', '')
|
||||
|
||||
|
||||
NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0))
|
||||
NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '')
|
||||
NEWZNAB_APIKEY = check_setting_str(CFG, 'Newznab', 'newznab_apikey', '')
|
||||
NEWZNAB_ENABLED = bool(check_setting_int(CFG, 'Newznab', 'newznab_enabled', 1))
|
||||
|
||||
|
||||
# Need to pack the extra newznabs back into a list of tuples
|
||||
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)]))
|
||||
|
||||
|
||||
NZBSORG = bool(check_setting_int(CFG, 'NZBsorg', 'nzbsorg', 0))
|
||||
NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '')
|
||||
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_UID = check_setting_str(CFG, 'Newzbin', 'newzbin_uid', '')
|
||||
NEWZBIN_PASSWORD = check_setting_str(CFG, 'Newzbin', 'newzbin_password', '')
|
||||
|
||||
|
||||
NZBSRUS = bool(check_setting_int(CFG, 'NZBsRus', 'nzbsrus', 0))
|
||||
NZBSRUS_UID = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_uid', '')
|
||||
NZBSRUS_APIKEY = check_setting_str(CFG, 'NZBsRus', 'nzbsrus_apikey', '')
|
||||
|
||||
LASTFM_USERNAME = check_setting_str(CFG, 'General', 'lastfm_username', '')
|
||||
|
||||
|
||||
INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default')
|
||||
FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755')
|
||||
|
||||
|
||||
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')
|
||||
XLDPROFILE = check_setting_str(CFG, 'General', 'xldprofile', '')
|
||||
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_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)
|
||||
|
||||
|
||||
XBMC_ENABLED = bool(check_setting_int(CFG, 'XBMC', 'xbmc_enabled', 0))
|
||||
XBMC_HOST = check_setting_str(CFG, 'XBMC', 'xbmc_host', '')
|
||||
XBMC_USERNAME = check_setting_str(CFG, 'XBMC', 'xbmc_username', '')
|
||||
XBMC_PASSWORD = check_setting_str(CFG, 'XBMC', 'xbmc_password', '')
|
||||
XBMC_UPDATE = bool(check_setting_int(CFG, 'XBMC', 'xbmc_update', 0))
|
||||
XBMC_NOTIFY = bool(check_setting_int(CFG, 'XBMC', 'xbmc_notify', 0))
|
||||
|
||||
|
||||
NMA_ENABLED = bool(check_setting_int(CFG, 'NMA', 'nma_enabled', 0))
|
||||
NMA_APIKEY = check_setting_str(CFG, 'NMA', 'nma_apikey', '')
|
||||
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))
|
||||
|
||||
|
||||
PUSHOVER_ENABLED = bool(check_setting_int(CFG, 'Pushover', 'pushover_enabled', 0))
|
||||
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)
|
||||
|
||||
|
||||
MIRROR = check_setting_str(CFG, 'General', 'mirror', 'musicbrainz.org')
|
||||
CUSTOMHOST = check_setting_str(CFG, 'General', 'customhost', 'localhost')
|
||||
CUSTOMPORT = check_setting_int(CFG, 'General', 'customport', 5000)
|
||||
@@ -463,9 +468,9 @@ def initialize():
|
||||
HPPASS = check_setting_str(CFG, 'General', 'hppass', '')
|
||||
|
||||
CACHE_SIZEMB = check_setting_int(CFG,'Advanced','cache_sizemb',32)
|
||||
|
||||
|
||||
ALBUM_COMPLETION_PCT = check_setting_int(CFG, 'Advanced', 'album_completion_pct', 80)
|
||||
|
||||
|
||||
# update folder formats in the config & bump up config version
|
||||
if CONFIG_VERSION == '0':
|
||||
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' }
|
||||
FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
|
||||
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
|
||||
|
||||
|
||||
CONFIG_VERSION = '1'
|
||||
|
||||
|
||||
if CONFIG_VERSION == '1':
|
||||
|
||||
from headphones.helpers import replace_all
|
||||
@@ -501,32 +506,32 @@ def initialize():
|
||||
'year': '$year',
|
||||
'type': '$type',
|
||||
'first': '$first'
|
||||
}
|
||||
}
|
||||
FILE_FORMAT = replace_all(FILE_FORMAT, file_values)
|
||||
FOLDER_FORMAT = replace_all(FOLDER_FORMAT, folder_values)
|
||||
|
||||
|
||||
CONFIG_VERSION = '2'
|
||||
|
||||
|
||||
if CONFIG_VERSION == '2':
|
||||
|
||||
|
||||
# Update the config to use direct path to the encoder rather than the encoder folder
|
||||
if ENCODERFOLDER:
|
||||
ENCODER_PATH = os.path.join(ENCODERFOLDER, ENCODER)
|
||||
CONFIG_VERSION = '3'
|
||||
|
||||
|
||||
if not LOG_DIR:
|
||||
LOG_DIR = os.path.join(DATA_DIR, 'logs')
|
||||
|
||||
|
||||
if not os.path.exists(LOG_DIR):
|
||||
try:
|
||||
os.makedirs(LOG_DIR)
|
||||
except OSError:
|
||||
if VERBOSE:
|
||||
print 'Unable to create the log directory. Logging to screen only.'
|
||||
|
||||
|
||||
# Start the logger, silence console logging if we need to
|
||||
logger.headphones_log.initLogger(verbose=VERBOSE)
|
||||
|
||||
|
||||
if not CACHE_DIR:
|
||||
# Put the cache dir in the data dir for now
|
||||
CACHE_DIR = os.path.join(DATA_DIR, 'cache')
|
||||
@@ -535,23 +540,23 @@ def initialize():
|
||||
os.makedirs(CACHE_DIR)
|
||||
except OSError:
|
||||
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
|
||||
if SEARCH_INTERVAL < 360:
|
||||
logger.info("Search interval too low. Resetting to 6 hour minimum")
|
||||
SEARCH_INTERVAL = 360
|
||||
|
||||
|
||||
# Initialize the database
|
||||
logger.info('Checking to see if the database has all tables....')
|
||||
try:
|
||||
dbcheck()
|
||||
except Exception, e:
|
||||
logger.error("Can't connect to the database: %s" % e)
|
||||
|
||||
|
||||
# Get the currently installed version - returns None, 'win32' or the git hash
|
||||
# Also sets INSTALL_TYPE variable to 'win', 'git' or 'source'
|
||||
CURRENT_VERSION = versioncheck.getVersion()
|
||||
|
||||
|
||||
# Check for new versions
|
||||
if CHECK_GITHUB_ON_STARTUP:
|
||||
try:
|
||||
@@ -563,62 +568,62 @@ def initialize():
|
||||
|
||||
__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()
|
||||
if pid == 0:
|
||||
pass
|
||||
else:
|
||||
# Exit the parent process
|
||||
logger.debug('Forking once...')
|
||||
os._exit(0)
|
||||
pid = os.fork() # @UndefinedVariable - only available in UNIX
|
||||
if pid != 0:
|
||||
sys.exit(0)
|
||||
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()
|
||||
|
||||
# Do second fork
|
||||
try:
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
logger.debug('Forking twice...')
|
||||
os._exit(0) # Exit second parent process
|
||||
except OSError, e:
|
||||
sys.exit("2nd fork failed: %s [%d]" % (e.strerror, e.errno))
|
||||
# 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())
|
||||
|
||||
os.chdir("/")
|
||||
os.umask(0)
|
||||
|
||||
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()
|
||||
pid = str(os.getpid())
|
||||
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)
|
||||
|
||||
def launch_browser(host, port, root):
|
||||
|
||||
if host == '0.0.0.0':
|
||||
host = 'localhost'
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
webbrowser.open('http://%s:%i%s' % (host, port, root))
|
||||
except Exception, 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']['cache_dir'] = CACHE_DIR
|
||||
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_on_startup'] = int(CHECK_GITHUB_ON_STARTUP)
|
||||
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_all'] = int(AUTOWANT_ALL)
|
||||
new_config['General']['keep_torrent_files'] = int(KEEP_TORRENT_FILES)
|
||||
|
||||
|
||||
new_config['General']['numberofseeders'] = NUMBEROFSEEDERS
|
||||
new_config['General']['torrentblackhole_dir'] = TORRENTBLACKHOLE_DIR
|
||||
new_config['General']['isohunt'] = int(ISOHUNT)
|
||||
@@ -686,7 +693,7 @@ def config_write():
|
||||
new_config['Waffles']['waffles'] = int(WAFFLES)
|
||||
new_config['Waffles']['waffles_uid'] = WAFFLES_UID
|
||||
new_config['Waffles']['waffles_passkey'] = WAFFLES_PASSKEY
|
||||
|
||||
|
||||
new_config['Rutracker'] = {}
|
||||
new_config['Rutracker']['rutracker'] = int(RUTRACKER)
|
||||
new_config['Rutracker']['rutracker_user'] = RUTRACKER_USER
|
||||
@@ -724,30 +731,30 @@ def config_write():
|
||||
for newznab in EXTRA_NEWZNABS:
|
||||
for item in newznab:
|
||||
flattened_newznabs.append(item)
|
||||
|
||||
|
||||
new_config['Newznab']['extra_newznabs'] = flattened_newznabs
|
||||
|
||||
new_config['NZBsorg'] = {}
|
||||
new_config['NZBsorg']['nzbsorg'] = int(NZBSORG)
|
||||
new_config['NZBsorg']['nzbsorg_uid'] = NZBSORG_UID
|
||||
new_config['NZBsorg']['nzbsorg_hash'] = NZBSORG_HASH
|
||||
|
||||
|
||||
new_config['Newzbin'] = {}
|
||||
new_config['Newzbin']['newzbin'] = int(NEWZBIN)
|
||||
new_config['Newzbin']['newzbin_uid'] = NEWZBIN_UID
|
||||
new_config['Newzbin']['newzbin_password'] = NEWZBIN_PASSWORD
|
||||
|
||||
|
||||
new_config['NZBsRus'] = {}
|
||||
new_config['NZBsRus']['nzbsrus'] = int(NZBSRUS)
|
||||
new_config['NZBsRus']['nzbsrus_uid'] = NZBSRUS_UID
|
||||
new_config['NZBsRus']['nzbsrus_apikey'] = NZBSRUS_APIKEY
|
||||
|
||||
|
||||
new_config['Prowl'] = {}
|
||||
new_config['Prowl']['prowl_enabled'] = int(PROWL_ENABLED)
|
||||
new_config['Prowl']['prowl_keys'] = PROWL_KEYS
|
||||
new_config['Prowl']['prowl_onsnatch'] = int(PROWL_ONSNATCH)
|
||||
new_config['Prowl']['prowl_priority'] = int(PROWL_PRIORITY)
|
||||
|
||||
|
||||
new_config['XBMC'] = {}
|
||||
new_config['XBMC']['xbmc_enabled'] = int(XBMC_ENABLED)
|
||||
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_update'] = int(XBMC_UPDATE)
|
||||
new_config['XBMC']['xbmc_notify'] = int(XBMC_NOTIFY)
|
||||
|
||||
|
||||
new_config['NMA'] = {}
|
||||
new_config['NMA']['nma_enabled'] = int(NMA_ENABLED)
|
||||
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_onsnatch'] = int(PUSHOVER_ONSNATCH)
|
||||
new_config['Pushover']['pushover_priority'] = int(PUSHOVER_PRIORITY)
|
||||
|
||||
|
||||
new_config['Synoindex'] = {}
|
||||
new_config['Synoindex']['synoindex_enabled'] = int(SYNOINDEX_ENABLED)
|
||||
|
||||
|
||||
new_config['General']['lastfm_username'] = LASTFM_USERNAME
|
||||
new_config['General']['interface'] = INTERFACE
|
||||
new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS
|
||||
@@ -787,43 +794,48 @@ def config_write():
|
||||
new_config['General']['encodervbrcbr'] = ENCODERVBRCBR
|
||||
new_config['General']['encoderlossless'] = int(ENCODERLOSSLESS)
|
||||
new_config['General']['delete_lossless_files'] = int(DELETE_LOSSLESS_FILES)
|
||||
|
||||
|
||||
new_config['General']['mirror'] = MIRROR
|
||||
new_config['General']['customhost'] = CUSTOMHOST
|
||||
new_config['General']['customport'] = CUSTOMPORT
|
||||
new_config['General']['customsleep'] = CUSTOMSLEEP
|
||||
new_config['General']['hpuser'] = HPUSER
|
||||
new_config['General']['hppass'] = HPPASS
|
||||
|
||||
|
||||
new_config['Advanced'] = {}
|
||||
new_config['Advanced']['album_completion_pct'] = ALBUM_COMPLETION_PCT
|
||||
new_config['Advanced']['cache_sizemb'] = CACHE_SIZEMB
|
||||
|
||||
|
||||
new_config.write()
|
||||
|
||||
|
||||
|
||||
def start():
|
||||
|
||||
|
||||
global __INITIALIZED__, started
|
||||
|
||||
|
||||
if __INITIALIZED__:
|
||||
|
||||
|
||||
# Start our scheduled background tasks
|
||||
from headphones import updater, searcher, librarysync, postprocessor
|
||||
|
||||
SCHED.add_interval_job(updater.dbUpdate, hours=24)
|
||||
SCHED.add_interval_job(searcher.searchforalbum, minutes=SEARCH_INTERVAL)
|
||||
SCHED.add_interval_job(librarysync.libraryScan, minutes=LIBRARYSCAN_INTERVAL, kwargs={'cron':True})
|
||||
|
||||
|
||||
if CHECK_GITHUB:
|
||||
SCHED.add_interval_job(versioncheck.checkGithub, minutes=CHECK_GITHUB_INTERVAL)
|
||||
|
||||
|
||||
SCHED.add_interval_job(postprocessor.checkFolder, minutes=DOWNLOAD_SCAN_INTERVAL)
|
||||
|
||||
SCHED.start()
|
||||
|
||||
|
||||
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():
|
||||
|
||||
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 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)')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT IncludeExtras from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN IncludeExtras INTEGER DEFAULT 0')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT LatestAlbum from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN LatestAlbum TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseDate from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN ReleaseDate TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT AlbumID from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN AlbumID TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT HaveTracks from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN HaveTracks INTEGER DEFAULT 0')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT TotalTracks from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN TotalTracks INTEGER DEFAULT 0')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT Type from albums')
|
||||
except sqlite3.OperationalError:
|
||||
@@ -882,108 +894,108 @@ def dbcheck():
|
||||
c.execute('SELECT TrackNumber from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN TrackNumber INTEGER')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT FolderName from snatched')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE snatched ADD COLUMN FolderName TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT Location from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN Location TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT Location from have')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE have ADD COLUMN Location TEXT')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT BitRate from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN BitRate INTEGER')
|
||||
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN BitRate INTEGER')
|
||||
|
||||
try:
|
||||
c.execute('SELECT CleanName from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN CleanName TEXT')
|
||||
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN CleanName TEXT')
|
||||
|
||||
try:
|
||||
c.execute('SELECT CleanName from have')
|
||||
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
|
||||
try:
|
||||
c.execute('SELECT Format from have')
|
||||
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:
|
||||
c.execute('SELECT Format from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN Format TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT LastUpdated from artists')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE artists ADD COLUMN LastUpdated TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT ArtworkURL from artists')
|
||||
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:
|
||||
c.execute('SELECT ArtworkURL from albums')
|
||||
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:
|
||||
c.execute('SELECT ThumbURL from artists')
|
||||
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:
|
||||
c.execute('SELECT ThumbURL from albums')
|
||||
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:
|
||||
c.execute('SELECT ArtistID from descriptions')
|
||||
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:
|
||||
c.execute('SELECT LastUpdated from descriptions')
|
||||
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:
|
||||
c.execute('SELECT ReleaseID from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseID TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseFormat from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseFormat TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseCountry from albums')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE albums ADD COLUMN ReleaseCountry TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT ReleaseID from tracks')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE tracks ADD COLUMN ReleaseID TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT Matched from have')
|
||||
except sqlite3.OperationalError:
|
||||
c.execute('ALTER TABLE have ADD COLUMN Matched TEXT DEFAULT NULL')
|
||||
|
||||
|
||||
try:
|
||||
c.execute('SELECT Extras from artists')
|
||||
except sqlite3.OperationalError:
|
||||
@@ -1010,27 +1022,28 @@ def dbcheck():
|
||||
conn.commit()
|
||||
c.close()
|
||||
|
||||
|
||||
|
||||
def shutdown(restart=False, update=False):
|
||||
|
||||
cherrypy.engine.exit()
|
||||
SCHED.shutdown(wait=False)
|
||||
|
||||
|
||||
config_write()
|
||||
|
||||
|
||||
if not restart and not update:
|
||||
logger.info('Headphones is shutting down...')
|
||||
|
||||
if update:
|
||||
logger.info('Headphones is updating...')
|
||||
try:
|
||||
versioncheck.update()
|
||||
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)
|
||||
os.remove(PIDFILE)
|
||||
|
||||
|
||||
if restart:
|
||||
logger.info('Headphones is restarting...')
|
||||
popen_list = [sys.executable, FULL_PATH]
|
||||
@@ -1039,5 +1052,5 @@ def shutdown(restart=False, update=False):
|
||||
popen_list += ['--nolaunch']
|
||||
logger.info('Restarting Headphones with ' + str(popen_list))
|
||||
subprocess.Popen(popen_list, cwd=os.getcwd())
|
||||
|
||||
|
||||
os._exit(0)
|
||||
|
||||
@@ -17,29 +17,27 @@ import platform, subprocess, re, os, urllib2, tarfile
|
||||
|
||||
import headphones
|
||||
from headphones import logger, version
|
||||
from headphones.exceptions import ex
|
||||
|
||||
import lib.simplejson as simplejson
|
||||
|
||||
user = "rembo10"
|
||||
branch = "master"
|
||||
|
||||
def runGit(args):
|
||||
|
||||
if headphones.GIT_PATH:
|
||||
git_locations = ['"'+headphones.GIT_PATH+'"']
|
||||
else:
|
||||
git_locations = ['git']
|
||||
|
||||
|
||||
if platform.system().lower() == 'darwin':
|
||||
git_locations.append('/usr/local/git/bin/git')
|
||||
|
||||
|
||||
|
||||
|
||||
output = err = None
|
||||
|
||||
|
||||
for cur_git in git_locations:
|
||||
|
||||
|
||||
cmd = cur_git+' '+args
|
||||
|
||||
|
||||
try:
|
||||
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)
|
||||
@@ -48,7 +46,7 @@ def runGit(args):
|
||||
except OSError:
|
||||
logger.debug('Command ' + cmd + ' didn\'t work, couldn\'t find git')
|
||||
continue
|
||||
|
||||
|
||||
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)
|
||||
output = None
|
||||
@@ -57,58 +55,58 @@ def runGit(args):
|
||||
output = None
|
||||
elif output:
|
||||
break
|
||||
|
||||
|
||||
return (output, err)
|
||||
|
||||
|
||||
def getVersion():
|
||||
|
||||
if version.HEADPHONES_VERSION.startswith('win32build'):
|
||||
|
||||
|
||||
headphones.INSTALL_TYPE = 'win'
|
||||
|
||||
|
||||
# Don't have a way to update exe yet, but don't want to set VERSION to None
|
||||
return 'Windows Install'
|
||||
|
||||
|
||||
elif os.path.isdir(os.path.join(headphones.PROG_DIR, '.git')):
|
||||
|
||||
|
||||
headphones.INSTALL_TYPE = 'git'
|
||||
output, err = runGit('rev-parse HEAD')
|
||||
|
||||
|
||||
if not output:
|
||||
logger.error('Couldn\'t find latest installed version.')
|
||||
return None
|
||||
|
||||
|
||||
cur_commit_hash = output.strip()
|
||||
|
||||
|
||||
if not re.match('^[a-z0-9]+$', cur_commit_hash):
|
||||
logger.error('Output doesn\'t look like a hash, not using it')
|
||||
return None
|
||||
|
||||
|
||||
return cur_commit_hash
|
||||
|
||||
|
||||
else:
|
||||
|
||||
|
||||
headphones.INSTALL_TYPE = 'source'
|
||||
|
||||
|
||||
version_file = os.path.join(headphones.PROG_DIR, 'version.txt')
|
||||
|
||||
|
||||
if not os.path.isfile(version_file):
|
||||
return None
|
||||
|
||||
|
||||
fp = open(version_file, 'r')
|
||||
current_version = fp.read().strip(' \n\r')
|
||||
fp.close()
|
||||
|
||||
|
||||
if current_version:
|
||||
return current_version
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def checkGithub():
|
||||
|
||||
# Get the latest commit available from github
|
||||
url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (user, branch)
|
||||
logger.info ('Retrieving latest version information from github')
|
||||
url = 'https://api.github.com/repos/%s/headphones/commits/%s' % (headphones.GIT_USER, headphones.GIT_BRANCH)
|
||||
logger.info('Retrieving latest version information from github')
|
||||
try:
|
||||
result = urllib2.urlopen(url).read()
|
||||
git = simplejson.JSONDecoder().decode(result)
|
||||
@@ -117,12 +115,12 @@ def checkGithub():
|
||||
logger.warn('Could not get the latest commit from github')
|
||||
headphones.COMMITS_BEHIND = 0
|
||||
return headphones.CURRENT_VERSION
|
||||
|
||||
# See how many commits behind we are
|
||||
|
||||
# See how many commits behind we are
|
||||
if headphones.CURRENT_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:
|
||||
result = urllib2.urlopen(url).read()
|
||||
git = simplejson.JSONDecoder().decode(result)
|
||||
@@ -131,99 +129,99 @@ def checkGithub():
|
||||
logger.warn('Could not get commits behind from github')
|
||||
headphones.COMMITS_BEHIND = 0
|
||||
return headphones.CURRENT_VERSION
|
||||
|
||||
|
||||
if headphones.COMMITS_BEHIND >= 1:
|
||||
logger.info('New version is available. You are %s commits behind' % headphones.COMMITS_BEHIND)
|
||||
elif headphones.COMMITS_BEHIND == 0:
|
||||
logger.info('Headphones is up to date')
|
||||
elif headphones.COMMITS_BEHIND == -1:
|
||||
logger.info('You are running an unknown version of Headphones. Run the updater to identify your version')
|
||||
|
||||
|
||||
else:
|
||||
logger.info('You are running an unknown version of Headphones. Run the updater to identify your version')
|
||||
|
||||
|
||||
return headphones.LATEST_VERSION
|
||||
|
||||
|
||||
def update():
|
||||
|
||||
|
||||
|
||||
if headphones.INSTALL_TYPE == 'win':
|
||||
|
||||
|
||||
logger.info('Windows .exe updating not supported yet.')
|
||||
pass
|
||||
|
||||
|
||||
|
||||
elif headphones.INSTALL_TYPE == 'git':
|
||||
|
||||
|
||||
output, err = runGit('pull origin ' + version.HEADPHONES_VERSION)
|
||||
|
||||
|
||||
if not output:
|
||||
logger.error('Couldn\'t download latest version')
|
||||
|
||||
|
||||
for line in output.split('\n'):
|
||||
|
||||
|
||||
if 'Already up-to-date.' in line:
|
||||
logger.info('No update available, not updating')
|
||||
logger.info('Output: ' + str(output))
|
||||
elif line.endswith('Aborting.'):
|
||||
logger.error('Unable to update from git: '+line)
|
||||
logger.info('Output: ' + str(output))
|
||||
|
||||
|
||||
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')
|
||||
version_path = os.path.join(headphones.PROG_DIR, 'version.txt')
|
||||
|
||||
|
||||
try:
|
||||
logger.info('Downloading update from: '+tar_download_url)
|
||||
data = urllib2.urlopen(tar_download_url)
|
||||
except (IOError, URLError):
|
||||
logger.error("Unable to retrieve new version from "+tar_download_url+", can't update")
|
||||
return
|
||||
|
||||
|
||||
download_name = data.geturl().split('/')[-1]
|
||||
|
||||
|
||||
tar_download_path = os.path.join(headphones.PROG_DIR, download_name)
|
||||
|
||||
|
||||
# Save tar to disk
|
||||
f = open(tar_download_path, 'wb')
|
||||
f.write(data.read())
|
||||
f.close()
|
||||
|
||||
|
||||
# Extract the tar to update folder
|
||||
logger.info('Extracing file' + tar_download_path)
|
||||
tar = tarfile.open(tar_download_path)
|
||||
tar.extractall(update_dir)
|
||||
tar.close()
|
||||
|
||||
|
||||
# Delete the tar.gz
|
||||
logger.info('Deleting file' + tar_download_path)
|
||||
os.remove(tar_download_path)
|
||||
|
||||
|
||||
# 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))]
|
||||
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
|
||||
content_dir = os.path.join(update_dir, update_dir_contents[0])
|
||||
|
||||
|
||||
# walk temp folder and move files to main folder
|
||||
for dirname, dirnames, filenames in os.walk(content_dir):
|
||||
dirname = dirname[len(content_dir)+1:]
|
||||
for curfile in filenames:
|
||||
old_path = os.path.join(content_dir, dirname, curfile)
|
||||
new_path = os.path.join(headphones.PROG_DIR, dirname, curfile)
|
||||
|
||||
|
||||
if os.path.isfile(new_path):
|
||||
os.remove(new_path)
|
||||
os.renames(old_path, new_path)
|
||||
|
||||
|
||||
# Update version.txt
|
||||
try:
|
||||
ver_file = open(version_path, 'w')
|
||||
ver_file.write(headphones.LATEST_VERSION)
|
||||
ver_file.close()
|
||||
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
|
||||
|
||||
209
init.ubuntu
Normal file → Executable file
209
init.ubuntu
Normal file → Executable 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
|
||||
# Provides: headphones
|
||||
# Required-Start: $local_fs $network $remote_fs
|
||||
@@ -12,50 +51,152 @@
|
||||
# Description: starts instance of Headphones using start-stop-daemon
|
||||
### END INIT INFO
|
||||
|
||||
############### EDIT ME ##################
|
||||
# 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
|
||||
# Script name
|
||||
NAME=headphones
|
||||
|
||||
# app name
|
||||
DESC=headphones
|
||||
# App name
|
||||
DESC=Headphones
|
||||
|
||||
# user
|
||||
RUN_AS=root
|
||||
SETTINGS_LOADED=FALSE
|
||||
|
||||
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
|
||||
start)
|
||||
echo "Starting $DESC"
|
||||
start-stop-daemon -d $APP_PATH -c $RUN_AS --start --background --pidfile $PID_FILE --make-pidfile --exec $DAEMON -- $DAEMON_OPTS
|
||||
start)
|
||||
start_headphones
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping $DESC"
|
||||
start-stop-daemon --stop --pidfile $PID_FILE
|
||||
stop)
|
||||
stop_headphones
|
||||
;;
|
||||
|
||||
restart|force-reload)
|
||||
echo "Restarting $DESC"
|
||||
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
|
||||
restart|force-reload)
|
||||
stop_headphones
|
||||
start_headphones
|
||||
;;
|
||||
*)
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload}" >&2
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user