I wrote a short script for adding torrents to the Transmission web UI easily. You can either set it as the helper for torrent files for your browser (Preferences -> Applications ->TORRENT file and 'Use other...' in Firefox) or if you use GNOME, you can copy or link it into ~/.gnome2/nautilus-scripts, select some torrent files in Nautilus and select this script under Scripts in the right click menu. Don't forget to set TRANSMISSION_HOST and NAME_COLON_PASSWORD (set it to None if you don't use authentication).
#!/usr/bin/env python
from __future__ import with_statement
from sys import argv
from os import environ
from base64 import b64encode
from json import dumps
from httplib import HTTPConnection
# Change these!
TRANSMISSION_HOST = '<hostname>'
NAME_COLON_PASSWORD = '<username>:<password>'
#NAME_COLON_PASSWORD = None
def addtorrent(filename):
if not filename.endswith('.torrent'):
return
with open(filename, 'rb') as f:
metainfo = b64encode(f.read())
headers = NAME_COLON_PASSWORD and {'Authorization': 'Basic ' + b64encode(NAME_COLON_PASSWORD)} or {}
body = dumps({'method': 'torrent-add', 'arguments': {'metainfo': metainfo}})
conn = HTTPConnection(TRANSMISSION_HOST)
conn.request('POST', '/transmission/rpc', body, headers)
conn.close()
if 'NAUTILUS_SCRIPT_SELECTED_FILE_PATHS' in environ:
for filename in environ['NAUTILUS_SCRIPT_SELECTED_FILE_PATHS'].split('\n'):
addtorrent(filename)
elif len(argv) == 2:
addtorrent(argv[1])
409 Conflict
<h1>409: Conflict</h1><p>Your request had an invalid session-id header.</p><p>To fix this, follow these steps:<ol><li> When reading a response, get its X-Transmission-Session-Id header and remember it<li> Add the updated header to your outgoing requests<li> When you get this 409 error message, resend your request with the updated header</ol></p><p>This requirement has been added to help prevent <a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF</a> attacks.</p><p><code>X-Transmission-Session-Id: oFwhq3Rul8Eqs9PHODU6Ga6OxuvgvKGghrf62KgePKD6aV6v</code></p>
From the RPC docs -
+2.4. CSRF Protection
+
+ Most Transmission RPC servers require a X-Transmission-Session-Id
+ header to be sent with requests, to prevent CSRF attacks.
+
+ When your request has the wrong id -- such as when you send your first
+ request, or when the server expires the CSRF token -- the
+ Transmission RPC server will return an HTTP 409 error with the
+ right X-Transmission-Session-Id in its own headers.
+
+ So, the correct way to handle a 409 response is to update your
+ X-Transmission-Session-Id and to resend the previous request.
guigouz wrote:From the RPC docs -
+ So, the correct way to handle a 409 response is to update your
+ X-Transmission-Session-Id and to resend the previous request.
So add updating the request header in the Python script, if at all possible, or trash the script.
#!/usr/bin/python3
#
# Transmission magnet link uploader
#
# Uses httplib2 & PyQt4
# http://code.google.com/p/httplib2/
# http://www.riverbankcomputing.co.uk/software/pyqt/download
#
# Standard
from json import dumps
from sys import argv, exit
from urllib.parse import unquote
# 3rd Party
import httplib2
from PyQt4 import QtGui, QtCore
# Settings
url = 'https://my.server.inet:19091/transmission/rpc'
username = 'transmission'
password = 'password'
icon = 'C:\\Scripts\\Magnet-icon.png'
# Functions
# Show Message Box
def show_message(title, message):
app = QtGui.QApplication([])
QtGui.QMessageBox.information(None, title, message)
# Show Tray Message
def show_tray_message(title, message):
app = QtGui.QApplication([])
trayIcon = QtGui.QSystemTrayIcon(QtGui.QIcon(icon), app)
trayIcon.show()
trayIcon.showMessage(title, message, QtGui.QSystemTrayIcon.Information)
QtCore.QTimer.singleShot(8000, app.quit)
app.exec_()
# Get RPC Session ID
def get_session_id():
global handle
handle.add_credentials(username, password)
resp, content = handle.request(url, "GET")
return resp['x-transmission-session-id']
# Post Magnet Link
def post_link(magnetlink):
sessionid = get_session_id()
if sessionid:
global handle
headers = {"X-Transmission-Session-Id": sessionid}
body = dumps({"method": "torrent-add", "arguments": {"filename": magnetlink}})
response, content = handle.request(url, 'POST', headers=headers, body=body)
if str(content).find("success") == -1:
title = argv[0] + ' - Error'
message = 'Magnet Link: ' + magnetlink + '\nAnswer: ' + content
show_message(title, message)
else:
message = '\n'.join(names) + '\n' + '\n'.join(trackers)
show_tray_message('Magnet Link Added', message)
# End of Functions
# Check Argument and Decode Name/Trackers or Display Alert Message
if len(argv) < 2:
show_message(argv[0] + ' - Alert', 'Usage: ' + argv[0] + ' [magnet link]')
exit(1)
elif argv[1].startswith('magnet'):
names = []
trackers = []
for item in argv[1].split('&'):
decoded = unquote(item)
if decoded.startswith('dn='):
names.append(decoded.replace('dn=', ''))
if decoded.startswith('tr='):
trackers.append(decoded.replace('tr=', ''))
else:
show_message(argv[0] + ' - Alert', argv[1] + ' not magnet link!')
exit(1)
# Global Handle
handle = httplib2.Http(".cache")
post_link(argv[1])
Second version, ugly but working, shows tray message when adding magnet links. I use it in Win7 with Firefox, transmission is behind lighttpd SSL proxy.