diff --git a/headphones/postprocessor.py b/headphones/postprocessor.py index 27b3a25b..84055452 100644 --- a/headphones/postprocessor.py +++ b/headphones/postprocessor.py @@ -162,7 +162,7 @@ def verify(albumid, albumpath, Kind=None, forced=False): elif files.lower().endswith('.cue'): downloaded_cuecount += 1 # if any of the files end in *.part, we know the torrent isn't done yet. Process if forced, though - elif files.lower().endswith('.part') and not forced: + elif files.lower().endswith(('.part', '.utpart')) and not forced: logger.info("Looks like " + os.path.basename(albumpath).decode(headphones.SYS_ENCODING, 'replace') + " isn't complete yet. Will try again on the next run") return diff --git a/headphones/searcher.py b/headphones/searcher.py index f3565688..9308d3bb 100644 --- a/headphones/searcher.py +++ b/headphones/searcher.py @@ -715,7 +715,7 @@ def send_to_downloader(data, bestqual, album): # rutracker needs cookies to be set, pass the .torrent file instead of url if bestqual[3] == 'rutracker.org': - file_or_url = rutracker.get_torrent(bestqual[2]) + file_or_url, _hash = rutracker.get_torrent(bestqual[2]) else: file_or_url = bestqual[2] @@ -744,13 +744,14 @@ def send_to_downloader(data, bestqual, album): # rutracker needs cookies to be set, pass the .torrent file instead of url if bestqual[3] == 'rutracker.org': - file_or_url = rutracker.get_torrent(bestqual[2]) + file_or_url, _hash = rutracker.get_torrent(bestqual[2]) + folder_name, cacheid = utorrent.dirTorrent(_hash) + folder_name = os.path.basename(os.path.normpath(folder_name)) + utorrent.labelTorrent(_hash) else: file_or_url = bestqual[2] - - _hash = CalculateTorrentHash(file_or_url, data) - - folder_name = utorrent.addTorrent(file_or_url, _hash) + _hash = CalculateTorrentHash(file_or_url, data) + folder_name = utorrent.addTorrent(file_or_url, _hash) if folder_name: logger.info('Torrent folder name: %s' % folder_name) @@ -1437,7 +1438,7 @@ def preprocess(resultlist): return request.request_content(url=result[2], headers=headers), result def CalculateTorrentHash(link, data): - + if link.startswith('magnet'): tor_hash = re.findall('urn:btih:([\w]{32,40})', link)[0] if len(tor_hash) == 32: diff --git a/headphones/searcher_rutracker.py b/headphones/searcher_rutracker.py index dffb638b..edb2d10d 100644 --- a/headphones/searcher_rutracker.py +++ b/headphones/searcher_rutracker.py @@ -10,10 +10,13 @@ import cookielib from urlparse import urlparse from bs4 import BeautifulSoup import headphones -from headphones import logger, db -import lib.bencode as bencode +from headphones import logger, db, utorrent +from lib.bencode import bencode as bencode, bdecode import os from tempfile import mkdtemp +from hashlib import sha1 +import requests +import re class Rutracker(): @@ -189,7 +192,7 @@ class Rutracker(): page = self.opener.open(url) torrent = page.read() if torrent: - decoded = bencode.bdecode(torrent) + decoded = bdecode(torrent) metainfo = decoded['info'] page.close () except Exception, e: @@ -275,6 +278,9 @@ class Rutracker(): prev = os.umask(headphones.UMASK) page = self.opener.open(downloadurl) torrent = page.read() + decoded = bdecode(torrent) + metainfo = decoded['info'] + tor_hash = sha1(bencode(metainfo)).hexdigest() if savelocation: download_path = os.path.join(savelocation, torrent_name) else: @@ -284,8 +290,61 @@ class Rutracker(): fp.write (torrent) fp.close () os.umask(prev) + + # Add file to utorrent + if headphones.TORRENT_DOWNLOADER == 2: + self.utorrent_add_file(download_path) + except Exception, e: logger.error('Error getting torrent: %s' % e) return False - return download_path + return download_path, tor_hash + + #TODO get this working in utorrent.py + def utorrent_add_file(self, filename): + + host = headphones.UTORRENT_HOST + if not host.startswith('http'): + host = 'http://' + host + if host.endswith('/'): + host = host[:-1] + if host.endswith('/gui'): + host = host[:-4] + + base_url = host + username = headphones.UTORRENT_USERNAME + password = headphones.UTORRENT_PASSWORD + + session = requests.Session() + url = base_url + '/gui/' + session.auth = (username, password) + + try: + r = session.get(url + 'token.html') + except: + logger.debug('Error getting token') + return + if r.status_code == '401': + logger.debug('Error reaching utorrent') + return + + regex = re.search(r'.+>([^<]+)', r.text) + if regex is None: + logger.debug('Error reading token') + return + + session.params = {'token': regex.group(1)} + + params = {'action': 'add-file'} + f = open(filename, 'rb') + files = {'torrent_file': f} + + try: + session.post(url, params=params, files=files) + except: + logger.debug('Error adding file to utorrent') + return + finally: + f.close() + diff --git a/headphones/utorrent.py b/headphones/utorrent.py index b03acdf2..12d68c7a 100644 --- a/headphones/utorrent.py +++ b/headphones/utorrent.py @@ -19,11 +19,17 @@ import json, re, os, time import headphones from headphones import logger +from collections import namedtuple +import requests +import re + class utorrentclient(object): - TOKEN_REGEX = "" - def __init__(self, base_url = None, username = None, password = None,): + TOKEN_REGEX = "" + UTSetting = namedtuple("UTSetting", ["name", "int", "str", "access"]) + + def __init__(self, base_url = None, username = None, password = None,): host = headphones.UTORRENT_HOST if not host.startswith('http'): @@ -119,6 +125,16 @@ class utorrentclient(object): return self._action(params) + def get_settings(self, key=None): + params = [('action', 'getsettings'), ] + status, value = self._action(params) + settings = {} + for args in value['settings']: + settings[args[0]] = self.UTSetting(*args) + if key: + return settings[key] + return settings + def _action(self, params, body=None, content_type=None): url = self.base_url + '/gui/' + '?token=' + self.token + '&' + urllib.urlencode(params) request = urllib2.Request(url) @@ -136,31 +152,63 @@ class utorrentclient(object): logger.debug('URL: ' + str(url)) logger.debug('uTorrent webUI raised the following error: ' + str(err)) - def labelTorrent(hash): label = headphones.UTORRENT_LABEL uTorrentClient = utorrentclient() - settinglabel = True - while settinglabel: - torrentList = uTorrentClient.list() - for torrent in torrentList[1].get('torrents'): - if (torrent[0].lower() == hash): - uTorrentClient.setprops(hash,'label',label) - settinglabel = False - return True + if label: + uTorrentClient.setprops(hash,'label',label) +def dirTorrent(hash, cacheid=None): -def dirTorrent(hash): uTorrentClient = utorrentclient() - torrentList = uTorrentClient.list() - for torrent in torrentList[1].get('torrents'): - if (torrent[0].lower() == hash): - return torrent[26] - return False + if not cacheid: + status, torrentList = uTorrentClient.list() + else: + params = [('list', '1'), ('cid', cacheid)] + status, torrentList = uTorrentClient._action(params) + + if 'torrentp' in torrentList: + torrents = torrentList['torrentp'] + else: + torrents = torrentList['torrents'] + + cacheid = torrentList['torrentc'] + + for torrent in torrents: + if (torrent[0].lower() == hash): + return torrent[26], cacheid + + return None, None def addTorrent(link, hash): uTorrentClient = utorrentclient() + + # Get Active Directory from settings + active_dir, completed_dir = getSettingsDirectories() + uTorrentClient.add_url(link) - labelTorrent(hash) - return dirTorrent(hash) + + # Get Torrent Folder Name + torrent_folder, cacheid = dirTorrent(hash) + + # If there's no folder yet then it's probably a magnet, try until folder is populated + if torrent_folder == active_dir or not torrent_folder: + tries = 1 + while (torrent_folder == active_dir or torrent_folder == None) and tries <= 10: + tries += 1 + time.sleep(6) + torrent_folder, cacheid = dirTorrent(hash, cacheid) + + if torrent_folder == active_dir: + return None + else: + labelTorrent(hash) + return os.path.basename(os.path.normpath(torrent_folder)) + +def getSettingsDirectories(): + uTorrentClient = utorrentclient() + settings = uTorrentClient.get_settings() + active = settings['dir_active_download'][2] + completed = settings['dir_completed_download'][2] + return active, completed