From 3f23b5553a47a59f9682fca635ae8a18ad2f79e0 Mon Sep 17 00:00:00 2001 From: VoidVolker Date: Fri, 8 Jul 2016 14:39:36 +0300 Subject: [PATCH 01/19] [+] --host command line option --- Headphones.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Headphones.py b/Headphones.py index dc956a43e..e45067970 100755 --- a/Headphones.py +++ b/Headphones.py @@ -81,6 +81,8 @@ def main(): help='Prevent browser from launching on startup') parser.add_argument( '--pidfile', help='Create a pid file (only relevant when running as a daemon)') + parser.add_argument( + '--host', help='Specify a host (default - localhost)') args = parser.parse_args() @@ -170,6 +172,13 @@ def main(): else: http_port = int(headphones.CONFIG.HTTP_PORT) + # Force the http host if neccessary + if args.host: + http_host = args.host + logger.info('Using forced web server host: %s', http_host) + else: + http_host = headphones.CONFIG.HTTP_HOST + # Check if pyOpenSSL is installed. It is required for certificate generation # and for CherryPy. if headphones.CONFIG.ENABLE_HTTPS: @@ -183,7 +192,7 @@ def main(): # Try to start the server. Will exit here is address is already in use. web_config = { 'http_port': http_port, - 'http_host': headphones.CONFIG.HTTP_HOST, + 'http_host': http_host, 'http_root': headphones.CONFIG.HTTP_ROOT, 'http_proxy': headphones.CONFIG.HTTP_PROXY, 'enable_https': headphones.CONFIG.ENABLE_HTTPS, From a7a709df517db57ab2fef71fb52e805b48e0d401 Mon Sep 17 00:00:00 2001 From: VoidVolker Date: Fri, 8 Jul 2016 14:42:19 +0300 Subject: [PATCH 02/19] [+] HP_HOST option --- init-scripts/init.ubuntu | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/init-scripts/init.ubuntu b/init-scripts/init.ubuntu index c4c0b8dc6..9a7e094f4 100755 --- a/init-scripts/init.ubuntu +++ b/init-scripts/init.ubuntu @@ -105,7 +105,12 @@ load_settings() { PORT_OPTS=" --port=${HP_PORT} " } - DAEMON_OPTS=" Headphones.py --quiet --daemon --nolaunch --pidfile=${PID_FILE} --datadir=${DATA_DIR} ${PORT_OPTS}${EXTRA_DAEMON_OPTS}" + # Host config + [ -n "$HP_HOST" ] && { + HOST_OPTS=" --host=${HP_HOST} " + } + + DAEMON_OPTS=" Headphones.py --quiet --daemon --nolaunch --pidfile=${PID_FILE} --datadir=${DATA_DIR} ${PORT_OPTS} ${HOST_OPTS} ${EXTRA_DAEMON_OPTS}" SETTINGS_LOADED=TRUE fi From 9a681a94226c07ba65c0511508c3c1096f08f426 Mon Sep 17 00:00:00 2001 From: VoidVolker Date: Fri, 8 Jul 2016 14:44:01 +0300 Subject: [PATCH 03/19] [=] HP_HOST description --- init-scripts/init.ubuntu | 1 + 1 file changed, 1 insertion(+) diff --git a/init-scripts/init.ubuntu b/init-scripts/init.ubuntu index 9a7e094f4..47f2f2b45 100755 --- a/init-scripts/init.ubuntu +++ b/init-scripts/init.ubuntu @@ -33,6 +33,7 @@ ## PYTHON_BIN= #$DAEMON, the location of the python binary, the default is /usr/bin/python ## HP_OPTS= #$EXTRA_DAEMON_OPTS, extra cli option for headphones, i.e. " --config=/home/headphones/config.ini" ## HP_PORT= #$PORT_OPTS, hardcoded port for the webserver, overrides value in config.ini +## HP_HOST= #$HOST_OPTS, host for the webserver, overrides value in config.ini ## ## EXAMPLE if want to run as different user ## add HP_USER=username to /etc/default/headphones From 323d3645721dbf843743b60c23f8cd27a9deb3f2 Mon Sep 17 00:00:00 2001 From: Bryon Roche Date: Thu, 14 Jul 2016 05:20:39 -0700 Subject: [PATCH 04/19] Added missing support method for current FauxSocket for pypy --- lib/cherrypy/wsgiserver/wsgiserver2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cherrypy/wsgiserver/wsgiserver2.py b/lib/cherrypy/wsgiserver/wsgiserver2.py index b4919cf57..ee1f82148 100644 --- a/lib/cherrypy/wsgiserver/wsgiserver2.py +++ b/lib/cherrypy/wsgiserver/wsgiserver2.py @@ -99,12 +99,14 @@ def my_crazy_app(environ, start_response): class FauxSocket(object): - """Faux socket with the minimal interface required by pypy""" def _reuse(self): pass + def _drop(self): + pass + _fileobject_uses_str_type = isinstance( socket._fileobject(FauxSocket())._rbuf, basestring) del FauxSocket # this class is not longer required for anything. From c0c64621e64db8abcc43408e64aa3f2a48997b85 Mon Sep 17 00:00:00 2001 From: Bryon Roche Date: Thu, 14 Jul 2016 05:22:25 -0700 Subject: [PATCH 05/19] Add a thread-dumping handler Add a 'crier' handler to dump the thread stacks of running threads to the log, for easier debugging. --- headphones/crier.py | 36 ++++++++++++++++++++++++++++++++++++ headphones/webserve.py | 7 ++++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 headphones/crier.py diff --git a/headphones/crier.py b/headphones/crier.py new file mode 100644 index 000000000..2399f6a97 --- /dev/null +++ b/headphones/crier.py @@ -0,0 +1,36 @@ +import pprint +import sys +import threading +import traceback + +from headphones import logger + + +def cry(): + """ + Logs thread traces. + """ + tmap = {} + main_thread = None + # get a map of threads by their ID so we can print their names + # during the traceback dump + for t in threading.enumerate(): + if t.ident: + tmap[t.ident] = t + else: + main_thread = t + + # Loop over each thread's current frame, writing info about it + for tid, frame in sys._current_frames().iteritems(): + thread = tmap.get(tid, main_thread) + + lines = [] + lines.append('%s\n' % thread.getName()) + lines.append('========================================\n') + lines += traceback.format_stack(frame) + lines.append('========================================\n') + lines.append('LOCAL VARIABLES:\n') + lines.append('========================================\n') + lines.append(pprint.pformat(frame.f_locals)) + lines.append('\n\n') + logger.info("".join(lines)) diff --git a/headphones/webserve.py b/headphones/webserve.py index f4a06c2bc..249bf9f95 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -28,7 +28,7 @@ import os import re -from headphones import logger, searcher, db, importer, mb, lastfm, librarysync, helpers, notifiers +from headphones import logger, searcher, db, importer, mb, lastfm, librarysync, helpers, notifiers, crier from headphones.helpers import checked, radio, today, clean_name from mako.lookup import TemplateLookup from mako import exceptions @@ -69,6 +69,11 @@ def home(self): artists = myDB.select('SELECT * from artists order by ArtistSortName COLLATE NOCASE') return serve_template(templatename="index.html", title="Home", artists=artists) + @cherrypy.expose + def threads(self): + crier.cry() + raise cherrypy.HTTPRedirect("home") + @cherrypy.expose def artistPage(self, ArtistID): myDB = db.DBConnection() From d3584a5ae9d2e7acc68ac131b9408da9f8bac544 Mon Sep 17 00:00:00 2001 From: clowninasack Date: Mon, 1 Aug 2016 10:30:10 -0700 Subject: [PATCH 06/19] Fixed FreeBSD init script. --- init-scripts/init.freebsd | 59 +++++++++++++-------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/init-scripts/init.freebsd b/init-scripts/init.freebsd index 85d2cf14e..bd4cca2ae 100755 --- a/init-scripts/init.freebsd +++ b/init-scripts/init.freebsd @@ -1,7 +1,8 @@ #!/bin/sh # # PROVIDE: headphones -# REQUIRE: DAEMON sabnzbd +# REQUIRE: DAEMON +# BEFORE: LOGIN # KEYWORD: shutdown # # Add the following lines to /etc/rc.conf.local or /etc/rc.conf @@ -15,56 +16,34 @@ # as root. # headphones_dir: Directory where Headphones lives. # Default: /usr/local/headphones -# headphones_chdir: Change to this directory before running Headphones. -# Default is same as headphones_dir. # headphones_pid: The name of the pidfile to create. # Default is headphones.pid in headphones_dir. -PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin" . /etc/rc.subr name="headphones" rcvar=${name}_enable -load_rc_config ${name} - : "${headphones_enable:="NO"}" : "${headphones_user:="_sabnzbd"}" : "${headphones_dir:="/usr/local/headphones"}" -: "${headphones_chdir:="${headphones_dir}"}" -: "${headphones_pid:="${headphones_dir}/headphones.pid"}" - -status_cmd="${name}_status" -stop_cmd="${name}_stop" - -command="/usr/sbin/daemon" -command_args="-f -p ${headphones_pid} python ${headphones_dir}/Headphones.py ${headphones_flags} --quiet --nolaunch" - -# Ensure user is root when running this script. -if [ "$(id -u)" != "0" ]; then - echo "Oops, you should be root before running this!" - exit 1 -fi - -verify_headphones_pid() { - # Make sure the pid corresponds to the Headphones process. - pid=$(cat "${headphones_pid}" 2>/dev/null) - pgrep -F "${headphones_pid}" -q "python ${headphones_dir}/Headphones.py" - return $? -} - -# Try to stop Headphones cleanly by calling shutdown over http. -headphones_stop() { - echo "Stopping $name" - verify_headphones_pid - if [ -n "${pid}" ]; then - wait_for_pids "${pid}" - echo "Stopped" - fi -} - -headphones_status() { - verify_headphones_pid && echo "$name is running as ${pid}" || echo "$name is not running" +: "${headphones_conf:="/usr/local/headphones/config.ini"}" + +command="${headphones_dir}/Headphones.py" +command_interpreter="/usr/bin/python" +pidfile="/var/run/headphones/headphones.pid" +start_precmd="headphones_start_precmd" +headphones_flags="--daemon --nolaunch --pidfile $pidfile --config $headphones_conf $headphones_flags" + +headphones_start_precmd() { + if [ $($ID -u) != 0 ]; then + err 1 "Must be root." + fi + + if [ ! -d /var/run/headphones ]; then + install -do $headphones_user /var/run/headphones + fi } +load_rc_config ${name} run_rc_command "$1" From 8eb3ece2f9a1480cebd9c64bb2fd8d6b89527f34 Mon Sep 17 00:00:00 2001 From: Ade Date: Sat, 17 Sep 2016 20:27:01 +1200 Subject: [PATCH 07/19] rutracker login fix stop redirecting to the same login page --- headphones/rutracker.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/headphones/rutracker.py b/headphones/rutracker.py index af8e947e7..a4141c38d 100644 --- a/headphones/rutracker.py +++ b/headphones/rutracker.py @@ -44,22 +44,18 @@ def login(self): logger.info("Attempting to log in to rutracker...") try: - r = self.session.post(loginpage, data=post_params, timeout=self.timeout) + r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) # try again if 'bb_data' not in r.cookies.keys(): time.sleep(10) - r = self.session.post(loginpage, data=post_params, timeout=self.timeout) - if r.status_code != 200: - logger.error("rutracker login returned status code %s" % r.status_code) - self.loggedin = False + r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) + if 'bb_data' in r.cookies.keys(): + self.loggedin = True + logger.info("Successfully logged in to rutracker") else: - if 'bb_data' in r.cookies.keys(): - self.loggedin = True - logger.info("Successfully logged in to rutracker") - else: - logger.error( - "Could not login to rutracker, credentials maybe incorrect, site is down or too many attempts. Try again later") - self.loggedin = False + logger.error( + "Could not login to rutracker, credentials maybe incorrect, site is down or too many attempts. Try again later") + self.loggedin = False return self.loggedin except Exception as e: logger.error("Unknown error logging in to rutracker: %s" % e) From 99680e9a0f4f61710fb7fc75e5f094d35b5c62c9 Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 00:46:12 +0200 Subject: [PATCH 08/19] Update searcher.py to add t411 support --- headphones/searcher.py | 86 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/headphones/searcher.py b/headphones/searcher.py index c8f16184f..ff7e4736f 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -14,6 +14,7 @@ # along with Headphones. If not, see . # NZBGet support added by CurlyMo as a part of XBian - XBMC on the Raspberry Pi +# t411 support added by a1ex, @likeitneverwentaway on github for maintenance from base64 import b16encode, b32decode from hashlib import sha1 @@ -812,6 +813,19 @@ def send_to_downloader(data, bestqual, album): # Get torrent name from .torrent, this is usually used by the torrent client as the folder name torrent_name = helpers.replace_illegal_chars(folder_name) + '.torrent' download_path = os.path.join(headphones.CONFIG.TORRENTBLACKHOLE_DIR, torrent_name) + + # Blackhole for t411 + if bestqual[2].lower().startswith("http://api.t411"): + if headphones.CONFIG.MAGNET_LINKS == 2: + try: + url = bestqual[2].split('TOKEN')[0] + token = bestqual[2].split('TOKEN')[1] + data = request.request_content(url, headers = {'Authorization':token}) + torrent_to_file(download_path, data) + logger.info('Successfully converted magnet to torrent file') + except Exception as e: + logger.error("Error converting magnet link: %s" % str(e)) + return if bestqual[2].lower().startswith("magnet:"): if headphones.CONFIG.MAGNET_LINKS == 1: @@ -1763,6 +1777,78 @@ def set_proxy(proxy_url): resultlist.append((title, size, url, provider, 'torrent', match)) except Exception as e: logger.exception("Unhandled exception in Mininova Parser") + # t411 + if headphones.CONFIG.TQUATTRECENTONZE: + username = headphones.CONFIG.TQUATTRECENTONZE_USER + password = headphones.CONFIG.TQUATTRECENTONZE_PASSWORD + API_URL = "http://api.t411.ch" + AUTH_URL= API_URL + '/auth' + DL_URL = API_URL + '/torrents/download/' + provider = "t411" + t411_term = term.replace(" ","%20") + SEARCH_URL = API_URL + '/torrents/search/' + t411_term + "?limit=15&cid=395&subcat=623" + headers_login = {'username': username, 'password' : password} + + # Requesting content + logger.info('Parsing results from t411 using search term: %s' % term) + req = request.request_content(AUTH_URL, method='post',data = headers_login) + + if len(req.split('"')) == 9: + token =req.split('"')[7] + headers_auth = {'Authorization':token} + logger.info('t411 - User %s logged in' % username) + else: + logger.info('t411 - Login error : %s' % req.split('"')[3]) + + # Quality + if headphones.CONFIG.PREFERRED_QUALITY == 3 or losslessOnly: + providerurl = "&term[16][]=529&term[16][]=1184" + elif headphones.CONFIG.PREFERRED_QUALITY == 1 or allow_lossless: + providerurl = fix_url(SEARCH_URL + "&term[16][]=685&term[16][]=527&term[16][]=1070&term[16][]=528&term[16][]=1167&term[16][]=1166&term[16][]=530&term[16][]=529&term[16][]=1184&term[16][]=532&term[16][]=533&term[16][]=1085&term[16][]=534&term[16][]=535&term[16][]=1069&term[16][]=537&term[16][]=538") + elif headphones.CONFIG.PREFERRED_QUALITY == 0: + providerurl = fix_url(SEARCH_URL + "&term[16][]=685&term[16][]=527&term[16][]=1070&term[16][]=528&term[16][]=1167&term[16][]=1166&term[16][]=530&term[16][]=532&term[16][]=533&term[16][]=1085&term[16][]=534&term[16][]=535&term[16][]=1069&term[16][]=537&term[16][]=538") + else: + providerurl = fix_url(SEARCH_URL) + + # Tracker search + req = request.request_content(providerurl, headers = headers_auth) + req = json.loads(req) + total = req['total'] + + # Process feed + if total == '0': + logger.info("No results found from t411 for %s" % term) + else: + logger.info('Found %s results from t411' % total) + torrents = req['torrents'] + for torrent in torrents: + try: + title = torrent['name'] + if torrent['seeders'] < minimumseeders: + logger.info('Skipping torrent %s : seeders below minimum set' % title) + continue + id = torrent['id'] + size = int(torrent['size']) + data = request.request_content(DL_URL + id, headers = headers_auth) + + #Blackhole + if headphones.CONFIG.TORRENT_DOWNLOADER == 0 and headphones.CONFIG.MAGNET_LINKS == 2: + url = DL_URL + id + 'TOKEN' + token + resultlist.append((title, size, url, provider, 'torrent', True)) + + # Build magnet + else: + metadata = bdecode(data) + hashcontents = bencode(metadata['info']) + digest = sha1(hashcontents).hexdigest() + trackers = [metadata["announce"]][0] + url = 'magnet:?xt=urn:btih:%s&tr=%s' % (digest, trackers) + resultlist.append((title, size, url, provider, 'torrent', True)) + + except Exception as e: + logger.error("Error converting magnet link: %s" % str(e)) + return + # attempt to verify that this isn't a substring result # when looking for "Foo - Foo" we don't want "Foobar" From bd8eb74662d370ac4394876afe962c0d70684ab2 Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 00:50:48 +0200 Subject: [PATCH 09/19] Update config.html to add t411 support --- data/interfaces/default/config.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index a22a0ea76..baf395860 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -743,6 +743,22 @@

