hardlink solution for uTorrent

This commit is contained in:
Joel Kåberg 2013-02-25 11:02:51 +01:00
parent 2dcf0ef2af
commit 48c8b44bd3
8 changed files with 224 additions and 2 deletions

View file

@ -7,14 +7,18 @@ import os
import shutil import shutil
import logging import logging
import datetime import datetime
import time
import urllib2
from subprocess import call from subprocess import call
# Custom imports # Custom imports
import linktastic.linktastic as linktastic import linktastic.linktastic as linktastic
import autoProcessMovie import autoProcessMovie
import autoProcessTV import autoProcessTV
from nzbToMediaEnv import * from nzbToMediaEnv import *
from nzbToMediaUtil import * from nzbToMediaUtil import *
from utorrent.client import UTorrentClient
nzbtomedia_configure_logging(os.path.dirname(sys.argv[0])) nzbtomedia_configure_logging(os.path.dirname(sys.argv[0]))
Logger = logging.getLogger(__name__) Logger = logging.getLogger(__name__)
@ -272,7 +276,7 @@ if len(sys.argv) == 2: #for other clients we assume we must at least get the dir
inputName = '' # We dont have a name yet inputName = '' # We dont have a name yet
inputCategory = '' # We dont have a category yet inputCategory = '' # We dont have a category yet
elif len(sys.argv) > 3 and sys.argv[1] == 'utorrent': #distinguish utorrent from others like deluge. elif len(sys.argv) > 4 and sys.argv[1] == 'utorrent': #distinguish utorrent from others like deluge.
# We will pass in 'utorrent' '%D', '%N', and '%L' (if it exists), from uTorrent # We will pass in 'utorrent' '%D', '%N', and '%L' (if it exists), from uTorrent
# In short pass "/path/to/downloaded/torrent/ name" to TorrentToMedia.py, eg >>>> TorrentToMedia.py /Downloaded/MovieName.2013.BluRay.1080p.x264-10bit.DTS MovieName.2013.BluRay.1080p.x264-10bit.DTS <<<< # In short pass "/path/to/downloaded/torrent/ name" to TorrentToMedia.py, eg >>>> TorrentToMedia.py /Downloaded/MovieName.2013.BluRay.1080p.x264-10bit.DTS MovieName.2013.BluRay.1080p.x264-10bit.DTS <<<<
inputDirectory = os.path.normpath(sys.argv[2]) inputDirectory = os.path.normpath(sys.argv[2])
@ -281,6 +285,7 @@ elif len(sys.argv) > 3 and sys.argv[1] == 'utorrent': #distinguish utorrent from
inputCategory = sys.argv[4] # We dont have a category yet inputCategory = sys.argv[4] # We dont have a category yet
except: except:
inputCategory = '' # We dont have a category yet inputCategory = '' # We dont have a category yet
inputHash = sys.argv[5]
elif len(sys.argv) == 4: elif len(sys.argv) == 4:
# We will assume this to be the passin from deluge. torrent id, torrent name, torrent save path. # We will assume this to be the passin from deluge. torrent id, torrent name, torrent save path.
@ -312,6 +317,9 @@ movieDestination = os.path.normpath(config.get("CouchPotato", "outputDirectory")
# Torrent specific # Torrent specific
useLink = int(config.get("Torrent", "useLink")) useLink = int(config.get("Torrent", "useLink"))
extractionTool = os.path.normpath(config.get("Torrent", "extractionTool")) extractionTool = os.path.normpath(config.get("Torrent", "extractionTool"))
uTorrentWEBui = config.get("Torrent", "uTorrentWEBui")
uTorrentUSR = config.get("Torrent", "uTorrentUSR")
uTorrentPWD = config.get("Torrent", "uTorrentPWD")
compressedContainer = (config.get("Torrent", "compressedExtentions")).split(',') compressedContainer = (config.get("Torrent", "compressedExtentions")).split(',')
mediaContainer = (config.get("Torrent", "mediaExtentions")).split(',') mediaContainer = (config.get("Torrent", "mediaExtentions")).split(',')
metaContainer = (config.get("Torrent", "metaExtentions")).split(',') metaContainer = (config.get("Torrent", "metaExtentions")).split(',')
@ -429,11 +437,26 @@ old_stdout = sys.stdout # Still crude, but we wat to capture this for now
logFile = os.path.join(os.path.dirname(sys.argv[0]), "postprocess.log") logFile = os.path.join(os.path.dirname(sys.argv[0]), "postprocess.log")
log_file = open(logFile,"a+") log_file = open(logFile,"a+")
sys.stdout = log_file sys.stdout = log_file
if inputCategory == movieCategory:
# Hardlink solution with uTorrent
if inputHash and useLink:
Logger.debug("MAIN: We are using hardlinks with uTorrent, calling uTorrent to pause download")
utorrentClass = UTorrentClient(uTorrentWEBui, uTorrentUSR, uTorrentPWD)
utorrentClass.stop(inputHash)
time.sleep(10)
if inputCategory == movieCategory:
Logger.info("MAIN: Calling postprocessing script for CouchPotatoServer") Logger.info("MAIN: Calling postprocessing script for CouchPotatoServer")
autoProcessMovie.process(outputDestination, inputName, status) autoProcessMovie.process(outputDestination, inputName, status)
elif inputCategory == tvCategory: elif inputCategory == tvCategory:
Logger.info("MAIN: Calling postprocessing script for Sick-Beard") Logger.info("MAIN: Calling postprocessing script for Sick-Beard")
autoProcessTV.processEpisode(outputDestination, inputName, status) autoProcessTV.processEpisode(outputDestination, inputName, status)
# Hardlink solution with uTorrent
if inputHash and useLink:
Logger.debug("MAIN: We are using hardlinks with uTorrent, calling uTorrent to resume download")
utorrentClass.start(inputHash)
time.sleep(10)
sys.stdout = old_stdout sys.stdout = old_stdout
log_file.close() log_file.close()

View file

@ -31,6 +31,10 @@ failed_fork=0
useLink = 0 useLink = 0
extractionTool = C:\Program Files\7-Zip\7z.exe extractionTool = C:\Program Files\7-Zip\7z.exe
categories = music,music_videos,pictures,software categories = music,music_videos,pictures,software
###### uTorrent Hardlink solution (You must edit this if your using TorrentToMedia.py with uTorrent)
uTorrentWEBui = http://localhost:8090/gui/
uTorrentUSR = your username
uTorrentPWD = your password
###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ###### ###### ADVANCED USE - ONLY EDIT IF YOU KNOW WHAT YOU'RE DOING ######
compressedExtentions = .zip,.rar,.7z,.gz,.bz,.tar,.arj compressedExtentions = .zip,.rar,.7z,.gz,.bz,.tar,.arj
mediaExtentions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg,.vob,.iso mediaExtentions = .mkv,.avi,.divx,.xvid,.mov,.wmv,.mp4,.mpg,.mpeg,.vob,.iso

0
utorrent/__init__.py Normal file
View file

BIN
utorrent/__init__.pyc Normal file

Binary file not shown.

124
utorrent/client.py Normal file
View file

@ -0,0 +1,124 @@
#coding=utf8
import urllib
import urllib2
import urlparse
import cookielib
import re
import StringIO
try:
import json
except ImportError:
import simplejson as json
from upload import MultiPartForm
class UTorrentClient(object):
def __init__(self, base_url, username, password):
self.base_url = base_url
self.username = username
self.password = password
self.opener = self._make_opener('uTorrent', base_url, username, password)
self.token = self._get_token()
#TODO refresh token, when necessary
def _make_opener(self, realm, base_url, username, password):
'''uTorrent API need HTTP Basic Auth and cookie support for token verify.'''
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm=realm,
uri=base_url,
user=username,
passwd=password)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
cookie_jar = cookielib.CookieJar()
cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar)
handlers = [auth_handler, cookie_handler]
opener = urllib2.build_opener(*handlers)
return opener
def _get_token(self):
url = urlparse.urljoin(self.base_url, 'token.html')
response = self.opener.open(url)
token_re = "<div id='token' style='display:none;'>([^<>]+)</div>"
match = re.search(token_re, response.read())
return match.group(1)
def list(self, **kwargs):
params = [('list', '1')]
params += kwargs.items()
return self._action(params)
def start(self, *hashes):
params = [('action', 'start'),]
for hash in hashes:
params.append(('hash', hash))
return self._action(params)
def stop(self, *hashes):
params = [('action', 'stop'),]
for hash in hashes:
params.append(('hash', hash))
return self._action(params)
def pause(self, *hashes):
params = [('action', 'pause'),]
for hash in hashes:
params.append(('hash', hash))
return self._action(params)
def forcestart(self, *hashes):
params = [('action', 'forcestart'),]
for hash in hashes:
params.append(('hash', hash))
return self._action(params)
def getfiles(self, hash):
params = [('action', 'getfiles'), ('hash', hash)]
return self._action(params)
def getprops(self, hash):
params = [('action', 'getprops'), ('hash', hash)]
return self._action(params)
def setprio(self, hash, priority, *files):
params = [('action', 'setprio'), ('hash', hash), ('p', str(priority))]
for file_index in files:
params.append(('f', str(file_index)))
return self._action(params)
def addfile(self, filename, filepath=None, bytes=None):
params = [('action', 'add-file')]
form = MultiPartForm()
if filepath is not None:
file_handler = open(filepath)
else:
file_handler = StringIO.StringIO(bytes)
form.add_file('torrent_file', filename.encode('utf-8'), file_handler)
return self._action(params, str(form), form.get_content_type())
def _action(self, params, body=None, content_type=None):
#about token, see https://github.com/bittorrent/webui/wiki/TokenSystem
url = self.base_url + '?token=' + self.token + '&' + urllib.urlencode(params)
request = urllib2.Request(url)
if body:
request.add_data(body)
request.add_header('Content-length', len(body))
if content_type:
request.add_header('Content-type', content_type)
try:
response = self.opener.open(request)
return response.code, json.loads(response.read())
except urllib2.HTTPError,e:
raise

