Python script for adding torrents

Discussion of the Web Interface for Transmission, formerly known as Clutch. This applies to all version of Transmission
Post Reply
at0m13
Posts: 1
Joined: Mon Apr 20, 2009 6:22 am

Python script for adding torrents

Post by at0m13 »

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).

Code: Select all

#!/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])
mmaura
Posts: 2
Joined: Sat Sep 12, 2009 9:07 am

Re: Python script for adding torrents

Post by mmaura »

Your script is interesting but is not woring for me.

at line 23 i have put :

Code: Select all

    conn.request('POST', '/transmission/rpc', body, headers)

    r1 = conn.getresponse()
    print r1.status, r1.reason
    data1 = r1.read()
    print data1

    conn.close()

the answer is :

Code: Select all

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>


i dont understand whats happen...
guigouz
Posts: 1
Joined: Sat Nov 12, 2011 8:11 pm

Re: Python script for adding torrents

Post by guigouz »

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.
killemov
Posts: 542
Joined: Sat Jul 31, 2010 5:04 pm

Re: Python script for adding torrents

Post by killemov »

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.
VoXqWBqQME6WtI
Posts: 13
Joined: Tue Jan 26, 2010 10:16 am

Re: Python script for adding torrents

Post by VoXqWBqQME6WtI »

Code: Select all

#!/usr/bin/python3
#
# Simple magnet link uploader
#
# Needs httplib2: http://code.google.com/p/httplib2/
#

import httplib2
from sys import argv, exit
from json import dumps

# is magnet link given in command line?
if len(argv) < 2: 
    print('Usage: magnet-handler.py "magnet link"')
    exit(1)

# Replace hostname, transmission-username and transmission-password
url = 'http://hostname:9091/transmission/rpc'
username = 'transmission-username'
password = 'transmission-password'

h = httplib2.Http(".cache")
h.add_credentials(username, password)
resp, content = h.request(url, "GET")

headers = { "X-Transmission-Session-Id": resp['x-transmission-session-id'] }
body = dumps( { "method": "torrent-add",
                "arguments": { "filename": argv[1] } } )

response, content = h.request(url, 'POST', headers=headers, body=body)

if str(content).find("success") == -1:
    print("Magnet Link: " + argv[1])
    print("Answer: " + content)
    print("No 'success' here!")
    print("Press Enter to Exit.")
    input()
Simple script for magnet link uploading. Better or fixes are welcome.
lazybones
Posts: 220
Joined: Sun Jan 24, 2010 12:41 am

Re: Python script for adding torrents

Post by lazybones »

For building with python you might want to import this http://packages.python.org/transmissionrpc/
killemov
Posts: 542
Joined: Sat Jul 31, 2010 5:04 pm

Re: Python script for adding torrents

Post by killemov »

lazybones wrote:For building with python you might want to import this http://packages.python.org/transmissionrpc/
I would recommend against using this abstraction.
VoXqWBqQME6WtI
Posts: 13
Joined: Tue Jan 26, 2010 10:16 am

Re: Python script for adding torrents

Post by VoXqWBqQME6WtI »

Code: Select all

#!/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.
VoXqWBqQME6WtI
Posts: 13
Joined: Tue Jan 26, 2010 10:16 am

Re: Python script for adding torrents

Post by VoXqWBqQME6WtI »

Code: Select all

#!/usr/bin/python3
#
# Transmission magnet link uploader
# (https cert check disabled)
#
# Uses requests & PyQt5
# http://docs.python-requests.org/en/latest/
# http://www.riverbankcomputing.co.uk/software/pyqt/download5
#

# Standard
from json import dumps
from sys import argv, exit
from urllib.parse import unquote

# 3rd Party
import requests
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import (QApplication, QMessageBox, QSystemTrayIcon)

# Settings
url = 'https://address.domain:port/transmission/rpc'
username = 'transmission'
password = 'secret'
icon = 'C:\\Icons\\Magnet-icon.png'

# Functions

# Show Message Box
def show_message(title, message):
    app = QApplication([])
    QMessageBox.information(None, title, message)

# Show Tray Message
def show_tray_message(title, message):
    app = QApplication([])
    trayIcon = QSystemTrayIcon(QIcon(icon), app)
    trayIcon.show()
    trayIcon.showMessage(title, message, QSystemTrayIcon.Information)
    QTimer.singleShot(8000, app.quit)
    app.exec_()

# Get RPC Session ID
def get_session_id():
    sessionid_request = requests.get(url, auth=(username, password), verify=False)
    return sessionid_request.headers['x-transmission-session-id']

# Post Magnet Link
def post_link(magnetlink):
    sessionid = get_session_id()
    if sessionid:
        headers = {"X-Transmission-Session-Id": sessionid}
        body = dumps({"method": "torrent-add", "arguments": {"filename": magnetlink}})
        post_request = requests.post(url, data=body, headers=headers, auth=(username, password), verify=False)
        if str(post_request.text).find("success") == -1:
            title =  argv[0] + ' - Error'
            message = 'Magnet Link: ' + magnetlink + '\nAnswer: ' + post_request.text
            show_message(title, message)
        else:
            message = '\n'.join(names) + '\n' + '\n'.join(trackers)
            show_tray_message('Magnet Link Added', message)

# End of Functions

# Main prog
if __name__ == '__main__':

    # Check Argument and Extract 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)
    
    post_link(argv[1])
Switched httplib2 to requests and update to pyqt5.
Post Reply