diff --git a/data/interfaces/default/config.html b/data/interfaces/default/config.html index 99d1d4ec..5bc2edea 100644 --- a/data/interfaces/default/config.html +++ b/data/interfaces/default/config.html @@ -644,6 +644,10 @@ +
+ + +
@@ -651,6 +655,30 @@
+
+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
@@ -2412,6 +2440,7 @@ initConfigCheckbox("#use_waffles"); initConfigCheckbox("#use_rutracker"); initConfigCheckbox("#use_whatcd"); + initConfigCheckbox("#use_pth"); initConfigCheckbox("#use_strike"); initConfigCheckbox("#api_enabled"); initConfigCheckbox("#enable_https"); diff --git a/headphones/config.py b/headphones/config.py index e825cc68..46efed19 100644 --- a/headphones/config.py +++ b/headphones/config.py @@ -293,6 +293,12 @@ _CONFIG_DEFINITIONS = { 'WHATCD_PASSWORD': (str, 'What.cd', ''), 'WHATCD_RATIO': (str, 'What.cd', ''), 'WHATCD_USERNAME': (str, 'What.cd', ''), + 'WHATCD_URL': (str, 'What.cd', 'https://what.cd'), + 'PTH': (int, 'PassTheHeadphones.me', 0), + 'PTH_PASSWORD': (str, 'PassTheHeadphones.me', ''), + 'PTH_RATIO': (str, 'PassTheHeadphones.me', ''), + 'PTH_USERNAME': (str, 'PassTheHeadphones.me', ''), + 'PTH_URL': (str, 'PassTheHeadphones.me', 'https://passtheheadphones.me'), 'XBMC_ENABLED': (int, 'XBMC', 0), 'XBMC_HOST': (str, 'XBMC', ''), 'XBMC_NOTIFY': (int, 'XBMC', 0), diff --git a/headphones/searcher.py b/headphones/searcher.py index ac938972..7b19eb26 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -38,7 +38,6 @@ from headphones import logger, db, helpers, classes, sab, nzbget, request from headphones import utorrent, transmission, notifiers, rutracker, deluge from bencode import bencode, bdecode - # Magnet to torrent services, for Black hole. Stolen from CouchPotato. TORRENT_TO_MAGNET_SERVICES = [ # 'https://zoink.it/torrent/%s.torrent', @@ -163,6 +162,8 @@ def get_seed_ratio(provider): seed_ratio = headphones.CONFIG.KAT_RATIO elif provider == 'What.cd': seed_ratio = headphones.CONFIG.WHATCD_RATIO + elif provider == 'PassTheHeadphones.Me': + seed_ratio = headphones.CONFIG.PTH_RATIO elif provider == 'The Pirate Bay': seed_ratio = headphones.CONFIG.PIRATEBAY_RATIO elif provider == 'Old Pirate Bay': @@ -274,6 +275,7 @@ def do_sorted_search(album, new, losslessOnly, choose_specific_download=False): headphones.CONFIG.WAFFLES or headphones.CONFIG.RUTRACKER or headphones.CONFIG.WHATCD or + headphones.CONFIG.PTH or headphones.CONFIG.STRIKE) results = [] @@ -1504,7 +1506,8 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, try: logger.info(u"Attempting to log in to What.cd...") gazelle = gazelleapi.GazelleAPI(headphones.CONFIG.WHATCD_USERNAME, - headphones.CONFIG.WHATCD_PASSWORD) + headphones.CONFIG.WHATCD_PASSWORD, + headphones.CONFIG.WHATCD_URL) gazelle._login() except Exception as e: gazelle = None @@ -1564,6 +1567,106 @@ def searchTorrent(album, new=False, losslessOnly=False, albumlength=None, provider, 'torrent', True)) + # PassTheHeadphones.me - Using same logic as What.CD as it's also Gazelle, so should really make this into something reusable + if headphones.CONFIG.PTH: + provider = "PassTheHeadphones.me" + providerurl = "https://passtheheadphones.me/" + + bitrate = None + bitrate_string = bitrate + + if headphones.CONFIG.PREFERRED_QUALITY == 3 or losslessOnly: # Lossless Only mode + search_formats = [gazelleformat.FLAC] + maxsize = 10000000000 + elif headphones.CONFIG.PREFERRED_QUALITY == 2: # Preferred quality mode + search_formats = [None] # should return all + bitrate = headphones.CONFIG.PREFERRED_BITRATE + if bitrate: + if 225 <= int(bitrate) < 256: + bitrate = 'V0' + elif 200 <= int(bitrate) < 225: + bitrate = 'V1' + elif 175 <= int(bitrate) < 200: + bitrate = 'V2' + for encoding_string in gazelleencoding.ALL_ENCODINGS: + if re.search(bitrate, encoding_string, flags=re.I): + bitrate_string = encoding_string + if bitrate_string not in gazelleencoding.ALL_ENCODINGS: + logger.info( + u"Your preferred bitrate is not one of the available What.cd filters, so not using it as a search parameter.") + maxsize = 10000000000 + elif headphones.CONFIG.PREFERRED_QUALITY == 1 or allow_lossless: # Highest quality including lossless + search_formats = [gazelleformat.FLAC, gazelleformat.MP3] + maxsize = 10000000000 + else: # Highest quality excluding lossless + search_formats = [gazelleformat.MP3] + maxsize = 300000000 + + if not gazelle or not gazelle.logged_in(): + try: + logger.info(u"Attempting to log in to PassTheHeadphones.me...") + gazelle = gazelleapi.GazelleAPI(headphones.CONFIG.PTH_USERNAME, + headphones.CONFIG.PTH_PASSWORD, + headphones.CONFIG.PTH_URL) + gazelle._login() + except Exception as e: + gazelle = None + logger.error(u"PassTheHeadphones credentials incorrect or site is down. Error: %s %s" % ( + e.__class__.__name__, str(e))) + + if gazelle and gazelle.logged_in(): + logger.info(u"Searching %s..." % provider) + all_torrents = [] + for search_format in search_formats: + if usersearchterm: + all_torrents.extend( + gazelle.search_torrents(searchstr=usersearchterm, format=search_format, + encoding=bitrate_string)['results']) + else: + all_torrents.extend(gazelle.search_torrents(artistname=semi_clean_artist_term, + groupname=semi_clean_album_term, + format=search_format, + encoding=bitrate_string)['results']) + + # filter on format, size, and num seeders + logger.info(u"Filtering torrents by format, maximum size, and minimum seeders...") + match_torrents = [t for t in all_torrents if + t.size <= maxsize and t.seeders >= minimumseeders] + + logger.info( + u"Remaining torrents: %s" % ", ".join(repr(torrent) for torrent in match_torrents)) + + # sort by times d/l'd + if not len(match_torrents): + logger.info(u"No results found from %s for %s after filtering" % (provider, term)) + elif len(match_torrents) > 1: + logger.info(u"Found %d matching releases from %s for %s - %s after filtering" % + (len(match_torrents), provider, artistterm, albumterm)) + logger.info( + "Sorting torrents by times snatched and preferred bitrate %s..." % bitrate_string) + match_torrents.sort(key=lambda x: int(x.snatched), reverse=True) + if gazelleformat.MP3 in search_formats: + # sort by size after rounding to nearest 10MB...hacky, but will favor highest quality + match_torrents.sort(key=lambda x: int(10 * round(x.size / 1024. / 1024. / 10.)), + reverse=True) + if search_formats and None not in search_formats: + match_torrents.sort( + key=lambda x: int(search_formats.index(x.format))) # prefer lossless + # if bitrate: + # match_torrents.sort(key=lambda x: re.match("mp3", x.getTorrentDetails(), flags=re.I), reverse=True) + # match_torrents.sort(key=lambda x: str(bitrate) in x.getTorrentFolderName(), reverse=True) + logger.info( + u"New order: %s" % ", ".join(repr(torrent) for torrent in match_torrents)) + + for torrent in match_torrents: + if not torrent.file_path: + torrent.group.update_group_data() # will load the file_path for the individual torrents + resultlist.append((torrent.file_path, + torrent.size, + gazelle.generate_torrent_link(torrent.id), + provider, + 'torrent', True)) + # Pirate Bay if headphones.CONFIG.PIRATEBAY: provider = "The Pirate Bay" @@ -1907,6 +2010,8 @@ def preprocess(resultlist): headers['User-Agent'] = USER_AGENT elif result[3] == 'What.cd': headers['User-Agent'] = 'Headphones' + elif result[3] == 'PassTheHeadphones.me': + headers['User-Agent'] = 'Headphones' elif result[3] == "The Pirate Bay" or result[3] == "Old Pirate Bay": headers[ 'User-Agent'] = 'Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2243.2 Safari/537.36' diff --git a/headphones/webserve.py b/headphones/webserve.py index 9b09feba..368a5327 100644 --- a/headphones/webserve.py +++ b/headphones/webserve.py @@ -1228,6 +1228,12 @@ class WebInterface(object): "whatcd_username": headphones.CONFIG.WHATCD_USERNAME, "whatcd_password": headphones.CONFIG.WHATCD_PASSWORD, "whatcd_ratio": headphones.CONFIG.WHATCD_RATIO, + "whatcd_url": headphones.CONFIG.WHATCD_URL, + "use_pth": checked(headphones.CONFIG.PTH), + "pth_username": headphones.CONFIG.PTH_USERNAME, + "pth_password": headphones.CONFIG.PTH_PASSWORD, + "pth_ratio": headphones.CONFIG.PTH_RATIO, + "pth_url": headphones.CONFIG.PTH_URL, "use_strike": checked(headphones.CONFIG.STRIKE), "strike_ratio": headphones.CONFIG.STRIKE_RATIO, "use_tquattrecentonze": checked(headphones.CONFIG.TQUATTRECENTONZE), diff --git a/lib/pygazelle/api.py b/lib/pygazelle/api.py index b3dba2bb..92aac04e 100644 --- a/lib/pygazelle/api.py +++ b/lib/pygazelle/api.py @@ -42,7 +42,7 @@ class GazelleAPI(object): 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'} - def __init__(self, username=None, password=None): + def __init__(self, username=None, password=None, url=None): self.session = requests.session() self.session.headers = self.default_headers self.username = username @@ -59,7 +59,7 @@ class GazelleAPI(object): self.cached_torrents = {} self.cached_requests = {} self.cached_categories = {} - self.site = "https://what.cd/" + self.site = url + "/" self.past_request_timestamps = [] def wait_for_rate_limit(self): @@ -95,7 +95,7 @@ class GazelleAPI(object): self.wait_for_rate_limit() - loginpage = 'https://what.cd/login.php' + loginpage = self.site + 'login.php' data = {'username': self.username, 'password': self.password, 'keeplogged': '1'}