Settings

+ +
+
+ +
+
+
+ + +
+
+ + +
+
+
@@ -2400,6 +2416,7 @@

Settings

initConfigCheckbox("#api_enabled"); initConfigCheckbox("#enable_https"); initConfigCheckbox("#customauth"); + initConfigCheckbox("#use_tquattrecentonze"); $('#twitterStep1').click(function () { From d3d48d27df71ab2f67554347c91a6254bfb04d72 Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 01:00:49 +0200 Subject: [PATCH 10/19] Update webserve.py to add t411 support --- headphones/webserve.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/headphones/webserve.py b/headphones/webserve.py index 249bf9f95..1337894c9 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -1229,6 +1229,9 @@ def config(self): "whatcd_ratio": headphones.CONFIG.WHATCD_RATIO, "use_strike": checked(headphones.CONFIG.STRIKE), "strike_ratio": headphones.CONFIG.STRIKE_RATIO, + "use_tquattrecentonze": checked(headphones.CONFIG.TQUATTRECENTONZE), + "tquattrecentonze_user": headphones.CONFIG.TQUATTRECENTONZE_USER, + "tquattrecentonze_password": headphones.CONFIG.TQUATTRECENTONZE_PASSWORD, "pref_qual_0": radio(headphones.CONFIG.PREFERRED_QUALITY, 0), "pref_qual_1": radio(headphones.CONFIG.PREFERRED_QUALITY, 1), "pref_qual_2": radio(headphones.CONFIG.PREFERRED_QUALITY, 2), @@ -1425,7 +1428,7 @@ def configUpdate(self, **kwargs): "use_newznab", "newznab_enabled", "use_torznab", "torznab_enabled", "use_nzbsorg", "use_omgwtfnzbs", "use_kat", "use_piratebay", "use_oldpiratebay", "use_mininova", "use_waffles", "use_rutracker", - "use_whatcd", "use_strike", "preferred_bitrate_allow_lossless", "detect_bitrate", + "use_whatcd", "use_strike", "use_tquattrecentonze", "preferred_bitrate_allow_lossless", "detect_bitrate", "ignore_clean_releases", "freeze_db", "cue_split", "move_files", "rename_files", "correct_metadata", "cleanup_files", "keep_nfo", "add_album_art", "embed_album_art", "embed_lyrics", From aa503f0fe88a1ff4fd6dee49211500bc62be7a22 Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 01:01:39 +0200 Subject: [PATCH 11/19] Update config.py to add t411 support --- headphones/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/headphones/config.py b/headphones/config.py index 5b8190074..e825cc685 100644 --- a/headphones/config.py +++ b/headphones/config.py @@ -274,6 +274,9 @@ def __repr__(self): 'TWITTER_PASSWORD': (str, 'Twitter', ''), 'TWITTER_PREFIX': (str, 'Twitter', 'Headphones'), 'TWITTER_USERNAME': (str, 'Twitter', ''), + 'TQUATTRECENTONZE': (int, 'tquattrecentonze', 0), + 'TQUATTRECENTONZE_PASSWORD': (str, 'tquattrecentonze', ''), + 'TQUATTRECENTONZE_USER': (str, 'tquattrecentonze', ''), 'UPDATE_DB_INTERVAL': (int, 'General', 24), 'USENET_RETENTION': (int, 'General', '1500'), 'UTORRENT_HOST': (str, 'uTorrent', ''), From 31a99a908afa91b8ada2e2d6a5c4c5f9722cba8f Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 01:08:54 +0200 Subject: [PATCH 12/19] Added credit --- headphones/webserve.py | 1 + 1 file changed, 1 insertion(+) diff --git a/headphones/webserve.py b/headphones/webserve.py index 1337894c9..9b09febad 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -14,6 +14,7 @@ # along with Headphones. If not, see . # NZBGet support added by CurlyMo as a part of XBian - XBMC on the Raspberry Pi +# t411 support added by a1ex, @likeitneverwentaway on github for maintenance from operator import itemgetter import threading From 42294d261d1cce82ec3e8be593671d00d257daba Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 8 Oct 2016 01:55:55 +0200 Subject: [PATCH 13/19] Fix typo, import loads from json --- headphones/searcher.py | 44 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index ff7e4736f..6c7fe8cf3 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -25,6 +25,7 @@ import subprocess import unicodedata import urlparse +from json import loads import os import re @@ -813,14 +814,14 @@ def send_to_downloader(data, bestqual, album): # Get torrent name from .torrent, this is usually used by the torrent client as the folder name torrent_name = helpers.replace_illegal_chars(folder_name) + '.torrent' download_path = os.path.join(headphones.CONFIG.TORRENTBLACKHOLE_DIR, torrent_name) - + # Blackhole for t411 if bestqual[2].lower().startswith("http://api.t411"): if headphones.CONFIG.MAGNET_LINKS == 2: try: url = bestqual[2].split('TOKEN')[0] token = bestqual[2].split('TOKEN')[1] - data = request.request_content(url, headers = {'Authorization':token}) + data = request.request_content(url, headers={'Authorization': token}) torrent_to_file(download_path, data) logger.info('Successfully converted magnet to torrent file') except Exception as e: @@ -1782,24 +1783,24 @@ def set_proxy(proxy_url): username = headphones.CONFIG.TQUATTRECENTONZE_USER password = headphones.CONFIG.TQUATTRECENTONZE_PASSWORD API_URL = "http://api.t411.ch" - AUTH_URL= API_URL + '/auth' + AUTH_URL = API_URL + '/auth' DL_URL = API_URL + '/torrents/download/' provider = "t411" - t411_term = term.replace(" ","%20") + t411_term = term.replace(" ", "%20") SEARCH_URL = API_URL + '/torrents/search/' + t411_term + "?limit=15&cid=395&subcat=623" - headers_login = {'username': username, 'password' : password} - + headers_login = {'username': username, 'password': password} + # Requesting content logger.info('Parsing results from t411 using search term: %s' % term) - req = request.request_content(AUTH_URL, method='post',data = headers_login) - + req = request.request_content(AUTH_URL, method='post', data=headers_login) + if len(req.split('"')) == 9: - token =req.split('"')[7] - headers_auth = {'Authorization':token} + token = req.split('"')[7] + headers_auth = {'Authorization': token} logger.info('t411 - User %s logged in' % username) else: logger.info('t411 - Login error : %s' % req.split('"')[3]) - + # Quality if headphones.CONFIG.PREFERRED_QUALITY == 3 or losslessOnly: providerurl = "&term[16][]=529&term[16][]=1184" @@ -1809,12 +1810,12 @@ def set_proxy(proxy_url): providerurl = fix_url(SEARCH_URL + "&term[16][]=685&term[16][]=527&term[16][]=1070&term[16][]=528&term[16][]=1167&term[16][]=1166&term[16][]=530&term[16][]=532&term[16][]=533&term[16][]=1085&term[16][]=534&term[16][]=535&term[16][]=1069&term[16][]=537&term[16][]=538") else: providerurl = fix_url(SEARCH_URL) - + # Tracker search - req = request.request_content(providerurl, headers = headers_auth) - req = json.loads(req) + req = request.request_content(providerurl, headers=headers_auth) + req = loads(req) total = req['total'] - + # Process feed if total == '0': logger.info("No results found from t411 for %s" % term) @@ -1829,26 +1830,25 @@ def set_proxy(proxy_url): continue id = torrent['id'] size = int(torrent['size']) - data = request.request_content(DL_URL + id, headers = headers_auth) - - #Blackhole + data = request.request_content(DL_URL + id, headers=headers_auth) + + # Blackhole if headphones.CONFIG.TORRENT_DOWNLOADER == 0 and headphones.CONFIG.MAGNET_LINKS == 2: url = DL_URL + id + 'TOKEN' + token resultlist.append((title, size, url, provider, 'torrent', True)) - + # Build magnet else: metadata = bdecode(data) hashcontents = bencode(metadata['info']) digest = sha1(hashcontents).hexdigest() trackers = [metadata["announce"]][0] - url = 'magnet:?xt=urn:btih:%s&tr=%s' % (digest, trackers) + url = 'magnet:?xt=urn:btih:%s&tr=%s' % (digest, trackers) resultlist.append((title, size, url, provider, 'torrent', True)) - + except Exception as e: logger.error("Error converting magnet link: %s" % str(e)) return - # attempt to verify that this isn't a substring result # when looking for "Foo - Foo" we don't want "Foobar" From 7428b56dd56ca5cfb258174607fe9578e5e83194 Mon Sep 17 00:00:00 2001 From: Ade Date: Sun, 9 Oct 2016 15:56:25 +1300 Subject: [PATCH 14/19] Remove mb apostrophe Fixes #2737 --- headphones/helpers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/headphones/helpers.py b/headphones/helpers.py index ff062d576..af1a13e08 100644 --- a/headphones/helpers.py +++ b/headphones/helpers.py @@ -251,6 +251,7 @@ def replace_illegal_chars(string, type="file"): # Translation table. # Cover additional special characters processing normalization. u"'": '', # replace apostrophe with nothing + u"’": '', # replace musicbrainz style apostrophe with nothing u'&': ' and ', # expand & to ' and ' } From c9a1796e569797f4d7ab9c1d02e4910f90359cbd Mon Sep 17 00:00:00 2001 From: Ade Date: Sat, 15 Oct 2016 09:59:11 +1300 Subject: [PATCH 15/19] Allow hyphen in mb search Fixes #2499 --- headphones/mb.py | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/headphones/mb.py b/headphones/mb.py index 397e50087..faba6b8a2 100644 --- a/headphones/mb.py +++ b/headphones/mb.py @@ -91,10 +91,6 @@ def findArtist(name, limit=1): artistlist = [] artistResults = None - chars = set('!?*-') - if any((c in chars) for c in name): - name = '"' + name + '"' - criteria = {'artist': name.lower()} with mb_lock: @@ -156,16 +152,13 @@ def findRelease(name, limit=1, artist=None): if not artist and ':' in name: name, artist = name.rsplit(":", 1) - chars = set('!?*-') - if any((c in chars) for c in name): - name = '"' + name + '"' - if artist and any((c in chars) for c in artist): - artist = '"' + artist + '"' + criteria = {'release': name.lower()} + if artist: + criteria['artist'] = artist.lower() with mb_lock: try: - releaseResults = musicbrainzngs.search_releases(query=name, limit=limit, artist=artist)[ - 'release-list'] + releaseResults = musicbrainzngs.search_releases(limit=limit, **criteria)['release-list'] except musicbrainzngs.WebServiceError as e: # need to update exceptions logger.warn('Attempt to query MusicBrainz for "%s" failed: %s' % (name, str(e))) mb_lock.snooze(5) @@ -234,10 +227,6 @@ def findSeries(name, limit=1): serieslist = [] seriesResults = None - chars = set('!?*-') - if any((c in chars) for c in name): - name = '"' + name + '"' - criteria = {'series': name.lower()} with mb_lock: @@ -759,19 +748,12 @@ def findArtistbyAlbum(name): def findAlbumID(artist=None, album=None): results = None - chars = set('!?*-') try: if album and artist: - if any((c in chars) for c in album): - album = '"' + album + '"' - if any((c in chars) for c in artist): - artist = '"' + artist + '"' criteria = {'release': album.lower()} criteria['artist'] = artist.lower() else: - if any((c in chars) for c in album): - album = '"' + album + '"' criteria = {'release': album.lower()} with mb_lock: results = musicbrainzngs.search_release_groups(limit=1, **criteria).get( From b58f670694ad13ba105d4fd0e8de048377bbbff9 Mon Sep 17 00:00:00 2001 From: etomm Date: Sat, 15 Oct 2016 10:08:51 +0200 Subject: [PATCH 16/19] Handling Deluge empty password --- headphones/deluge.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/headphones/deluge.py b/headphones/deluge.py index f97063d3f..6c1050540 100644 --- a/headphones/deluge.py +++ b/headphones/deluge.py @@ -269,7 +269,8 @@ def _get_auth(): delugeweb_host = headphones.CONFIG.DELUGE_HOST delugeweb_cert = headphones.CONFIG.DELUGE_CERT delugeweb_password = headphones.CONFIG.DELUGE_PASSWORD - logger.debug('Deluge: Using password %s******%s' % (delugeweb_password[0], delugeweb_password[-1])) + if len(delugeweb_password) > 0: + logger.debug('Deluge: Using password %s******%s' % (delugeweb_password[0], delugeweb_password[-1])) if not delugeweb_host.startswith('http'): delugeweb_host = 'http://%s' % delugeweb_host From 89e17939783992309cc52895461455f8b38f2481 Mon Sep 17 00:00:00 2001 From: likeitneverwentaway Date: Sat, 15 Oct 2016 14:39:55 +0200 Subject: [PATCH 17/19] Fixed lossless only for t411 --- headphones/searcher.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/headphones/searcher.py b/headphones/searcher.py index 6c7fe8cf3..cda9a8225 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -1803,7 +1803,7 @@ def set_proxy(proxy_url): # Quality if headphones.CONFIG.PREFERRED_QUALITY == 3 or losslessOnly: - providerurl = "&term[16][]=529&term[16][]=1184" + providerurl = fix_url(SEARCH_URL + "&term[16][]=529&term[16][]=1184") elif headphones.CONFIG.PREFERRED_QUALITY == 1 or allow_lossless: providerurl = fix_url(SEARCH_URL + "&term[16][]=685&term[16][]=527&term[16][]=1070&term[16][]=528&term[16][]=1167&term[16][]=1166&term[16][]=530&term[16][]=529&term[16][]=1184&term[16][]=532&term[16][]=533&term[16][]=1085&term[16][]=534&term[16][]=535&term[16][]=1069&term[16][]=537&term[16][]=538") elif headphones.CONFIG.PREFERRED_QUALITY == 0: From 0086980b1b4a8d5d2e98b8ff081ad66baafc94a6 Mon Sep 17 00:00:00 2001 From: Benjamin Piouffle Date: Wed, 19 Oct 2016 12:41:46 +1100 Subject: [PATCH 18/19] Fix Rutracker loggin by looking for the cookie in request history --- headphones/rutracker.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/headphones/rutracker.py b/headphones/rutracker.py index a4141c38d..b80685cfe 100644 --- a/headphones/rutracker.py +++ b/headphones/rutracker.py @@ -46,10 +46,10 @@ def login(self): try: r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) # try again - if 'bb_data' not in r.cookies.keys(): + if not self.has_bb_data_cookie(r): time.sleep(10) r = self.session.post(loginpage, data=post_params, timeout=self.timeout, allow_redirects=False) - if 'bb_data' in r.cookies.keys(): + if self.has_bb_data_cookie(r): self.loggedin = True logger.info("Successfully logged in to rutracker") else: @@ -62,6 +62,12 @@ def login(self): self.loggedin = False return self.loggedin + def has_bb_data_cookie(self, response): + if 'bb_data' in response.cookies.keys(): + return True + # Rutracker randomly send a 302 redirect code, cookie may be present in response history + return next(('bb_data' in r.cookies.keys() for r in response.history), False) + def searchurl(self, artist, album, year, format): """ Return the search url From 579b5a2f2fa7d9926bb3187c5d8ea08f97afd17c Mon Sep 17 00:00:00 2001 From: rembo10 Date: Thu, 10 Nov 2016 20:56:51 +0000 Subject: [PATCH 19/19] Updated changelog for v0.5.17 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1037f8e07..087baab76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## v0.5.17 +Released 10 November 2016 + +Highlights: +* Added: t411 support +* Fixed: Rutracker login +* Fixed: Deluge empty password +* Fixed: FreeBSD init script +* Improved: Musicbrainz searching + +The full list of commits can be found [here](https://github.com/rembo10/headphones/compare/v0.5.16...v0.5.17). + ## v0.5.16 Released 10 June 2016