mirror of
https://github.com/rembo10/headphones.git
synced 2026-05-16 08:35:32 +01:00
Transmission API working
This commit is contained in:
@@ -198,7 +198,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<label>Transmission Password:</label>
|
||||
<input type="text" name="transmission_password" value="${config['transmission_pass']}" size="30">
|
||||
<input type="password" name="transmission_password" value="${config['transmission_pass']}" size="30">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset id="utorrent_options">
|
||||
@@ -337,7 +337,7 @@
|
||||
<fieldset>
|
||||
<legend>Torrents</legend>
|
||||
<div class="row checkbox">
|
||||
<input type="checkbox" name="use_piratebay" value="1" ${config['use_piratebay']} /><label>Pirate Bay</label>
|
||||
<input type="checkbox" name="use_piratebay" value="1" ${config['use_piratebay']} /><label>The Pirate Bay</label>
|
||||
</div>
|
||||
<div class="row checkbox">
|
||||
<input type="checkbox" name="use_isohunt" value="1" ${config['use_isohunt']} /><label>Isohunt</label>
|
||||
|
||||
@@ -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: <a href="%s">%s</a> - %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]
|
||||
|
||||
@@ -13,4 +13,80 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
|
||||
@@ -13,4 +13,98 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Headphones. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## 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("<div.*?>(.*?)</", request.read())[0]
|
||||
return token
|
||||
|
||||
def add_torrent_uri(self, torrent):
|
||||
action = "action=add-url&s=%s" % urllib.quote(torrent)
|
||||
return self._request(action)
|
||||
|
||||
def add_torrent_file(self, filename, filedata):
|
||||
action = "action=add-file"
|
||||
return self._request(action, {"torrent_file": (ss(filename), filedata)})
|
||||
|
||||
def set_torrent(self, hash, params):
|
||||
action = "action=setprops&hash=%s" % hash
|
||||
for k, v in params.iteritems():
|
||||
action += "&s=%s&v=%s" % (k, v)
|
||||
return self._request(action)
|
||||
|
||||
def pause_torrent(self, hash):
|
||||
action = "action=pause&hash=%s" % hash
|
||||
return self._request(action)
|
||||
|
||||
def get_status(self):
|
||||
action = "list=1"
|
||||
return self._request(action)
|
||||
|
||||
def get_settings(self):
|
||||
action = "action=getsettings"
|
||||
settings_dict = {}
|
||||
try:
|
||||
utorrent_settings = json.loads(self._request(action))
|
||||
|
||||
# Create settings dict
|
||||
for item in utorrent_settings['settings']:
|
||||
if item[1] == 0: # int
|
||||
settings_dict[item[0]] = int(item[2] if not item[2].strip() == '' else '0')
|
||||
elif item[1] == 1: # bool
|
||||
settings_dict[item[0]] = True if item[2] == 'true' else False
|
||||
elif item[1] == 2: # string
|
||||
settings_dict[item[0]] = item[2]
|
||||
|
||||
#log.debug('uTorrent settings: %s', settings_dict)
|
||||
|
||||
except Exception, err:
|
||||
log.error('Failed to get settings from uTorrent: %s', err)
|
||||
|
||||
return settings_dict
|
||||
|
||||
Reference in New Issue
Block a user