BIN
utorrent/client.pyc Normal file

Binary file not shown.

71
utorrent/upload.py Normal file
View file

@ -0,0 +1,71 @@
#code copied from http://www.doughellmann.com/PyMOTW/urllib2/
import itertools
import mimetools
import mimetypes
from cStringIO import StringIO
import urllib
import urllib2
class MultiPartForm(object):
"""Accumulate the data to be used when posting a form."""
def __init__(self):
self.form_fields = []
self.files = []
self.boundary = mimetools.choose_boundary()
return
def get_content_type(self):
return 'multipart/form-data; boundary=%s' % self.boundary
def add_field(self, name, value):
"""Add a simple field to the form data."""
self.form_fields.append((name, value))
return
def add_file(self, fieldname, filename, fileHandle, mimetype=None):
"""Add a file to be uploaded."""
body = fileHandle.read()
if mimetype is None:
mimetype = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
self.files.append((fieldname, filename, mimetype, body))
return
def __str__(self):
"""Return a string representing the form data, including attached files."""
# Build a list of lists, each containing "lines" of the
# request. Each part is separated by a boundary string.
# Once the list is built, return a string where each
# line is separated by '\r\n'.
parts = []
part_boundary = '--' + self.boundary
# Add the form fields
parts.extend(
[ part_boundary,
'Content-Disposition: form-data; name="%s"' % name,
'',
value,
]
for name, value in self.form_fields
)
# Add the files to upload
parts.extend(
[ part_boundary,
'Content-Disposition: file; name="%s"; filename="%s"' % \
(field_name, filename),
'Content-Type: %s' % content_type,
'',
body,
]
for field_name, filename, content_type, body in self.files
)
# Flatten the list and add closing boundary marker,
# then return CR+LF separated data
flattened = list(itertools.chain(*parts))
flattened.append('--' + self.boundary + '--')
flattened.append('')
return '\r\n'.join(flattened)

BIN
utorrent/upload.pyc Normal file

Binary file not shown.