Compare commits

...
27 Commits
Author SHA1 Message Date
rembo10 18c4b87158 Merge branch 'develop' 2013-10-11 13:58:23 +02:00
rembo10 e8829e36d8 Merge branch 'piratebay-proxy' into develop 2013-09-23 18:44:41 +05:30
rembo10 8a6c37bcf6 Added piratebay proxy url to config page 2013-09-23 18:44:11 +05:30
rembo10 6f8f2c292b Added ability to use a piratebay proxy to the backend 2013-09-23 18:27:27 +05:30
rembo10 5c60019d38 Use int(x,8) for file permissions 2013-09-21 11:33:18 +05:30
rembo10 8d6ff27882 Merge branch 'file-permissions' into develop 2013-09-09 14:20:44 +05:30
rembo10 d9cd120ca8 Fixed a typo, int() the permissions string 2013-09-09 14:20:34 +05:30
rembo10 2e1c9d7f84 Added file permissions & folder permissions to config page 2013-09-08 15:03:23 +05:30
rembo10 2f07d952b2 Added file_permissions to config & post processor 2013-09-08 14:57:17 +05:30
rembo10 dc69421f39 Bug fixes, added HTTPS support, music encoder fix, sanity checking for
transmission, piratebay torrage support
2013-08-26 15:15:43 +05:30
rembo10 70bcee2fa7 Merge remote-tracking branch 'coolbombom/master' into develop 2013-08-25 12:46:51 +05:30
rembo10 b8c2ad9c73 Merge remote-tracking branch 'bakie/feature/use_underscores' into develop 2013-08-24 10:26:36 +05:30
rembo10 e115d266ac Merge branch 'bug-fixes' into develop 2013-08-24 10:20:09 +05:30
rembo10 eed11d8493 Merge branch 'ssl-support' into develop 2013-08-24 10:19:54 +05:30
rembo10 7502959310 Changed waffles passkey to password input type 2013-08-24 10:19:02 +05:30
rembo10 2e55b0eb5b Modified gitignore to exclude cert & key files for https 2013-08-24 10:15:20 +05:30
rembo10 ea1d86b6b1 Added https options to web interface 2013-08-24 10:13:51 +05:30
rembo10 482cb68bd6 Fixed up some bugs/bad imports, added lib/certgen 2013-08-24 09:51:58 +05:30
rembo10 a5c087465c Added backend code for ssl support (init.py, webstart.py) 2013-08-24 09:20:37 +05:30
rembo10 28e1380c3a Merge remote-tracking branch 'AdeHub/master' into develop 2013-08-20 09:38:11 +05:30
rembo10 dd58d78f5f Fix for post-processing the same album multiple times if torrent download dir == nzb download dir 2013-08-14 12:03:50 +05:30
rembo10 411383c856 A little bit of error checking for Transmission 2013-08-14 11:40:34 +05:30
Bakie 0b22e5fde6 use underscores during rename and move 2013-08-11 17:19:15 +02:00
Ade 12dda31891 Encoder fix up
missed a couple of commas
2013-08-09 08:30:24 +12:00
rembo10 95bafed76a Fix for torrent temp-folder not being created when non-ascii chars in foldername 2013-08-06 10:00:41 -07:00
coolbombom 1084c11866 Update searcher.py 2013-08-06 12:08:26 +02:00
rembo10 24187955fa Merge branch 'torrent-quick-fixes' into develop 2013-08-05 19:56:59 -07:00
12 changed files with 341 additions and 45 deletions
+5
View File
@@ -15,6 +15,11 @@
logs/*
cache/*
# HTTPS Cert/Key #
##################
*.crt
*.key
# OS generated files #
######################
.DS_Store?
+4 -3
View File
@@ -142,7 +142,7 @@ def main():
# Force the http port if neccessary
if args.port:
http_port = args.port
logger.info('Starting Headphones on forced port: %i' % http_port)
logger.info('Using forced port: %i' % http_port)
else:
http_port = int(headphones.HTTP_PORT)
@@ -152,12 +152,13 @@ def main():
'http_host': headphones.HTTP_HOST,
'http_root': headphones.HTTP_ROOT,
'http_proxy': headphones.HTTP_PROXY,
'enable_https': headphones.ENABLE_HTTPS,
'https_cert': headphones.HTTPS_CERT,
'https_key': headphones.HTTPS_KEY,
'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)
+53 -2
View File
@@ -54,6 +54,19 @@
<div class="row checkbox">
<input type="checkbox" name="launch_browser" value="1" ${config['launch_browser']} /> <label>Launch Browser on Startup</label>
</div>
<div class="row checkbox">
<input type="checkbox" name="enable_https" id="enable_https" value="1" ${config['enable_https']} /> <label>Enable HTTPS</label>
</div>
<div id="https_options">
<div class="row">
<label>HTTPS Cert</label>
<input type="text" name="https_cert" value="${config['https_cert']}" size="30">
</div>
<div class="row">
<label>HTTPS Key</label>
<input type="text" name="https_key" value="${config['https_key']}" size="30">
</div>
</div>
</fieldset>
</td>
<td>
@@ -346,7 +359,13 @@
<fieldset>
<legend>Torrents</legend>
<div class="row checkbox">
<input type="checkbox" name="use_piratebay" value="1" ${config['use_piratebay']} /><label>The Pirate Bay</label>
<input id="usepiratebay" type="checkbox" name="use_piratebay" value="1" ${config['use_piratebay']} /><label>The Pirate Bay</label>
</div>
<div class="config">
<div class="row">
<label>Proxy URL (Optional): </label>
<input type="text" name="piratebay_proxy_url" value="${config['piratebay_proxy_url']}" size="36">
</div>
</div>
<div class="row checkbox">
<input type="checkbox" name="use_isohunt" value="1" ${config['use_isohunt']} /><label>Isohunt</label>
@@ -367,7 +386,7 @@
</div>
<div class="row">
<label>Waffles Passkey: </label>
<input type="text" name="waffles_passkey" value="${config['waffles_passkey']}" size="36">
<input type="password" name="waffles_passkey" value="${config['waffles_passkey']}" size="36">
</div>
</div>
<div class="row checkbox">
@@ -498,6 +517,9 @@
<input type="text" name="file_format" value="${config['file_format']}" size="43">
<small>Use: $Disc/$disc (disc #), $Track/$track (track #), $Title/$title, $Artist/$artist, $Album/$album and $Year/$year</small>
</div>
<div class="checkbox row clearfix">
<input type="checkbox" name="file_underscores" id="file_underscores" value="1" ${config['file_underscores']}/><label>Use underscores instead of spaces</label>
</div>
</fieldset>
<fieldset>
@@ -669,6 +691,14 @@
<div class="row left checkbox">
<input type="checkbox" name="autowant_all" value="1" ${config['autowant_all']} /><label>Automatically Mark All Albums as Wanted</label>
</div>
<div class="row">
<label>Folder Permissions:</label>
<input type="text" name="folder_permissions" value="${config['folder_permissions']}" size="7">
</div>
<div class="row">
<label>File Permissions:</label>
<input type="text" name="file_permissions" value="${config['file_permissions']}" size="7">
</div>
<div class="row">
<label>Cache Size (in MB):</label>
<input type="text" name="cache_sizemb" value="${config['cache_sizemb']}" size="7">
@@ -945,6 +975,25 @@
$('#api_key').val(data);
});
});
if ($("#enable_https").is(":checked"))
{
$("#https_options").show();
}
else
{
$("#https_options").hide();
}
$("#enable_https").click(function(){
if ($("#enable_https").is(":checked"))
{
$("#https_options").slideDown();
}
else
{
$("#https_options").slideUp();
}
});
if ($("#music_encoder").is(":checked"))
{
$("#encoderoptions").show();
@@ -1210,10 +1259,12 @@
initConfigCheckbox("#usenewznab");
initConfigCheckbox("#usenzbsrus");
initConfigCheckbox("#usenzbsorg");
initConfigCheckbox("#usepiratebay");
initConfigCheckbox("#usewaffles");
initConfigCheckbox("#userutracker");
initConfigCheckbox("#usewhatcd");
initConfigCheckbox("#useapi");
initConfigCheckbox("#enable_https");
}
$(document).ready(function() {
initThisPage();
+29 -5
View File
@@ -73,6 +73,10 @@ HTTP_ROOT = None
HTTP_PROXY = False
LAUNCH_BROWSER = False
ENABLE_HTTPS = False
HTTPS_CERT = None
HTTPS_KEY = None
API_ENABLED = False
API_KEY = None
@@ -93,6 +97,7 @@ DESTINATION_DIR = None
LOSSLESS_DESTINATION_DIR = None
FOLDER_FORMAT = None
FILE_FORMAT = None
FILE_UNDERSCORES = False
PATH_TO_XML = None
PREFERRED_QUALITY = None
PREFERRED_BITRATE = None
@@ -179,6 +184,7 @@ ISOHUNT = None
KAT = None
MININOVA = None
PIRATEBAY = None
PIRATEBAY_PROXY_URL = None
WAFFLES = None
WAFFLES_UID = None
WAFFLES_PASSKEY = None
@@ -192,6 +198,7 @@ DOWNLOAD_TORRENT_DIR = None
INTERFACE = None
FOLDER_PERMISSIONS = None
FILE_PERMISSIONS = None
MUSIC_ENCODER = False
ENCODERFOLDER = None
@@ -291,20 +298,20 @@ def initialize():
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, \
RENAME_FILES, FOLDER_FORMAT, FILE_FORMAT, FILE_UNDERSCORES, CLEANUP_FILES, INCLUDE_EXTRAS, EXTRAS, AUTOWANT_UPCOMING, AUTOWANT_ALL, KEEP_TORRENT_FILES, \
ADD_ALBUM_ART, ALBUM_ART_FORMAT, EMBED_ALBUM_ART, EMBED_LYRICS, DOWNLOAD_DIR, BLACKHOLE, BLACKHOLE_DIR, USENET_RETENTION, SEARCH_INTERVAL, \
TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, PIRATEBAY, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, \
TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, PIRATEBAY, PIRATEBAY_PROXY_URL, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, \
RUTRACKER, RUTRACKER_USER, RUTRACKER_PASSWORD, WHATCD, WHATCD_USERNAME, WHATCD_PASSWORD, DOWNLOAD_TORRENT_DIR, \
LIBRARYSCAN, LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \
NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, HEADPHONES_INDEXER, NZBMATRIX, TRANSMISSION_HOST, TRANSMISSION_USERNAME, TRANSMISSION_PASSWORD, \
UTORRENT_HOST, UTORRENT_USERNAME, UTORRENT_PASSWORD, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, \
NZBSORG, NZBSORG_UID, NZBSORG_HASH, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, NZB_DOWNLOADER, TORRENT_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \
LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \
LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, FILE_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \
MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, \
PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_KEYS, PUSHOVER_ONSNATCH, MIRRORLIST, \
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, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, JOURNAL_MODE, UMASK
PREFERRED_BITRATE_LOW_BUFFER, PREFERRED_BITRATE_ALLOW_LOSSLESS, CACHE_SIZEMB, JOURNAL_MODE, UMASK, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY
if __INITIALIZED__:
return False
@@ -345,6 +352,9 @@ def initialize():
HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '')
HTTP_ROOT = check_setting_str(CFG, 'General', 'http_root', '/')
HTTP_PROXY = bool(check_setting_int(CFG, 'General', 'http_proxy', 0))
ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0))
HTTPS_CERT = check_setting_str(CFG, 'General', 'https_cert', os.path.join(DATA_DIR, 'server.crt'))
HTTPS_KEY = check_setting_str(CFG, 'General', 'https_key', os.path.join(DATA_DIR, 'server.key'))
LAUNCH_BROWSER = bool(check_setting_int(CFG, 'General', 'launch_browser', 1))
API_ENABLED = bool(check_setting_int(CFG, 'General', 'api_enabled', 0))
API_KEY = check_setting_str(CFG, 'General', 'api_key', '')
@@ -373,6 +383,7 @@ def initialize():
RENAME_FILES = bool(check_setting_int(CFG, 'General', 'rename_files', 0))
FOLDER_FORMAT = check_setting_str(CFG, 'General', 'folder_format', 'Artist/Album [Year]')
FILE_FORMAT = check_setting_str(CFG, 'General', 'file_format', 'Track Artist - Album [Year] - Title')
FILE_UNDERSCORES = bool(check_setting_int(CFG, 'General', 'file_underscores', 0))
CLEANUP_FILES = bool(check_setting_int(CFG, 'General', 'cleanup_files', 0))
ADD_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'add_album_art', 0))
ALBUM_ART_FORMAT = check_setting_str(CFG, 'General', 'album_art_format', 'folder')
@@ -400,6 +411,7 @@ def initialize():
ISOHUNT = bool(check_setting_int(CFG, 'General', 'isohunt', 0))
KAT = bool(check_setting_int(CFG, 'General', 'kat', 0))
PIRATEBAY = bool(check_setting_int(CFG, 'General', 'piratebay', 0))
PIRATEBAY_PROXY_URL = check_setting_str(CFG, 'General', 'piratebay_proxy_url', '')
MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0))
DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '')
@@ -461,6 +473,7 @@ def initialize():
INTERFACE = check_setting_str(CFG, 'General', 'interface', 'default')
FOLDER_PERMISSIONS = check_setting_str(CFG, 'General', 'folder_permissions', '0755')
FILE_PERMISSIONS = check_setting_str(CFG, 'General', 'file_permissions', '0644')
ENCODERFOLDER = check_setting_str(CFG, 'General', 'encoderfolder', '')
ENCODER_PATH = check_setting_str(CFG, 'General', 'encoder_path', '')
@@ -679,9 +692,14 @@ def launch_browser(host, port, root):
if host == '0.0.0.0':
host = 'localhost'
if ENABLE_HTTPS:
protocol = 'https'
else:
protocol = 'http'
try:
webbrowser.open('http://%s:%i%s' % (host, port, root))
webbrowser.open('%s://%s:%i%s' % (protocol, host, port, root))
except Exception, e:
logger.error('Could not launch browser: %s' % e)
@@ -698,6 +716,9 @@ def config_write():
new_config['General']['http_password'] = HTTP_PASSWORD
new_config['General']['http_root'] = HTTP_ROOT
new_config['General']['http_proxy'] = int(HTTP_PROXY)
new_config['General']['enable_https'] = int(ENABLE_HTTPS)
new_config['General']['https_cert'] = HTTPS_CERT
new_config['General']['https_key'] = HTTPS_KEY
new_config['General']['launch_browser'] = int(LAUNCH_BROWSER)
new_config['General']['api_enabled'] = int(API_ENABLED)
new_config['General']['api_key'] = API_KEY
@@ -726,6 +747,7 @@ def config_write():
new_config['General']['rename_files'] = int(RENAME_FILES)
new_config['General']['folder_format'] = FOLDER_FORMAT
new_config['General']['file_format'] = FILE_FORMAT
new_config['General']['file_underscores'] = int(FILE_UNDERSCORES)
new_config['General']['cleanup_files'] = int(CLEANUP_FILES)
new_config['General']['add_album_art'] = int(ADD_ALBUM_ART)
new_config['General']['album_art_format'] = ALBUM_ART_FORMAT
@@ -748,6 +770,7 @@ def config_write():
new_config['General']['kat'] = int(KAT)
new_config['General']['mininova'] = int(MININOVA)
new_config['General']['piratebay'] = int(PIRATEBAY)
new_config['General']['piratebay_proxy_url'] = PIRATEBAY_PROXY_URL
new_config['General']['download_torrent_dir'] = DOWNLOAD_TORRENT_DIR
new_config['Waffles'] = {}
@@ -855,6 +878,7 @@ def config_write():
new_config['General']['lastfm_username'] = LASTFM_USERNAME
new_config['General']['interface'] = INTERFACE
new_config['General']['folder_permissions'] = FOLDER_PERMISSIONS
new_config['General']['file_permissions'] = FILE_PERMISSIONS
new_config['General']['music_encoder'] = int(MUSIC_ENCODER)
new_config['General']['encoder'] = ENCODER
+34
View File
@@ -345,3 +345,37 @@ def split_string(mystring):
for each_word in mystring.split(','):
mylist.append(each_word.strip())
return mylist
def create_https_certificates(ssl_cert, ssl_key):
"""
Stolen from SickBeard (http://github.com/midgetspy/Sick-Beard):
Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key'
"""
from headphones import logger
try:
from OpenSSL import crypto #@UnresolvedImport
from lib.certgen import createKeyPair, createCertRequest, createCertificate, TYPE_RSA, serial #@UnresolvedImport
except:
logger.warn(u"pyopenssl module missing, please install for https access")
return False
# Create the CA Certificate
cakey = createKeyPair(TYPE_RSA, 1024)
careq = createCertRequest(cakey, CN='Certificate Authority')
cacert = createCertificate(careq, (careq, cakey), serial, (0, 60*60*24*365*10)) # ten years
cname = 'Headphones'
pkey = createKeyPair(TYPE_RSA, 1024)
req = createCertRequest(pkey, CN=cname)
cert = createCertificate(req, (cacert, cakey), serial, (0, 60*60*24*365*10)) # ten years
# Save the key and certificate to disk
try:
open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
except:
logger.error(u"Error creating SSL key and certificate")
return False
return True
+2 -2
View File
@@ -224,9 +224,9 @@ def command(encoder,musicSource,musicDest,albumPath):
opts = []
if headphones.ADVANCEDENCODER =='':
if headphones.ENCODEROUTPUTFORMAT=='ogg':
opts.extend(['-acodec libvorbis'])
opts.extend(['-acodec', 'libvorbis'])
if headphones.ENCODEROUTPUTFORMAT=='m4a':
opts.extend(['-strict experimental'])
opts.extend(['-strict', 'experimental'])
if headphones.ENCODERVBRCBR=='cbr':
opts.extend(['-ar', str(headphones.SAMPLINGFREQUENCY), '-ab', str(headphones.BITRATE) + 'k'])
elif headphones.ENCODERVBRCBR=='vbr':
+48 -20
View File
@@ -43,28 +43,31 @@ def checkFolder():
if album['FolderName']:
# We're now checking sab config options after sending to determine renaming - but we'll keep the
# iterations in just in case we can't read the config for some reason
if album['Kind'] == 'nzb':
# We're now checking sab config options after sending to determine renaming - but we'll keep the
# iterations in just in case we can't read the config for some reason
nzb_album_possibilities = [ album['FolderName'],
sab_replace_dots(album['FolderName']),
sab_replace_spaces(album['FolderName']),
sab_replace_spaces(sab_replace_dots(album['FolderName']))
nzb_album_possibilities = [ album['FolderName'],
sab_replace_dots(album['FolderName']),
sab_replace_spaces(album['FolderName']),
sab_replace_spaces(sab_replace_dots(album['FolderName']))
]
torrent_album_path = os.path.join(headphones.DOWNLOAD_TORRENT_DIR, album['FolderName']).encode(headphones.SYS_ENCODING,'replace')
for nzb_folder_name in nzb_album_possibilities:
nzb_album_path = os.path.join(headphones.DOWNLOAD_DIR, nzb_folder_name).encode(headphones.SYS_ENCODING, 'replace')
for nzb_folder_name in nzb_album_possibilities:
nzb_album_path = os.path.join(headphones.DOWNLOAD_DIR, nzb_folder_name).encode(headphones.SYS_ENCODING, 'replace')
if os.path.exists(nzb_album_path):
logger.debug('Found %s in NZB download folder. Verifying....' % album['FolderName'])
verify(album['AlbumID'], nzb_album_path, 'nzb')
if album['Kind'] == 'torrent':
if os.path.exists(nzb_album_path):
logger.debug('Found %s in NZB download folder. Verifying....' % album['FolderName'])
verify(album['AlbumID'], nzb_album_path, album['Kind'])
if os.path.exists(torrent_album_path):
logger.debug('Found %s in torrent download folder. Verifying....' % album['FolderName'])
verify(album['AlbumID'], torrent_album_path, album['Kind'])
torrent_album_path = os.path.join(headphones.DOWNLOAD_TORRENT_DIR, album['FolderName']).encode(headphones.SYS_ENCODING,'replace')
if os.path.exists(torrent_album_path):
logger.debug('Found %s in torrent download folder. Verifying....' % album['FolderName'])
verify(album['AlbumID'], torrent_album_path, 'torrent')
def verify(albumid, albumpath, Kind=None, forced=False):
@@ -325,7 +328,7 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
logger.info('Starting post-processing for: %s - %s' % (release['ArtistName'], release['AlbumTitle']))
# Check to see if we're preserving the torrent dir
if headphones.KEEP_TORRENT_FILES and Kind=="torrent":
new_folder = os.path.join(albumpath, 'headphones-modified').encode(headphones.SYS_ENCODING, 'replace')
new_folder = os.path.join(albumpath, 'headphones-modified'.encode(headphones.SYS_ENCODING, 'replace'))
logger.info("Copying files to 'headphones-modified' subfolder to preserve downloaded files for seeding")
try:
shutil.copytree(albumpath, new_folder)
@@ -392,6 +395,8 @@ def doPostProcessing(albumid, albumpath, release, tracks, downloaded_track_list,
else:
albumpaths = [albumpath]
updateFilePermissions(albumpaths)
myDB = db.DBConnection()
myDB.action('UPDATE albums SET status = "Downloaded" WHERE AlbumID=?', [albumid])
myDB.action('UPDATE snatched SET status = "Processed" WHERE AlbumID=?', [albumid])
@@ -464,6 +469,9 @@ def addAlbumArt(artwork, albumpath, release):
album_art_name = album_art_name.replace('?','_').replace(':', '_').encode(headphones.SYS_ENCODING, 'replace')
if headphones.FILE_UNDERSCORES:
album_art_name = album_art_name.replace(' ', '_')
if album_art_name.startswith('.'):
album_art_name = album_art_name.replace(0, '_')
@@ -493,6 +501,10 @@ def moveFiles(albumpath, release, tracks):
artist = release['ArtistName'].replace('/', '_')
album = release['AlbumTitle'].replace('/', '_')
if headphones.FILE_UNDERSCORES:
artist = artist.replace(' ', '_')
album = album.replace(' ', '_')
releasetype = release['Type'].replace('/', '_')
if release['ArtistName'].startswith('The '):
@@ -832,6 +844,9 @@ def renameFiles(albumpath, downloaded_track_list, release):
new_file_name = new_file_name.replace('?','_').replace(':', '_').encode(headphones.SYS_ENCODING, 'replace')
if headphones.FILE_UNDERSCORES:
new_file_name = new_file_name.replace(' ', '_')
if new_file_name.startswith('.'):
new_file_name = new_file_name.replace(0, '_')
@@ -847,7 +862,20 @@ def renameFiles(albumpath, downloaded_track_list, release):
except Exception, e:
logger.error('Error renaming file: %s. Error: %s' % (downloaded_track.decode(headphones.SYS_ENCODING, 'replace'), e))
continue
def updateFilePermissions(albumpaths):
for folder in albumpaths:
logger.info("Updating file permissions in " + folder.decode(headphones.SYS_ENCODING, 'replace'))
for r,d,f in os.walk(folder):
for files in f:
full_path = os.path.join(r, files)
try:
os.chmod(full_path, int(headphones.FILE_PERMISSIONS, 8))
except:
logger.error("Could not change permissions for file: " + full_path.decode(headphones.SYS_ENCODING, 'replace'))
continue
def renameUnprocessedFolder(albumpath):
i = 0
+31 -6
View File
@@ -1073,11 +1073,22 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
provider))
# Pirate Bay
if headphones.PIRATEBAY and headphones.TORRENT_DOWNLOADER == 0:
logger.warn("Cannot search Pirate Bay with Blackhole option set")
if headphones.PIRATEBAY and headphones.TORRENT_DOWNLOADER != 0:
if headphones.PIRATEBAY:
provider = "The Pirate Bay"
providerurl = url_fix("http://thepiratebay.sx/search/" + term + "/0/99/")
if headphones.PIRATEBAY_PROXY_URL:
#Might need to clean up the user submitted url
pirate_proxy = headphones.PIRATEBAY_PROXY_URL
if not pirate_proxy.startswith('http'):
pirate_proxy = 'http://' + pirate_proxy
if pirate_proxy.endswith('/'):
pirate_proxy = pirate_proxy[:-1]
providerurl = url_fix(pirate_proxy + "/search/" + term + "/0/99/")
else:
providerurl = url_fix("http://thepiratebay.sx/search/" + term + "/0/99/")
if headphones.PREFERRED_QUALITY == 3 or losslessOnly:
category = '104' #flac
maxsize = 10000000000
@@ -1117,9 +1128,15 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
title = ''.join(item.find("a", {"class" : "detLink"}))
seeds = int(''.join(item.find("td", {"align" : "right"})))
url = item.findAll("a")[3]['href']
if headphones.TORRENT_DOWNLOADER == 0:
tor_hash = re.findall("urn:btih:(.*?)&", url)
if len(tor_hash) > 0:
url = "http://torrage.com/torrent/"+str(tor_hash[0]).upper()+".torrent"
else:
url = None
formatted_size = re.search('Size (.*),', unicode(item)).group(1).replace(u'\xa0', ' ')
size = helpers.piratesize(formatted_size)
if size < maxsize and minimumseeders < seeds:
if size < maxsize and minimumseeders < seeds and url != None:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, formatted_size))
else:
@@ -1193,6 +1210,9 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
rightformat = False
except Exception, e:
rightformat = False
for findterm in term.split(" "):
if not findterm in title:
rightformat = False
if rightformat == True and size < maxsize and minimumseeders < seeds:
resultlist.append((title, size, url, provider))
logger.info('Found %s. Size: %s' % (title, helpers.bytes_to_mb(size)))
@@ -1427,6 +1447,11 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False):
file_or_url = bestqual[2]
torrentid = transmission.addTorrent(file_or_url)
if not torrentid:
logger.error("Error sending torrent to Transmission. Are you sure it's running?")
return
torrent_folder_name = transmission.getTorrentFolder(torrentid)
logger.info('Torrent folder name: %s' % torrent_folder_name)
@@ -1449,7 +1474,7 @@ def preprocesstorrent(resultlist, pre_sorted_list=False):
for result in resultlist:
# get outta here if rutracker or piratebay
if result[3] == 'rutracker.org' or result[3] == 'The Pirate Bay':
if result[3] == 'rutracker.org':
return True, result
try:
+3 -1
View File
@@ -32,8 +32,10 @@ def addTorrent(link):
arguments = {'filename': link, 'download-dir':headphones.DOWNLOAD_TORRENT_DIR}
response = torrentAction(method,arguments)
if not response:
return False
if response['result'] == 'success':
name = response['arguments']['torrent-added']['name']
logger.info(u"Torrent sent to Transmission successfully")
+19 -4
View File
@@ -565,6 +565,9 @@ class WebInterface(object):
"http_port" : headphones.HTTP_PORT,
"http_pass" : headphones.HTTP_PASSWORD,
"launch_browser" : checked(headphones.LAUNCH_BROWSER),
"enable_https" : checked(headphones.ENABLE_HTTPS),
"https_cert" : headphones.HTTPS_CERT,
"https_key" : headphones.HTTPS_KEY,
"api_enabled" : checked(headphones.API_ENABLED),
"api_key" : headphones.API_KEY,
"download_scan_interval" : headphones.DOWNLOAD_SCAN_INTERVAL,
@@ -616,6 +619,7 @@ class WebInterface(object):
"use_isohunt" : checked(headphones.ISOHUNT),
"use_kat" : checked(headphones.KAT),
"use_piratebay" : checked(headphones.PIRATEBAY),
"piratebay_proxy_url" : headphones.PIRATEBAY_PROXY_URL,
"use_mininova" : checked(headphones.MININOVA),
"use_waffles" : checked(headphones.WAFFLES),
"waffles_uid" : headphones.WAFFLES_UID,
@@ -647,6 +651,7 @@ class WebInterface(object):
"lossless_dest_dir" : headphones.LOSSLESS_DESTINATION_DIR,
"folder_format" : headphones.FOLDER_FORMAT,
"file_format" : headphones.FILE_FORMAT,
"file_underscores" : checked(headphones.FILE_UNDERSCORES),
"include_extras" : checked(headphones.INCLUDE_EXTRAS),
"autowant_upcoming" : checked(headphones.AUTOWANT_UPCOMING),
"autowant_all" : checked(headphones.AUTOWANT_ALL),
@@ -692,7 +697,9 @@ class WebInterface(object):
"customsleep": headphones.CUSTOMSLEEP,
"hpuser": headphones.HPUSER,
"hppass": headphones.HPPASS,
"cache_sizemb":headphones.CACHE_SIZEMB,
"cache_sizemb": headphones.CACHE_SIZEMB,
"file_permissions": headphones.FILE_PERMISSIONS,
"folder_permissions": headphones.FOLDER_PERMISSIONS
}
# Need to convert EXTRAS to a dictionary we can pass to the config: it'll come in as a string like 2,5,6,8
@@ -718,21 +725,25 @@ class WebInterface(object):
utorrent_host=None, utorrent_username=None, utorrent_password=None, nzb_downloader=0, torrent_downloader=0, download_dir=None, blackhole_dir=None, usenet_retention=None,
use_headphones_indexer=0, newznab=0, newznab_host=None, newznab_apikey=None, newznab_enabled=0, nzbsorg=0, nzbsorg_uid=None, nzbsorg_hash=None, nzbsrus=0, nzbsrus_uid=None, nzbsrus_apikey=None,
preferred_words=None, required_words=None, ignored_words=None, preferred_quality=0, preferred_bitrate=None, detect_bitrate=0, move_files=0, torrentblackhole_dir=None, download_torrent_dir=None,
numberofseeders=None, use_piratebay=0, use_isohunt=0, use_kat=0, use_mininova=0, waffles=0, waffles_uid=None, waffles_passkey=None, whatcd=0, whatcd_username=None, whatcd_password=None,
numberofseeders=None, use_piratebay=0, piratebay_proxy_url=None, use_isohunt=0, use_kat=0, use_mininova=0, waffles=0, waffles_uid=None, waffles_passkey=None, whatcd=0, whatcd_username=None, whatcd_password=None,
rutracker=0, rutracker_user=None, rutracker_password=None, rename_files=0, correct_metadata=0, cleanup_files=0, add_album_art=0, album_art_format=None, embed_album_art=0, embed_lyrics=0,
destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0,
destination_dir=None, lossless_destination_dir=None, folder_format=None, file_format=None, file_underscores=0, include_extras=0, single=0, ep=0, compilation=0, soundtrack=0, live=0,
remix=0, spokenword=0, audiobook=0, autowant_upcoming=False, autowant_all=False, keep_torrent_files=False, interface=None, log_dir=None, cache_dir=None, music_encoder=0, encoder=None, xldprofile=None,
bitrate=None, samplingfrequency=None, encoderfolder=None, advancedencoder=None, encoderoutputformat=None, encodervbrcbr=None, encoderquality=None, encoderlossless=0,
delete_lossless_files=0, prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=0, xbmc_enabled=0, xbmc_host=None, xbmc_username=None, xbmc_password=None,
xbmc_update=0, xbmc_notify=0, nma_enabled=False, nma_apikey=None, nma_priority=0, nma_onsnatch=0, synoindex_enabled=False,
pushover_enabled=0, pushover_onsnatch=0, pushover_keys=None, pushover_priority=0, mirror=None, customhost=None, customport=None,
customsleep=None, hpuser=None, hppass=None, preferred_bitrate_high_buffer=None, preferred_bitrate_low_buffer=None, preferred_bitrate_allow_lossless=0, cache_sizemb=None, **kwargs):
customsleep=None, hpuser=None, hppass=None, preferred_bitrate_high_buffer=None, preferred_bitrate_low_buffer=None, preferred_bitrate_allow_lossless=0, cache_sizemb=None,
enable_https=0, https_cert=None, https_key=None, file_permissions=None, folder_permissions=None, **kwargs):
headphones.HTTP_HOST = http_host
headphones.HTTP_PORT = http_port
headphones.HTTP_USERNAME = http_username
headphones.HTTP_PASSWORD = http_password
headphones.LAUNCH_BROWSER = launch_browser
headphones.ENABLE_HTTPS = enable_https
headphones.HTTPS_CERT = https_cert
headphones.HTTPS_KEY = https_key
headphones.API_ENABLED = api_enabled
headphones.API_KEY = api_key
headphones.DOWNLOAD_SCAN_INTERVAL = download_scan_interval
@@ -778,6 +789,7 @@ class WebInterface(object):
headphones.ISOHUNT = use_isohunt
headphones.KAT = use_kat
headphones.PIRATEBAY = use_piratebay
headphones.PIRATEBAY_PROXY_URL = piratebay_proxy_url
headphones.MININOVA = use_mininova
headphones.WAFFLES = waffles
headphones.WAFFLES_UID = waffles_uid
@@ -806,6 +818,7 @@ class WebInterface(object):
headphones.LOSSLESS_DESTINATION_DIR = lossless_destination_dir
headphones.FOLDER_FORMAT = folder_format
headphones.FILE_FORMAT = file_format
headphones.FILE_UNDERSCORES = file_underscores
headphones.INCLUDE_EXTRAS = include_extras
headphones.AUTOWANT_UPCOMING = autowant_upcoming
headphones.AUTOWANT_ALL = autowant_all
@@ -851,6 +864,8 @@ class WebInterface(object):
headphones.HPUSER = hpuser
headphones.HPPASS = hppass
headphones.CACHE_SIZEMB = int(cache_sizemb)
headphones.FILE_PERMISSIONS = file_permissions
headphones.FOLDER_PERMISSIONS = folder_permissions
# Handle the variable config options. Note - keys with False values aren't getting passed
+31 -2
View File
@@ -20,12 +20,31 @@ import cherrypy
import headphones
from headphones import logger
from headphones.webserve import WebInterface
from headphones.helpers import create_https_certificates
def initialize(options={}):
#HTTPS stuff stolen from sickbeard
enable_https = options['enable_https']
https_cert = options['https_cert']
https_key = options['https_key']
cherrypy.config.update({
if enable_https:
# If either the HTTPS certificate or key do not exist, make some self-signed ones.
if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
if not create_https_certificates(https_cert, https_key):
logger.warn(u"Unable to create cert/key files, disabling HTTPS")
headphones.ENABLE_HTTPS = False
enable_https = False
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
logger.warn(u"Disabled HTTPS because of missing CERT and KEY files")
headphones.ENABLE_HTTPS = False
enable_https = False
options_dict = {
'log.screen': False,
'server.thread_pool': 10,
'server.socket_port': options['http_port'],
@@ -34,7 +53,17 @@ def initialize(options={}):
'tools.encode.on' : True,
'tools.encode.encoding' : 'utf-8',
'tools.decode.on' : True,
})
}
if enable_https:
options_dict['server.ssl_certificate'] = https_cert
options_dict['server.ssl_private_key'] = https_key
protocol = "https"
else:
protocol = "http"
logger.info(u"Starting Headphones on " + protocol + "://" + str(options['http_host']) + ":" + str(options['http_port']) + "/")
cherrypy.config.update(options_dict)
conf = {
'/': {
+82
View File
@@ -0,0 +1,82 @@
# -*- coding: latin-1 -*-
#
# Copyright (C) Martin Sjögren and AB Strakt 2001, All rights reserved
# Copyright (C) Jean-Paul Calderone 2008, All rights reserved
# This file is licenced under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1 or later (aka LGPL v2.1)
# Please see LGPL2.1.txt for more information
"""
Certificate generation module.
"""
from OpenSSL import crypto
import time
TYPE_RSA = crypto.TYPE_RSA
TYPE_DSA = crypto.TYPE_DSA
serial = int(time.time())
def createKeyPair(type, bits):
"""
Create a public/private key pair.
Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA
bits - Number of bits to use in the key
Returns: The public/private key pair in a PKey object
"""
pkey = crypto.PKey()
pkey.generate_key(type, bits)
return pkey
def createCertRequest(pkey, digest="md5", **name):
"""
Create a certificate request.
Arguments: pkey - The key to associate with the request
digest - Digestion method to use for signing, default is md5
**name - The name of the subject of the request, possible
arguments are:
C - Country name
ST - State or province name
L - Locality name
O - Organization name
OU - Organizational unit name
CN - Common name
emailAddress - E-mail address
Returns: The certificate request in an X509Req object
"""
req = crypto.X509Req()
subj = req.get_subject()
for (key,value) in name.items():
setattr(subj, key, value)
req.set_pubkey(pkey)
req.sign(pkey, digest)
return req
def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"):
"""
Generate a certificate given a certificate request.
Arguments: req - Certificate reqeust to use
issuerCert - The certificate of the issuer
issuerKey - The private key of the issuer
serial - Serial number for the certificate
notBefore - Timestamp (relative to now) when the certificate
starts being valid
notAfter - Timestamp (relative to now) when the certificate
stops being valid
digest - Digest method to use for signing, default is md5
Returns: The signed certificate in an X509 object
"""
cert = crypto.X509()
cert.set_serial_number(serial)
cert.gmtime_adj_notBefore(notBefore)
cert.gmtime_adj_notAfter(notAfter)
cert.set_issuer(issuerCert.get_subject())
cert.set_subject(req.get_subject())
cert.set_pubkey(req.get_pubkey())
cert.sign(issuerKey, digest)
return cert