From 54f2ba3b3bc0680d65f57191910db543bd3cb162 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Mon, 8 Jul 2013 10:41:10 +0530 Subject: [PATCH 01/15] initial changes to get transmission working: added torrent_downloader option (blackhole/transmission), updated config page --- data/interfaces/default/config.html | 57 ++++++++++++++++++++++------- headphones/__init__.py | 7 +++- headphones/webserve.py | 6 ++- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 3e0641a6..5dda08e5 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -177,20 +177,32 @@
Torrents -
- - - Folder your Download program watches for Torrents -
+ Black Hole Transmission +
+
+
+ + + Folder your Download program watches for Torrents +
+
+
+
+ + + Transmission Host +
+
+ +
+ + + Number of minimum seeders a torrent must have to be accepted +
- - - Number of minimum seeders a torrent must have to be accepted -
-
- - - Full path where your torrent client downloads your music e.g. /Users/name/Downloads/music + + + Full path where your torrent client downloads your music e.g. /Users/name/Downloads/music
@@ -1054,6 +1066,17 @@ $("#sabnzbd_options,#nzbget_options").hide(); $("#blackhole_options").show(); } + + if ($("#torrent_downloader_blackhole").is(":checked")) + { + $("#transmission_options").hide(); + $("#torrent_blackhole_options").show(); + } + if ($("#torrent_downloader_transmission").is(":checked")) + { + $("#torrent_blackhole_options").hide(); + $("#transmission_options").show(); + } $('input[type=radio]').change(function(){ if ($("#preferred_bitrate").is(":checked")) @@ -1084,6 +1107,14 @@ { $("#sabnzbd_options,#nzbget_options").fadeOut("fast", function() { $("#blackhole_options").fadeIn() }); } + if ($("#torrent_downloader_blackhole").is(":checked")) + { + $("#transmission_options").fadeOut("fast", function() { $("#torrent_blackhole_options").fadeIn() }); + } + if ($("#torrent_downloader_transmission").is(":checked")) + { + $("#torrent_blackhole_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() }); + } }); $("#mirror").change(handleNewServerSelection); diff --git a/headphones/__init__.py b/headphones/__init__.py index 965c5e1b..ab3451b0 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -109,7 +109,8 @@ ADD_ALBUM_ART = False ALBUM_ART_FORMAT = None EMBED_ALBUM_ART = False EMBED_LYRICS = False -NZB_DOWNLOADER = None +NZB_DOWNLOADER = None # 0: sabnzbd, 1: nzbget, 2: blackhole +TORRENT_DOWNLOADER = None # 0: blackhole, 1: transmission DOWNLOAD_DIR = None BLACKHOLE = None BLACKHOLE_DIR = None @@ -295,7 +296,7 @@ def initialize(): LIBRARYSCAN, LIBRARYSCAN_INTERVAL, DOWNLOAD_SCAN_INTERVAL, SAB_HOST, SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, \ NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, \ NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, NZBX, \ - NZB_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \ + NZB_DOWNLOADER, TORRENT_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \ LASTFM_USERNAME, INTERFACE, FOLDER_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, \ @@ -377,6 +378,7 @@ def initialize(): EMBED_ALBUM_ART = bool(check_setting_int(CFG, 'General', 'embed_album_art', 0)) EMBED_LYRICS = bool(check_setting_int(CFG, 'General', 'embed_lyrics', 0)) NZB_DOWNLOADER = check_setting_int(CFG, 'General', 'nzb_downloader', 0) + TORRENT_DOWNLOADER = check_setting_int(CFG, 'General', 'torrent_downloader', 0) DOWNLOAD_DIR = check_setting_str(CFG, 'General', 'download_dir', '') BLACKHOLE = bool(check_setting_int(CFG, 'General', 'blackhole', 0)) BLACKHOLE_DIR = check_setting_str(CFG, 'General', 'blackhole_dir', '') @@ -721,6 +723,7 @@ def config_write(): new_config['General']['embed_album_art'] = int(EMBED_ALBUM_ART) new_config['General']['embed_lyrics'] = int(EMBED_LYRICS) new_config['General']['nzb_downloader'] = NZB_DOWNLOADER + new_config['General']['torrent_downloader'] = TORRENT_DOWNLOADER new_config['General']['download_dir'] = DOWNLOAD_DIR new_config['General']['blackhole_dir'] = BLACKHOLE_DIR new_config['General']['usenet_retention'] = USENET_RETENTION diff --git a/headphones/webserve.py b/headphones/webserve.py index 1f8167ab..b7519aec 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -582,6 +582,8 @@ class WebInterface(object): "nzb_downloader_sabnzbd" : radio(headphones.NZB_DOWNLOADER, 0), "nzb_downloader_nzbget" : radio(headphones.NZB_DOWNLOADER, 1), "nzb_downloader_blackhole" : radio(headphones.NZB_DOWNLOADER, 2), + "torrent_downloader_blackhole" : radio(headphones.TORRENT_DOWNLOADER, 0), + "torrent_downloader_transmission" : radio(headphones.TORRENT_DOWNLOADER, 1), "download_dir" : headphones.DOWNLOAD_DIR, "use_blackhole" : checked(headphones.BLACKHOLE), "blackhole_dir" : headphones.BLACKHOLE_DIR, @@ -705,7 +707,8 @@ class WebInterface(object): def configUpdate(self, http_host='0.0.0.0', http_username=None, http_port=8181, http_password=None, launch_browser=0, api_enabled=0, api_key=None, download_scan_interval=None, nzb_search_interval=None, libraryscan_interval=None, sab_host=None, sab_username=None, sab_apikey=None, sab_password=None, - sab_category=None, nzbget_host=None, nzbget_username='nzbget', nzbget_password=None, nzbget_category=None, nzb_downloader=0, download_dir=None, blackhole=0, blackhole_dir=None, usenet_retention=None, newznab=0, newznab_host=None, newznab_apikey=None, + sab_category=None, nzbget_host=None, nzbget_username='nzbget', nzbget_password=None, nzbget_category=None, nzb_downloader=0, torrent_downloader=0, + download_dir=None, blackhole=0, blackhole_dir=None, usenet_retention=None, 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, nzbx=0, 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=10, 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, @@ -738,6 +741,7 @@ class WebInterface(object): headphones.NZBGET_PASSWORD = nzbget_password headphones.NZBGET_CATEGORY = nzbget_category headphones.NZB_DOWNLOADER = int(nzb_downloader) + headphones.TORRENT_DOWNLOADER = int(torrent_downloader) headphones.DOWNLOAD_DIR = download_dir headphones.BLACKHOLE = blackhole headphones.BLACKHOLE_DIR = blackhole_dir From a55f60768854efe412b66d9653203f91ecef1638 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Tue, 9 Jul 2013 19:13:43 +0530 Subject: [PATCH 02/15] Add utorrent support while we're at it (initial changes) --- data/interfaces/default/config.html | 27 +++++++++++++++++++++------ headphones/__init__.py | 2 +- headphones/webserve.py | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 5dda08e5..94037a0a 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -177,7 +177,7 @@
Torrents - Black Hole Transmission + Black Hole Transmission uTorrent
@@ -193,7 +193,13 @@ Transmission Host
- +
+
+ + + Utorrent Host +
+
@@ -1069,14 +1075,19 @@ if ($("#torrent_downloader_blackhole").is(":checked")) { - $("#transmission_options").hide(); + $("#transmission_options,#utorrent_options").hide(); $("#torrent_blackhole_options").show(); } if ($("#torrent_downloader_transmission").is(":checked")) { - $("#torrent_blackhole_options").hide(); + $("#torrent_blackhole_options,#utorrent_options").hide(); $("#transmission_options").show(); } + if ($("#torrent_downloader_utorrent").is(":checked")) + { + $("#torrent_blackhole_options,#transmission_options").hide(); + $("#utorrent_options").show(); + } $('input[type=radio]').change(function(){ if ($("#preferred_bitrate").is(":checked")) @@ -1109,11 +1120,15 @@ } if ($("#torrent_downloader_blackhole").is(":checked")) { - $("#transmission_options").fadeOut("fast", function() { $("#torrent_blackhole_options").fadeIn() }); + $("#transmission_options,#utorrent_options").fadeOut("fast", function() { $("#torrent_blackhole_options").fadeIn() }); } if ($("#torrent_downloader_transmission").is(":checked")) { - $("#torrent_blackhole_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() }); + $("#torrent_blackhole_options,#utorrent_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() }); + } + if ($("#torrent_downloader_utorrent").is(":checked")) + { + $("#torrent_blackhole_options,#transmission_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() }); } }); diff --git a/headphones/__init__.py b/headphones/__init__.py index ab3451b0..e28ecfbb 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -110,7 +110,7 @@ ALBUM_ART_FORMAT = None EMBED_ALBUM_ART = False EMBED_LYRICS = False NZB_DOWNLOADER = None # 0: sabnzbd, 1: nzbget, 2: blackhole -TORRENT_DOWNLOADER = None # 0: blackhole, 1: transmission +TORRENT_DOWNLOADER = None # 0: blackhole, 1: transmission, 2: utorrent DOWNLOAD_DIR = None BLACKHOLE = None BLACKHOLE_DIR = None diff --git a/headphones/webserve.py b/headphones/webserve.py index b7519aec..082c73bd 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -584,6 +584,7 @@ class WebInterface(object): "nzb_downloader_blackhole" : radio(headphones.NZB_DOWNLOADER, 2), "torrent_downloader_blackhole" : radio(headphones.TORRENT_DOWNLOADER, 0), "torrent_downloader_transmission" : radio(headphones.TORRENT_DOWNLOADER, 1), + "torrent_downloader_utorrent" : radio(headphones.TORRENT_DOWNLOADER, 2), "download_dir" : headphones.DOWNLOAD_DIR, "use_blackhole" : checked(headphones.BLACKHOLE), "blackhole_dir" : headphones.BLACKHOLE_DIR, From e5d1162589bd71b37d358a61f214e747df389972 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 10 Jul 2013 08:53:23 +0530 Subject: [PATCH 03/15] Added uTorrent and Transmission options to init.py, got rid of old nzbmatrix & newzbin stuff --- data/interfaces/default/config.html | 39 +++++++++---------- headphones/__init__.py | 59 +++++++++++++++-------------- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 94037a0a..3b8df313 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -162,17 +162,17 @@
-
+
Full path where SAB or NZBget downloads your music. e.g. /Users/name/Downloads/music
-
-
+
-
+
+
@@ -200,21 +200,22 @@ Utorrent Host
-
- - - Number of minimum seeders a torrent must have to be accepted -
-
- - - Full path where your torrent client downloads your music e.g. /Users/name/Downloads/music -
-
- - -
- +
+
+ + + Number of minimum seeders a torrent must have to be accepted +
+
+ + + Full path where your torrent client downloads your music e.g. /Users/name/Downloads/music +
+
+ + +
+
diff --git a/headphones/__init__.py b/headphones/__init__.py index e28ecfbb..108248f3 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -137,9 +137,13 @@ NZBGET_PASSWORD = None NZBGET_CATEGORY = None NZBGET_HOST = None -NZBMATRIX = False -NZBMATRIX_USERNAME = None -NZBMATRIX_APIKEY = None +TRANSMISSION_HOST = None +TRANSMISSION_USERNAME = None +TRANSMISSION_PASSWORD = None + +UTORRENT_HOST = None +UTORRENT_USERNAME = None +UTORRENT_PASSWORD = None NEWZNAB = False NEWZNAB_HOST = None @@ -151,10 +155,6 @@ NZBSORG = False NZBSORG_UID = None NZBSORG_HASH = None -NEWZBIN = False -NEWZBIN_UID = None -NEWZBIN_PASSWORD = None - NZBSRUS = False NZBSRUS_UID = None NZBSRUS_APIKEY = None @@ -294,8 +294,9 @@ def initialize(): TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, 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, NZBMATRIX, NZBMATRIX_USERNAME, NZBMATRIX_APIKEY, NEWZNAB, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_ENABLED, EXTRA_NEWZNABS, \ - NZBSORG, NZBSORG_UID, NZBSORG_HASH, NEWZBIN, NEWZBIN_UID, NEWZBIN_PASSWORD, NZBSRUS, NZBSRUS_UID, NZBSRUS_APIKEY, NZBX, \ + NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, 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, NZBX, \ NZB_DOWNLOADER, TORRENT_DOWNLOADER, PREFERRED_WORDS, REQUIRED_WORDS, IGNORED_WORDS, \ LASTFM_USERNAME, INTERFACE, FOLDER_PERMISSIONS, ENCODERFOLDER, ENCODER_PATH, ENCODER, XLDPROFILE, BITRATE, SAMPLINGFREQUENCY, \ MUSIC_ENCODER, ADVANCEDENCODER, ENCODEROUTPUTFORMAT, ENCODERQUALITY, ENCODERVBRCBR, ENCODERLOSSLESS, DELETE_LOSSLESS_FILES, \ @@ -312,12 +313,12 @@ def initialize(): CheckSection('General') CheckSection('SABnzbd') CheckSection('NZBget') - CheckSection('NZBMatrix') + CheckSection('Transmission') + CheckSection('uTorrent') CheckSection('Newznab') CheckSection('NZBsorg') CheckSection('NZBsRus') CheckSection('nzbX') - CheckSection('Newzbin') CheckSection('Waffles') CheckSection('Rutracker') CheckSection('What.cd') @@ -423,10 +424,14 @@ def initialize(): NZBGET_PASSWORD = check_setting_str(CFG, 'NZBget', 'nzbget_password', '') NZBGET_CATEGORY = check_setting_str(CFG, 'NZBget', 'nzbget_category', '') NZBGET_HOST = check_setting_str(CFG, 'NZBget', 'nzbget_host', '') - - 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', '') + + TRANSMISSION_HOST = check_setting_str(CFG, 'Transmission', 'transmission_host', '') + TRANSMISSION_USERNAME = check_setting_str(CFG, 'Transmission', 'transmission_username', '') + TRANSMISSION_PASSWORD = check_setting_str(CFG, 'Transmission', 'transmission_password', '') + + UTORRENT_HOST = check_setting_str(CFG, 'uTorrent', 'utorrent_host', '') + UTORRENT_USERNAME = check_setting_str(CFG, 'uTorrent', 'utorrent_username', '') + UTORRENT_PASSWORD = check_setting_str(CFG, 'uTorrent', 'utorrent_password', '') NEWZNAB = bool(check_setting_int(CFG, 'Newznab', 'newznab', 0)) NEWZNAB_HOST = check_setting_str(CFG, 'Newznab', 'newznab_host', '') @@ -441,10 +446,6 @@ def initialize(): NZBSORG_UID = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_uid', '') NZBSORG_HASH = check_setting_str(CFG, 'NZBsorg', 'nzbsorg_hash', '') - 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', '') @@ -772,11 +773,16 @@ def config_write(): new_config['NZBget']['nzbget_password'] = NZBGET_PASSWORD new_config['NZBget']['nzbget_category'] = NZBGET_CATEGORY new_config['NZBget']['nzbget_host'] = NZBGET_HOST - - new_config['NZBMatrix'] = {} - new_config['NZBMatrix']['nzbmatrix'] = int(NZBMATRIX) - new_config['NZBMatrix']['nzbmatrix_username'] = NZBMATRIX_USERNAME - new_config['NZBMatrix']['nzbmatrix_apikey'] = NZBMATRIX_APIKEY + + new_config['Transmission'] = {} + new_config['Transmission']['transmission_host'] = TRANSMISSION_HOST + new_config['Transmission']['transmission_username'] = TRANSMISSION_USERNAME + new_config['Transmission']['transmission_password'] = TRANSMISSION_PASSWORD + + new_config['uTorrent'] = {} + new_config['uTorrent']['utorrent_host'] = UTORRENT_HOST + new_config['uTorrent']['utorrent_username'] = UTORRENT_USERNAME + new_config['uTorrent']['utorrent_password'] = UTORRENT_PASSWORD new_config['Newznab'] = {} new_config['Newznab']['newznab'] = int(NEWZNAB) @@ -796,11 +802,6 @@ def config_write(): 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 From 109d5f996f22fd74d52f3622b3a693c19b4e6cbc Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 10 Jul 2013 09:03:56 +0530 Subject: [PATCH 04/15] Added Transmission & uTorrent options to config page --- data/interfaces/default/config.html | 38 ++++++++++++++++++++--------- headphones/webserve.py | 20 ++++++++++++--- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 3b8df313..9386cf59 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -162,7 +162,7 @@ -
+
@@ -187,18 +187,34 @@
-
- - - Transmission Host -
+
+ + + usually http://localhost:9091 +
+
+ + +
+
+ + +
-
- - - Utorrent Host -
+
+ + + usually http://localhost:9091 +
+
+ + +
+
+ + +
diff --git a/headphones/webserve.py b/headphones/webserve.py index 082c73bd..0b5e395b 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -579,6 +579,12 @@ class WebInterface(object): "nzbget_user" : headphones.NZBGET_USERNAME, "nzbget_pass" : headphones.NZBGET_PASSWORD, "nzbget_cat" : headphones.NZBGET_CATEGORY, + "transmission_host" : headphones.TRANSMISSION_HOST, + "transmission_user" : headphones.TRANSMISSION_USERNAME, + "transmission_pass" : headphones.TRANSMISSION_PASSWORD, + "utorrent_host" : headphones.UTORRENT_HOST, + "utorrent_user" : headphones.UTORRENT_USERNAME, + "utorrent_pass" : headphones.UTORRENT_PASSWORD, "nzb_downloader_sabnzbd" : radio(headphones.NZB_DOWNLOADER, 0), "nzb_downloader_nzbget" : radio(headphones.NZB_DOWNLOADER, 1), "nzb_downloader_blackhole" : radio(headphones.NZB_DOWNLOADER, 2), @@ -708,10 +714,10 @@ class WebInterface(object): def configUpdate(self, http_host='0.0.0.0', http_username=None, http_port=8181, http_password=None, launch_browser=0, api_enabled=0, api_key=None, download_scan_interval=None, nzb_search_interval=None, libraryscan_interval=None, sab_host=None, sab_username=None, sab_apikey=None, sab_password=None, - sab_category=None, nzbget_host=None, nzbget_username='nzbget', nzbget_password=None, nzbget_category=None, nzb_downloader=0, torrent_downloader=0, - download_dir=None, blackhole=0, blackhole_dir=None, usenet_retention=None, 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, nzbx=0, 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, + sab_category=None, nzbget_host=None, nzbget_username=None, nzbget_password=None, nzbget_category=None, transmission_host=None, transmission_username=None, transmission_password=None, + utorrent_host=None, utorrent_username=None, utorrent_password=None, nzb_downloader=0, torrent_downloader=0, download_dir=None, blackhole=0, blackhole_dir=None, + usenet_retention=None, 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, nzbx=0, 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=10, 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, @@ -741,6 +747,12 @@ class WebInterface(object): headphones.NZBGET_USERNAME = nzbget_username headphones.NZBGET_PASSWORD = nzbget_password headphones.NZBGET_CATEGORY = nzbget_category + headphones.TRANSMISSION_HOST = transmission_host + headphones.TRANSMISSION_USERNAME = transmission_username + headphones.TRANSMISSION_PASSWORD = transmission_password + headphones.UTORRENT_HOST = utorrent_host + headphones.UTORRENT_USERNAME = utorrent_username + headphones.UTORRENT_PASSWORD = utorrent_password headphones.NZB_DOWNLOADER = int(nzb_downloader) headphones.TORRENT_DOWNLOADER = int(torrent_downloader) headphones.DOWNLOAD_DIR = download_dir From b4735d3641b47669780db74fedfac75965df9d93 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 17 Jul 2013 21:02:24 +0530 Subject: [PATCH 05/15] Added utorrent & transmission py files --- headphones/transmission.py | 16 ++++++++++++++++ headphones/utorrent.py | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 headphones/transmission.py create mode 100644 headphones/utorrent.py diff --git a/headphones/transmission.py b/headphones/transmission.py new file mode 100644 index 00000000..e3b93d4e --- /dev/null +++ b/headphones/transmission.py @@ -0,0 +1,16 @@ +# This file is part of Headphones. +# +# Headphones is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Headphones is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Headphones. If not, see . + + diff --git a/headphones/utorrent.py b/headphones/utorrent.py new file mode 100644 index 00000000..e3b93d4e --- /dev/null +++ b/headphones/utorrent.py @@ -0,0 +1,16 @@ +# This file is part of Headphones. +# +# Headphones is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Headphones is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Headphones. If not, see . + + From 12cd433d00edba37a65f7b88d89bbe8b5b3bd58a Mon Sep 17 00:00:00 2001 From: rembo10 Date: Thu, 18 Jul 2013 23:42:12 +0530 Subject: [PATCH 06/15] Fixed issue (possible #1152) where postprocessor would hang when forced and the folder didn't exist --- headphones/postprocessor.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index fd54f17f..5be3a0b0 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -860,6 +860,9 @@ def forcePostProcess(): # Get a list of folders in the download_dir folders = [] for download_dir in download_dirs: + if not os.path.isdir(download_dir): + logger.warn('Directory ' + download_dir.decode(headphones.SYS_ENCODING, 'replace') + ' does not exist. Skipping') + continue for folder in os.listdir(download_dir): path_to_folder = os.path.join(download_dir, folder) if os.path.isdir(path_to_folder): From b9039df49280e87fcfe2a47c3c4fc2cf6b2d1481 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Sun, 21 Jul 2013 14:06:06 +0530 Subject: [PATCH 07/15] Quiet the scanning warning message if no dir is set --- headphones/librarysync.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/headphones/librarysync.py b/headphones/librarysync.py index 05ff49a0..5ee57d8b 100644 --- a/headphones/librarysync.py +++ b/headphones/librarysync.py @@ -28,7 +28,10 @@ def libraryScan(dir=None, append=False, ArtistID=None, ArtistName=None, cron=Fal return if not dir: - dir = headphones.MUSIC_DIR + if not headphones.MUSIC_DIR: + return + else: + dir = headphones.MUSIC_DIR # If we're appending a dir, it's coming from the post processor which is # already bytestring From e3450e15fb152e2cd7d766073ca5e77a30e7835b Mon Sep 17 00:00:00 2001 From: rembo10 Date: Tue, 23 Jul 2013 11:17:45 +0530 Subject: [PATCH 08/15] Fixed target bitrate sort for torrents --- headphones/searcher.py | 59 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 8ec70247..5f9a0f1a 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1198,7 +1198,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): if len(resultlist): - if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE and not pre_sorted_results: + if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: logger.debug('Target bitrate: %s kbps' % headphones.PREFERRED_BITRATE) @@ -1208,26 +1208,55 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): albumlength = sum([pair[0] for pair in tracks]) targetsize = albumlength/1000 * int(headphones.PREFERRED_BITRATE) * 128 - logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize)) - - newlist = [] - - for result in resultlist: - delta = abs(targetsize - result[1]) - newlist.append((result[0], result[1], result[2], result[3], delta)) - - torrentlist = sorted(newlist, key=lambda title: title[4]) + + if not targetsize: + logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) + nzblist = sorted(resultlist, key=lambda title: (-title[4] , -title[1])) + + else: + logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize)) + newlist = [] + flac_list = [] + + if headphones.PREFERRED_BITRATE_HIGH_BUFFER: + high_size_limit = targetsize * int(headphones.PREFERRED_BITRATE_HIGH_BUFFER)/100 + else: + high_size_limit = None + if headphones.PREFERRED_BITRATE_LOW_BUFFER: + low_size_limit = targetsize * int(headphones.PREFERRED_BITRATE_LOW_BUFFER)/100 + else: + low_size_limit = None + + for result in resultlist: + + if high_size_limit and (result[1] > high_size_limit): + logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit)) + + # Add lossless nzbs to the "flac list" which we can use if there are no good lossy matches + if 'flac' in result[0].lower(): + flac_list.append((result[0], result[1], result[2], result[3], result[4])) + + continue + + if low_size_limit and (result[1] < low_size_limit): + logger.info(result[0] + " is too small for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Minsize: " + helpers.bytes_to_mb(low_size_limit)) + continue + + delta = abs(targetsize - result[1]) + newlist.append((result[0], result[1], result[2], result[3], result[4], delta)) + + nzblist = sorted(newlist, key=lambda title: (-title[4], title[5])) + + if not len(nzblist) and len(flac_list) and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + logger.info("Since there were no appropriate lossy matches (and at least one lossless match), going to use lossless instead") + nzblist = sorted(flac_list, key=lambda title: (-title[4], -title[1])) except Exception, e: logger.debug('Error: %s' % str(e)) logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) - torrentlist = sorted(resultlist, key=lambda title: title[1], reverse=True) - - elif pre_sorted_results: - - torrentlist = resultlist + nzblist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) else: From f7b78d5a067fdbe5ba715cdb32449a786b17b2e8 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Tue, 23 Jul 2013 11:37:30 +0530 Subject: [PATCH 09/15] Added preferred words priority for torrents and fixed some variables --- headphones/searcher.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 5f9a0f1a..17e1083a 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1196,7 +1196,17 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): if len(resultlist): resultlist[:] = [result for result in resultlist if verifyresult(result[0], artistterm, term, losslessOnly)] - if len(resultlist): + if len(resultlist): + + # Add a priority if it has any of the preferred words + temp_list = [] + for result in resultlist: + if any(word.lower() in result[0].lower() for word in helpers.split_string(headphones.PREFERRED_WORDS)): + temp_list.append((result[0],result[1],result[2],result[3],1)) + else: + temp_list.append((result[0],result[1],result[2],result[3],0)) + + resultlist = temp_list if headphones.PREFERRED_QUALITY == 2 and headphones.PREFERRED_BITRATE: @@ -1211,7 +1221,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): if not targetsize: logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) - nzblist = sorted(resultlist, key=lambda title: (-title[4] , -title[1])) + torrentlist = sorted(resultlist, key=lambda title: (-title[4] , -title[1])) else: logger.info('Target size: %s' % helpers.bytes_to_mb(targetsize)) @@ -1245,22 +1255,22 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): delta = abs(targetsize - result[1]) newlist.append((result[0], result[1], result[2], result[3], result[4], delta)) - nzblist = sorted(newlist, key=lambda title: (-title[4], title[5])) + torrentlist = sorted(newlist, key=lambda title: (-title[4], title[5])) if not len(nzblist) and len(flac_list) and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: logger.info("Since there were no appropriate lossy matches (and at least one lossless match), going to use lossless instead") - nzblist = sorted(flac_list, key=lambda title: (-title[4], -title[1])) + torrentlist = sorted(flac_list, key=lambda title: (-title[4], -title[1])) except Exception, e: logger.debug('Error: %s' % str(e)) logger.info('No track information for %s - %s. Defaulting to highest quality' % (albums[0], albums[1])) - nzblist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) + torrentlist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) else: - torrentlist = sorted(resultlist, key=lambda title: title[1], reverse=True) + torrentlist = sorted(resultlist, key=lambda title: (-title[4], -title[1])) if new: From 041afea7c6b4bef69792f376c5915ba019eb3e42 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Tue, 23 Jul 2013 21:02:38 +0530 Subject: [PATCH 10/15] Added Pirate Bay support --- data/interfaces/default/config.html | 6 ++- headphones/__init__.py | 5 ++- headphones/helpers.py | 17 ++++++++ headphones/searcher.py | 68 ++++++++++++++++++++++++++--- headphones/webserve.py | 4 +- 5 files changed, 90 insertions(+), 10 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 9386cf59..48db074c 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -336,6 +336,9 @@
Torrents +
+ +
@@ -343,7 +346,8 @@
-
+ +
diff --git a/headphones/__init__.py b/headphones/__init__.py index 108248f3..1db6745a 100644 --- a/headphones/__init__.py +++ b/headphones/__init__.py @@ -178,6 +178,7 @@ NUMBEROFSEEDERS = 10 ISOHUNT = None KAT = None MININOVA = None +PIRATEBAY = None WAFFLES = None WAFFLES_UID = None WAFFLES_PASSKEY = None @@ -291,7 +292,7 @@ def initialize(): 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, \ 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, MININOVA, WAFFLES, WAFFLES_UID, WAFFLES_PASSKEY, \ + TORRENTBLACKHOLE_DIR, NUMBEROFSEEDERS, ISOHUNT, KAT, PIRATEBAY, 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, TRANSMISSION_HOST, TRANSMISSION_USERNAME, TRANSMISSION_PASSWORD, \ @@ -399,6 +400,7 @@ def initialize(): NUMBEROFSEEDERS = check_setting_str(CFG, 'General', 'numberofseeders', '10') 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)) MININOVA = bool(check_setting_int(CFG, 'General', 'mininova', 0)) DOWNLOAD_TORRENT_DIR = check_setting_str(CFG, 'General', 'download_torrent_dir', '') @@ -739,6 +741,7 @@ def config_write(): new_config['General']['isohunt'] = int(ISOHUNT) new_config['General']['kat'] = int(KAT) new_config['General']['mininova'] = int(MININOVA) + new_config['General']['piratebay'] = int(PIRATEBAY) new_config['General']['download_torrent_dir'] = DOWNLOAD_TORRENT_DIR new_config['Waffles'] = {} diff --git a/headphones/helpers.py b/headphones/helpers.py index c35e6a53..19c98b7e 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -142,6 +142,23 @@ def mb_to_bytes(mb_str): result = re.search('^(\d+(?:\.\d+)?)\s?(?:mb)?', mb_str, flags=re.I) if result: return int(float(result.group(1))*1048576) + +def piratesize(size): + split = size.split(" ") + factor = float(split[0]) + unit = split[1] + if unit == 'MiB': + size = factor * 1048576 + elif unit == 'GiB': + size = factor * 1073741824 + elif unit == 'KiB': + size = factor * 1024 + elif unit == "B": + size = factor + else: + size = 0 + + return size def replace_all(text, dic): diff --git a/headphones/searcher.py b/headphones/searcher.py index 17e1083a..f8304538 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -17,6 +17,7 @@ import urllib, urllib2, urlparse, httplib import lib.feedparser as feedparser +from bs4 import BeautifulSoup from lib.pygazelle import api as gazelleapi from lib.pygazelle import encoding as gazelleencoding from lib.pygazelle import format as gazelleformat @@ -117,7 +118,7 @@ def searchforalbum(albumid=None, new=False, lossless=False): else: foundNZB = searchNZB(result['AlbumID'], new) - if (headphones.KAT or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) and foundNZB == "none": + if (headphones.KAT or headphones.PIRATEBAY or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) and foundNZB == "none": if result['Status'] == "Wanted Lossless": searchTorrent(result['AlbumID'], new, losslessOnly=True) @@ -127,10 +128,10 @@ def searchforalbum(albumid=None, new=False, lossless=False): else: foundNZB = "none" - if (headphones.NZBMATRIX or headphones.NEWZNAB or headphones.NZBSORG or headphones.NEWZBIN or headphones.NZBX or headphones.NZBSRUS) and (headphones.SAB_HOST or headphones.BLACKHOLE_DIR or headphones.NZBGET_HOST): + if (headphones.NEWZNAB or headphones.NZBSORG or headphones.NZBX or headphones.NZBSRUS) and (headphones.SAB_HOST or headphones.BLACKHOLE_DIR or headphones.NZBGET_HOST): foundNZB = searchNZB(albumid, new, lossless) - if (headphones.KAT or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) and foundNZB == "none": + if (headphones.KAT or headphones.PIRATEBAY or headphones.ISOHUNT or headphones.MININOVA or headphones.WAFFLES or headphones.RUTRACKER or headphones.WHATCD) and foundNZB == "none": searchTorrent(albumid, new, lossless) def searchNZB(albumid=None, new=False, losslessOnly=False): @@ -1045,6 +1046,58 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): gazelle.generate_torrent_link(torrent.id), provider)) + # Pirate Bay + if headphones.PIRATEBAY and headphones.TORRENT_DOWNLOADER != 0: + provider = "The Pirate Bay" + providerurl = url_fix("http://thepiratebay.sx/search/" + term + "/0/99/") + if headphones.PREFERRED_QUALITY == 3 or losslessOnly: + category = '104' #flac + maxsize = 10000000000 + elif headphones.PREFERRED_QUALITY: + category = '100' #audio cat + maxsize = 10000000000 + else: + category = '101' #mp3 + maxsize = 300000000 + + searchURL = providerurl + category + + try: + data = urllib2.urlopen(searchURL, timeout=20).read() + except urllib2.URLError, e: + logger.warn('Error fetching data from The Pirate Bay: %s' % e) + data = False + + if data: + + logger.info(u'Parsing results from The Pirate Bay' % searchURL) + + soup = BeautifulSoup(data) + table = soup.find('table') + rows = table.findAll('tr') + + if len(rows) == '1': + logger.info(u"No results found from %s for %s" % (provider, term)) + pass + + else: + for item in rows[1:]: + try: + rightformat = True + title = ''.join(item.find("a", {"class" : "detLink"})) + seeds = int(''.join(item.find("td", {"align" : "right"}))) + url = item.findAll("a")[3]['href'] + formatted_size = re.search('Size (.*),', unicode(item)).group(1).replace(u'\xa0', ' ') + size = helpers.piratesize(formatted_size) + if size < maxsize and minimumseeders < seeds: + resultlist.append((title, size, url, provider)) + logger.info('Found %s. Size: %s' % (title, formatted_size)) + else: + logger.info('%s is larger than the maxsize or has too little seeders for this category, skipping. (Size: %i bytes, Seeders: %i)' % (title, size, int(seeds))) + + except Exception, e: + logger.error(u"An unknown error occurred in the Pirate Bay parser: %s" % e) + if headphones.ISOHUNT: provider = "isoHunt" providerurl = url_fix("http://isohunt.com/js/rss/" + term) @@ -1295,6 +1348,8 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): (data, bestqual) = preprocesstorrent(torrentlist, pre_sorted_results) + logger.info(u"Made it out") + if data and bestqual: logger.info(u'Found best result from %s: %s - %s' % (bestqual[3], bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1]))) torrent_folder_name = '%s - %s [%s]' % (helpers.latinToAscii(albums[0]).encode('UTF-8').replace('/', '_'), helpers.latinToAscii(albums[1]).encode('UTF-8').replace('/', '_'), year) @@ -1345,10 +1400,9 @@ def preprocesstorrent(resultlist, pre_sorted_list=False): selresult = result elif int(selresult[1]) < int(result[1]): # if size is lower than new result replace previous selected result (bigger size = better quality?) selresult = result - - # get outta here if rutracker - - if selresult[3] == 'rutracker.org': + + # get outta here if rutracker or piratebay + if selresult[3] == 'rutracker.org' or selresult[3] == 'The Pirate Bay': return True, selresult if pre_sorted_list: diff --git a/headphones/webserve.py b/headphones/webserve.py index 0b5e395b..c90157e4 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -615,6 +615,7 @@ class WebInterface(object): "numberofseeders" : headphones.NUMBEROFSEEDERS, "use_isohunt" : checked(headphones.ISOHUNT), "use_kat" : checked(headphones.KAT), + "use_piratebay" : checked(headphones.PIRATEBAY), "use_mininova" : checked(headphones.MININOVA), "use_waffles" : checked(headphones.WAFFLES), "waffles_uid" : headphones.WAFFLES_UID, @@ -718,7 +719,7 @@ class WebInterface(object): utorrent_host=None, utorrent_username=None, utorrent_password=None, nzb_downloader=0, torrent_downloader=0, download_dir=None, blackhole=0, blackhole_dir=None, usenet_retention=None, 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, nzbx=0, 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=10, 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=10, use_isohunt=0, use_kat=0, use_piratebay=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, 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, @@ -778,6 +779,7 @@ class WebInterface(object): headphones.DOWNLOAD_TORRENT_DIR = download_torrent_dir headphones.ISOHUNT = use_isohunt headphones.KAT = use_kat + headphones.PIRATEBAY = use_piratebay headphones.MININOVA = use_mininova headphones.WAFFLES = waffles headphones.WAFFLES_UID = waffles_uid From 0f6dbccaa3af4540b7ad29de7d3601592c447cde Mon Sep 17 00:00:00 2001 From: rembo10 Date: Wed, 24 Jul 2013 11:01:15 +0530 Subject: [PATCH 11/15] Fixed some typos, got rid of test log message --- headphones/searcher.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index f8304538..6efbc0be 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1293,7 +1293,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): for result in resultlist: if high_size_limit and (result[1] > high_size_limit): - logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit)) + logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit) + ")") # Add lossless nzbs to the "flac list" which we can use if there are no good lossy matches if 'flac' in result[0].lower(): @@ -1302,7 +1302,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): continue if low_size_limit and (result[1] < low_size_limit): - logger.info(result[0] + " is too small for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Minsize: " + helpers.bytes_to_mb(low_size_limit)) + logger.info(result[0] + " is too small for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Minsize: " + helpers.bytes_to_mb(low_size_limit) + ")") continue delta = abs(targetsize - result[1]) @@ -1310,7 +1310,7 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): torrentlist = sorted(newlist, key=lambda title: (-title[4], title[5])) - if not len(nzblist) and len(flac_list) and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: + if not len(torrentlist) and len(flac_list) and headphones.PREFERRED_BITRATE_ALLOW_LOSSLESS: logger.info("Since there were no appropriate lossy matches (and at least one lossless match), going to use lossless instead") torrentlist = sorted(flac_list, key=lambda title: (-title[4], -title[1])) @@ -1348,8 +1348,6 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): (data, bestqual) = preprocesstorrent(torrentlist, pre_sorted_results) - logger.info(u"Made it out") - if data and bestqual: logger.info(u'Found best result from %s: %s - %s' % (bestqual[3], bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1]))) torrent_folder_name = '%s - %s [%s]' % (helpers.latinToAscii(albums[0]).encode('UTF-8').replace('/', '_'), helpers.latinToAscii(albums[1]).encode('UTF-8').replace('/', '_'), year) From a0b538861c434363f74f3f0181eeaff70595a6fd Mon Sep 17 00:00:00 2001 From: rembo10 Date: Sat, 27 Jul 2013 14:19:26 +0530 Subject: [PATCH 12/15] Transmission API working --- data/interfaces/default/config.html | 4 +- headphones/searcher.py | 23 ++++--- headphones/transmission.py | 76 +++++++++++++++++++++++ headphones/utorrent.py | 94 +++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 12 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 48db074c..7d558b1a 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -198,7 +198,7 @@
- +
@@ -337,7 +337,7 @@
Torrents
- +
diff --git a/headphones/searcher.py b/headphones/searcher.py index 6efbc0be..07a2190f 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -33,6 +33,7 @@ import string import headphones, exceptions from headphones import logger, db, helpers, classes, sab, nzbget +from headphones import transmission import lib.bencode as bencode @@ -473,7 +474,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): for result in resultlist: if high_size_limit and (result[1] > high_size_limit): - logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit)) + logger.info(result[0] + " is too large for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Maxsize: " + helpers.bytes_to_mb(high_size_limit) + ")") # Add lossless nzbs to the "flac list" which we can use if there are no good lossy matches if 'flac' in result[0].lower(): @@ -482,7 +483,7 @@ def searchNZB(albumid=None, new=False, losslessOnly=False): continue if low_size_limit and (result[1] < low_size_limit): - logger.info(result[0] + " is too small for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Minsize: " + helpers.bytes_to_mb(low_size_limit)) + logger.info(result[0] + " is too small for this album - not considering it. (Size: " + helpers.bytes_to_mb(result[1]) + ", Minsize: " + helpers.bytes_to_mb(low_size_limit) + ")") continue delta = abs(targetsize - result[1]) @@ -1351,14 +1352,9 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): if data and bestqual: logger.info(u'Found best result from %s: %s - %s' % (bestqual[3], bestqual[2], bestqual[0], helpers.bytes_to_mb(bestqual[1]))) torrent_folder_name = '%s - %s [%s]' % (helpers.latinToAscii(albums[0]).encode('UTF-8').replace('/', '_'), helpers.latinToAscii(albums[1]).encode('UTF-8').replace('/', '_'), year) - if headphones.TORRENTBLACKHOLE_DIR == "sendtracker": - torrent = classes.TorrentDataSearchResult() - torrent.extraInfo.append(data) - torrent.name = torrent_folder_name - sab.sendTorrent(torrent) - - elif headphones.TORRENTBLACKHOLE_DIR != "": + # Blackhole + if headphones.TORRENT_DOWNLOADER == 0: # Get torrent name from .torrent, this is usually used by the torrent client as the folder name @@ -1388,6 +1384,11 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): logger.error('Couldn\'t get name from Torrent file: %s' % e) break + elif headphones.TORRENT_DOWNLOADER == 1: + logger.info("Sending torrent to Transmission") + transmission.sendTorrent(bestqual[2]) + + myDB.action('UPDATE albums SET status = "Snatched" WHERE AlbumID=?', [albums[2]]) myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [albums[2], bestqual[0], bestqual[1], bestqual[2], "Snatched", torrent_folder_name, "torrent"]) @@ -1399,9 +1400,11 @@ def preprocesstorrent(resultlist, pre_sorted_list=False): elif int(selresult[1]) < int(result[1]): # if size is lower than new result replace previous selected result (bigger size = better quality?) selresult = result - # get outta here if rutracker or piratebay + # get outta here if rutracker or piratebay, or if we're using Transmission or uTorrent if selresult[3] == 'rutracker.org' or selresult[3] == 'The Pirate Bay': return True, selresult + if headphones.TORRENT_DOWNLOADER != 0: + return True, selresult if pre_sorted_list: selresult = resultlist[0] diff --git a/headphones/transmission.py b/headphones/transmission.py index e3b93d4e..21d7e584 100644 --- a/headphones/transmission.py +++ b/headphones/transmission.py @@ -13,4 +13,80 @@ # You should have received a copy of the GNU General Public License # along with Headphones. If not, see . +import headphones +from headphones import logger, notifiers +import urllib2 +import lib.simplejson as json +import base64 + +# This is just a simple script to send torrents to transmission. The +# intention is to turn this into a class where we can check the state +# of the download, set the download dir, etc. +# TODO: Store the session id so we don't need to make 2 calls +# Store torrent id so we can check up on it + +def sendTorrent(link): + + host = headphones.TRANSMISSION_HOST + username = headphones.TRANSMISSION_USERNAME + password = headphones.TRANSMISSION_PASSWORD + sessionid = None + + if not host.startswith('http'): + host = 'http://' + host + + if host.endswith('/'): + host = host[:-1] + + host = host + "/transmission/rpc" + request = urllib2.Request(host) + if username and password: + base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '') + request.add_header("Authorization", "Basic %s" % base64string) + opener = urllib2.build_opener() + try: + data = opener.open(request).read() + except urllib2.HTTPError, e: + if e.code == 409: + sessionid = e.hdrs['x-transmission-session-id'] + else: + logger.error('Could not connect to Transmission. Error: ' + str(e)) + except Exception, e: + logger.error('Could not connect to Transmission. Error: ' + str(e)) + + if not sessionid: + logger.error("Error getting Session ID from Transmission") + return + + request.add_header('x-transmission-session-id', sessionid) + + postdata = json.dumps({ 'method': 'torrent-add', + 'arguments': { 'filename': link, + 'download-dir': headphones.DOWNLOAD_TORRENT_DIR } }) + + request.add_data(postdata) + + try: + response = json.loads(opener.open(request).read()) + except Exception, e: + logger.error("Error sending torrent to Transmission: " + str(e)) + return + + if response['result'] == 'success': + name = response['arguments']['torrent-added']['name'] + logger.info(u"Torrent sent to Transmission successfully") + if headphones.PROWL_ENABLED and headphones.PROWL_ONSNATCH: + logger.info(u"Sending Prowl notification") + prowl = notifiers.PROWL() + prowl.notify(name,"Download started") + if headphones.PUSHOVER_ENABLED and headphones.PUSHOVER_ONSNATCH: + logger.info(u"Sending Pushover notification") + prowl = notifiers.PUSHOVER() + prowl.notify(name,"Download started") + if headphones.NMA_ENABLED and headphones.NMA_ONSNATCH: + logger.debug(u"Sending NMA notification") + nma = notifiers.NMA() + nma.notify(snatched_nzb=name) + + return True diff --git a/headphones/utorrent.py b/headphones/utorrent.py index e3b93d4e..e464495b 100644 --- a/headphones/utorrent.py +++ b/headphones/utorrent.py @@ -13,4 +13,98 @@ # You should have received a copy of the GNU General Public License # along with Headphones. If not, see . +## uTorrentAPI class taken from CouchPotatoServer +## http://github.com/RuudBurger/CouchPotatoServer +class uTorrentAPI(object): + + def __init__(self, host = 'localhost', port = 8000, username = None, password = None): + + super(uTorrentAPI, self).__init__() + + self.url = 'http://' + str(host) + ':' + str(port) + '/gui/' + self.token = '' + self.last_time = time.time() + cookies = cookielib.CookieJar() + self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler) + self.opener.addheaders = [('User-agent', 'couchpotato-utorrent-client/1.0')] + if username and password: + password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() + password_manager.add_password(realm = None, uri = self.url, user = username, passwd = password) + self.opener.add_handler(urllib2.HTTPBasicAuthHandler(password_manager)) + self.opener.add_handler(urllib2.HTTPDigestAuthHandler(password_manager)) + elif username or password: + log.debug('User or password missing, not using authentication.') + self.token = self.get_token() + + def _request(self, action, data = None): + if time.time() > self.last_time + 1800: + self.last_time = time.time() + self.token = self.get_token() + request = urllib2.Request(self.url + "?token=" + self.token + "&" + action, data) + try: + open_request = self.opener.open(request) + response = open_request.read() + if response: + return response + else: + log.debug('Unknown failure sending command to uTorrent. Return text is: %s', response) + except httplib.InvalidURL, err: + log.error('Invalid uTorrent host, check your config %s', err) + except urllib2.HTTPError, err: + if err.code == 401: + log.error('Invalid uTorrent Username or Password, check your config') + else: + log.error('uTorrent HTTPError: %s', err) + except urllib2.URLError, err: + log.error('Unable to connect to uTorrent %s', err) + return False + + def get_token(self): + request = self.opener.open(self.url + "token.html") + token = re.findall("(.*?) Date: Sat, 27 Jul 2013 16:12:07 +0530 Subject: [PATCH 13/15] Grab the right folder name from transmission --- headphones/searcher.py | 5 +-- headphones/transmission.py | 73 ++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 07a2190f..f9f1c2cf 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1386,8 +1386,9 @@ def searchTorrent(albumid=None, new=False, losslessOnly=False): elif headphones.TORRENT_DOWNLOADER == 1: logger.info("Sending torrent to Transmission") - transmission.sendTorrent(bestqual[2]) - + torrentid = transmission.addTorrent(bestqual[2]) + torrent_folder_name = transmission.getTorrentFolder(torrentid) + myDB.action('UPDATE albums SET status = "Snatched" WHERE AlbumID=?', [albums[2]]) myDB.action('INSERT INTO snatched VALUES( ?, ?, ?, ?, DATETIME("NOW", "localtime"), ?, ?, ?)', [albums[2], bestqual[0], bestqual[1], bestqual[2], "Snatched", torrent_folder_name, "torrent"]) diff --git a/headphones/transmission.py b/headphones/transmission.py index 21d7e584..bace5517 100644 --- a/headphones/transmission.py +++ b/headphones/transmission.py @@ -19,6 +19,7 @@ from headphones import logger, notifiers import urllib2 import lib.simplejson as json import base64 +import time # This is just a simple script to send torrents to transmission. The # intention is to turn this into a class where we can check the state @@ -26,7 +27,52 @@ import base64 # TODO: Store the session id so we don't need to make 2 calls # Store torrent id so we can check up on it -def sendTorrent(link): +def addTorrent(link): + method = 'torrent-add' + arguments = {'filename': link, 'download-dir':headphones.DOWNLOAD_TORRENT_DIR} + + response = torrentAction(method,arguments) + + + if response['result'] == 'success': + name = response['arguments']['torrent-added']['name'] + logger.info(u"Torrent sent to Transmission successfully") + if headphones.PROWL_ENABLED and headphones.PROWL_ONSNATCH: + logger.info(u"Sending Prowl notification") + prowl = notifiers.PROWL() + prowl.notify(name,"Download started") + if headphones.PUSHOVER_ENABLED and headphones.PUSHOVER_ONSNATCH: + logger.info(u"Sending Pushover notification") + prowl = notifiers.PUSHOVER() + prowl.notify(name,"Download started") + if headphones.NMA_ENABLED and headphones.NMA_ONSNATCH: + logger.debug(u"Sending NMA notification") + nma = notifiers.NMA() + nma.notify(snatched_nzb=name) + + return response['arguments']['torrent-added']['id'] + +def getTorrentFolder(torrentid): + method = 'torrent-get' + arguments = { 'ids': torrentid, 'fields': ['name','percentDone']} + + response = torrentAction(method, arguments) + percentdone = response['arguments']['torrents'][0]['percentDone'] + torrent_folder_name = response['arguments']['torrents'][0]['name'] + print torrent_folder_name + + while percentdone == 0: + print "In the while loop" + time.sleep(5) + response = torrentAction(method, arguments) + percentdone = response['arguments']['torrents'][0]['percentDone'] + print "Attempting to get folder name, percent done: " + str(percentdone) + + torrent_folder_name = response['arguments']['torrents'][0]['name'] + print torrent_folder_name + " updated and finished!" + return torrent_folder_name + +def torrentAction(method, arguments): host = headphones.TRANSMISSION_HOST username = headphones.TRANSMISSION_USERNAME @@ -61,9 +107,8 @@ def sendTorrent(link): request.add_header('x-transmission-session-id', sessionid) - postdata = json.dumps({ 'method': 'torrent-add', - 'arguments': { 'filename': link, - 'download-dir': headphones.DOWNLOAD_TORRENT_DIR } }) + postdata = json.dumps({ 'method': method, + 'arguments': arguments }) request.add_data(postdata) @@ -72,21 +117,5 @@ def sendTorrent(link): except Exception, e: logger.error("Error sending torrent to Transmission: " + str(e)) return - - if response['result'] == 'success': - name = response['arguments']['torrent-added']['name'] - logger.info(u"Torrent sent to Transmission successfully") - if headphones.PROWL_ENABLED and headphones.PROWL_ONSNATCH: - logger.info(u"Sending Prowl notification") - prowl = notifiers.PROWL() - prowl.notify(name,"Download started") - if headphones.PUSHOVER_ENABLED and headphones.PUSHOVER_ONSNATCH: - logger.info(u"Sending Pushover notification") - prowl = notifiers.PUSHOVER() - prowl.notify(name,"Download started") - if headphones.NMA_ENABLED and headphones.NMA_ONSNATCH: - logger.debug(u"Sending NMA notification") - nma = notifiers.NMA() - nma.notify(snatched_nzb=name) - - return True + + return response From 2b07759be065dfd915430f9ef513cf1a5c75d8bc Mon Sep 17 00:00:00 2001 From: rembo10 Date: Sat, 27 Jul 2013 17:27:36 +0530 Subject: [PATCH 14/15] Fixed 'Keep Torrent Files for seeding' --- headphones/postprocessor.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 5be3a0b0..dea6773a 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -320,14 +320,28 @@ 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(os.path.dirname(albumpath), ('temp' + release['AlbumTitle'][:8]).encode(headphones.SYS_ENCODING, 'replace')) - new_folder = new_folder.strip() + new_folder = os.path.join(albumpath, 'headphones-modified').encode(headphones.SYS_ENCODING, 'replace') + logger.info("Copying files to 'headphones-modified' subfolder to preserve downleaded files for seeding") try: shutil.copytree(albumpath, new_folder) + # Update the album path with the new location albumpath = new_folder except Exception, e: logger.warn("Cannot copy/move files to temp folder: " + new_folder.decode(headphones.SYS_ENCODING, 'replace') + ". Not continuing. Error: " + str(e)) return + + # Need to update the downloaded track list with the new location. + # Could probably just throw in the "headphones-modified" folder, + # but this is good to make sure we're not counting files that may have failed to move + downloaded_track_list = [] + downloaded_cuecount = 0 + + for r,d,f in os.walk(albumpath): + for files in f: + if any(files.lower().endswith('.' + x.lower()) for x in headphones.MEDIA_FORMATS): + downloaded_track_list.append(os.path.join(r, files)) + elif files.lower().endswith('.cue'): + downloaded_cuecount += 1 #start encoding if headphones.MUSIC_ENCODER: downloaded_track_list=music_encoder.encode(albumpath) From 934bdd790ba3b271874a00130f4b2e357ff12170 Mon Sep 17 00:00:00 2001 From: rembo10 Date: Sat, 27 Jul 2013 17:41:08 +0530 Subject: [PATCH 15/15] Got rid of uTorrent option in the config (not ready yet but want to get the Transmission option out). Also added a little description to explain how you can use the Music Download Directory with Transmission --- data/interfaces/default/config.html | 9 ++- headphones/utorrent.py | 96 ----------------------------- 2 files changed, 6 insertions(+), 99 deletions(-) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 7d558b1a..5191ee7b 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -177,7 +177,7 @@
Torrents - Black Hole Transmission uTorrent + Black Hole Transmission
@@ -186,7 +186,7 @@ Folder your Download program watches for Torrents
-
+
@@ -200,8 +200,11 @@
+
+ Note: With Transmission, you can specify a different download directory for downloads sent from Headphones. + Set it in the Music Download Directory below
-
+
diff --git a/headphones/utorrent.py b/headphones/utorrent.py index e464495b..fca5f5e3 100644 --- a/headphones/utorrent.py +++ b/headphones/utorrent.py @@ -12,99 +12,3 @@ # # You should have received a copy of the GNU General Public License # along with Headphones. If not, see . - -## uTorrentAPI class taken from CouchPotatoServer -## http://github.com/RuudBurger/CouchPotatoServer - -class uTorrentAPI(object): - - def __init__(self, host = 'localhost', port = 8000, username = None, password = None): - - super(uTorrentAPI, self).__init__() - - self.url = 'http://' + str(host) + ':' + str(port) + '/gui/' - self.token = '' - self.last_time = time.time() - cookies = cookielib.CookieJar() - self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies), MultipartPostHandler) - self.opener.addheaders = [('User-agent', 'couchpotato-utorrent-client/1.0')] - if username and password: - password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm() - password_manager.add_password(realm = None, uri = self.url, user = username, passwd = password) - self.opener.add_handler(urllib2.HTTPBasicAuthHandler(password_manager)) - self.opener.add_handler(urllib2.HTTPDigestAuthHandler(password_manager)) - elif username or password: - log.debug('User or password missing, not using authentication.') - self.token = self.get_token() - - def _request(self, action, data = None): - if time.time() > self.last_time + 1800: - self.last_time = time.time() - self.token = self.get_token() - request = urllib2.Request(self.url + "?token=" + self.token + "&" + action, data) - try: - open_request = self.opener.open(request) - response = open_request.read() - if response: - return response - else: - log.debug('Unknown failure sending command to uTorrent. Return text is: %s', response) - except httplib.InvalidURL, err: - log.error('Invalid uTorrent host, check your config %s', err) - except urllib2.HTTPError, err: - if err.code == 401: - log.error('Invalid uTorrent Username or Password, check your config') - else: - log.error('uTorrent HTTPError: %s', err) - except urllib2.URLError, err: - log.error('Unable to connect to uTorrent %s', err) - return False - - def get_token(self): - request = self.opener.open(self.url + "token.html") - token = re.findall("(.*?)