mirror of
https://github.com/correl/Transmission-XBMC.git
synced 2024-11-25 03:00:15 +00:00
191 lines
5.9 KiB
Python
191 lines
5.9 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# Copyright (c) 2008-2010 Erik Svensson <erik.public@gmail.com>
|
||
|
# Licensed under the MIT license.
|
||
|
|
||
|
import sys, datetime
|
||
|
|
||
|
from transmissionrpc.constants import STATUS, PRIORITY
|
||
|
from transmissionrpc.utils import format_timedelta
|
||
|
|
||
|
class Torrent(object):
|
||
|
"""
|
||
|
Torrent is a class holding the data raceived from Transmission regarding a bittorrent transfer.
|
||
|
All fetched torrent fields are accessable through this class using attributes.
|
||
|
This class has a few convenience properties using the torrent data.
|
||
|
"""
|
||
|
|
||
|
def __init__(self, client, fields):
|
||
|
if 'id' not in fields:
|
||
|
raise ValueError('Torrent requires an id')
|
||
|
self.fields = {}
|
||
|
self.update(fields)
|
||
|
self.client = client
|
||
|
|
||
|
def _getNameString(self, codec=None):
|
||
|
if codec == None:
|
||
|
codec = sys.getdefaultencoding()
|
||
|
name = None
|
||
|
# try to find name
|
||
|
if 'name' in self.fields:
|
||
|
name = self.fields['name']
|
||
|
# if name is unicode, try to decode
|
||
|
if isinstance(name, unicode):
|
||
|
try:
|
||
|
name = name.encode(codec)
|
||
|
except UnicodeError:
|
||
|
name = None
|
||
|
return name
|
||
|
|
||
|
def __repr__(self):
|
||
|
tid = self.fields['id']
|
||
|
name = self._getNameString()
|
||
|
if isinstance(name, str):
|
||
|
return '<Torrent %d \"%s\">' % (tid, name)
|
||
|
else:
|
||
|
return '<Torrent %d>' % (tid)
|
||
|
|
||
|
def __str__(self):
|
||
|
name = self._getNameString()
|
||
|
if isinstance(name, str):
|
||
|
return 'Torrent \"%s\"' % (name)
|
||
|
else:
|
||
|
return 'Torrent'
|
||
|
|
||
|
def __copy__(self):
|
||
|
return Torrent(self.client, self.fields)
|
||
|
|
||
|
def update(self, other):
|
||
|
"""
|
||
|
Update the torrent data from a Transmission JSON-RPC arguments dictinary
|
||
|
"""
|
||
|
fields = None
|
||
|
if isinstance(other, dict):
|
||
|
fields = other
|
||
|
elif isinstance(other, Torrent):
|
||
|
fields = other.fields
|
||
|
else:
|
||
|
raise ValueError('Cannot update with supplied data')
|
||
|
for key, value in fields.iteritems():
|
||
|
self.fields[key.replace('-', '_')] = value
|
||
|
|
||
|
def files(self):
|
||
|
"""
|
||
|
Get list of files for this torrent.
|
||
|
|
||
|
This function returns a dictionary with file information for each file.
|
||
|
The file information is has following fields:
|
||
|
::
|
||
|
|
||
|
{
|
||
|
<file id>: {
|
||
|
'name': <file name>,
|
||
|
'size': <file size in bytes>,
|
||
|
'completed': <bytes completed>,
|
||
|
'priority': <priority ('high'|'normal'|'low')>,
|
||
|
'selected': <selected for download>
|
||
|
}
|
||
|
|
||
|
...
|
||
|
}
|
||
|
"""
|
||
|
result = {}
|
||
|
if 'files' in self.fields:
|
||
|
indicies = xrange(len(self.fields['files']))
|
||
|
files = self.fields['files']
|
||
|
priorities = self.fields['priorities']
|
||
|
wanted = self.fields['wanted']
|
||
|
for item in zip(indicies, files, priorities, wanted):
|
||
|
selected = True if item[3] else False
|
||
|
priority = PRIORITY[item[2]]
|
||
|
result[item[0]] = {
|
||
|
'selected': selected,
|
||
|
'priority': priority,
|
||
|
'size': item[1]['length'],
|
||
|
'name': item[1]['name'],
|
||
|
'completed': item[1]['bytesCompleted']}
|
||
|
return result
|
||
|
|
||
|
def __getattr__(self, name):
|
||
|
try:
|
||
|
return self.fields[name]
|
||
|
except KeyError:
|
||
|
raise AttributeError('No attribute %s' % name)
|
||
|
|
||
|
@property
|
||
|
def status(self):
|
||
|
"""
|
||
|
Returns the torrent status. Is either one of 'check pending', 'checking',
|
||
|
'downloading', 'seeding' or 'stopped'. The first two is related to
|
||
|
verification.
|
||
|
"""
|
||
|
return STATUS[self.fields['status']]
|
||
|
|
||
|
@property
|
||
|
def progress(self):
|
||
|
"""Get the download progress in percent."""
|
||
|
try:
|
||
|
return 100.0 * (self.fields['sizeWhenDone'] - self.fields['leftUntilDone']) / float(self.fields['sizeWhenDone'])
|
||
|
except ZeroDivisionError:
|
||
|
return 0.0
|
||
|
|
||
|
@property
|
||
|
def ratio(self):
|
||
|
"""Get the upload/download ratio."""
|
||
|
try:
|
||
|
return self.fields['uploadedEver'] / float(self.fields['downloadedEver'])
|
||
|
except ZeroDivisionError:
|
||
|
return 0.0
|
||
|
|
||
|
@property
|
||
|
def eta(self):
|
||
|
"""Get the "eta" as datetime.timedelta."""
|
||
|
eta = self.fields['eta']
|
||
|
if eta >= 0:
|
||
|
return datetime.timedelta(seconds=eta)
|
||
|
else:
|
||
|
ValueError('eta not valid')
|
||
|
|
||
|
@property
|
||
|
def date_active(self):
|
||
|
"""Get the attribute "activityDate" as datetime.datetime."""
|
||
|
return datetime.datetime.fromtimestamp(self.fields['activityDate'])
|
||
|
|
||
|
@property
|
||
|
def date_added(self):
|
||
|
"""Get the attribute "addedDate" as datetime.datetime."""
|
||
|
return datetime.datetime.fromtimestamp(self.fields['addedDate'])
|
||
|
|
||
|
@property
|
||
|
def date_started(self):
|
||
|
"""Get the attribute "startDate" as datetime.datetime."""
|
||
|
return datetime.datetime.fromtimestamp(self.fields['startDate'])
|
||
|
|
||
|
@property
|
||
|
def date_done(self):
|
||
|
"""Get the attribute "doneDate" as datetime.datetime."""
|
||
|
return datetime.datetime.fromtimestamp(self.fields['doneDate'])
|
||
|
|
||
|
def format_eta(self):
|
||
|
"""
|
||
|
Returns the attribute *eta* formatted as a string.
|
||
|
|
||
|
* If eta is -1 the result is 'not available'
|
||
|
* If eta is -2 the result is 'unknown'
|
||
|
* Otherwise eta is formatted as <days> <hours>:<minutes>:<seconds>.
|
||
|
"""
|
||
|
eta = self.fields['eta']
|
||
|
if eta == -1:
|
||
|
return 'not available'
|
||
|
elif eta == -2:
|
||
|
return 'unknown'
|
||
|
else:
|
||
|
return format_timedelta(self.eta)
|
||
|
|
||
|
@property
|
||
|
def priority(self):
|
||
|
"""
|
||
|
Get the priority as string.
|
||
|
Can be one of 'low', 'normal', 'high'.
|
||
|
"""
|
||
|
return PRIORITY[self.fields['bandwidthPriority']]
|