Skip to content

Instantly share code, notes, and snippets.

@werwolfby
Last active November 23, 2019 06:20
Show Gist options
  • Save werwolfby/bea8a01c1928c6d79ebf86d621119da5 to your computer and use it in GitHub Desktop.
Save werwolfby/bea8a01c1928c6d79ebf86d621119da5 to your computer and use it in GitHub Desktop.
Transmission Helper
import logging
__author__ = 'WerWolf'
def trace(logger, level=logging.INFO):
def wrapped(func):
def tmp(*args, **kwargs):
if logger.isEnabledFor(level):
logger.log(level, "Start %s" % func.__name__)
try:
return func(*args, **kwargs)
finally:
if logger.isEnabledFor(level):
logger.log(level, "End %s" % func.__name__)
return tmp
return wrapped
__author__ = 'WerWolf'
from transmissionrpc import Client
from operator import attrgetter
from argparse import ArgumentParser
import logging
from Tracer import trace
MESSAGE = logging.INFO + 5
logging.addLevelName(MESSAGE, 'MESSAGE')
def message(self, message, *args, **kwargs):
self._log(MESSAGE, message, args, **kwargs)
logging.Logger.message = message
log = logging.getLogger('transmission-helper')
def _getHashStrings(torrents):
return [t.hashString for t in torrents]
def _printInfo(action, torrents):
for t in torrents:
log.message("%s %s %f" % (action, t.name, t.ratio))
@trace(log)
def clear(client, ratio, include_seeding):
"""
Remove stopped torrents with ratio more that 'ratio' param
:type client: Client
:type ratio: float
:type include_seeding: bool
"""
def isForRemove(t):
if t.leftUntilDone > 0:
return False
if t.ratio < ratio:
return False
if t.status == 'seeding' and include_seeding:
return True
if t.status == 'stopped':
return True
return False
torrents = sorted(client.get_torrents(arguments=['id', 'name', 'hashString', 'addedDate', 'status', 'isFinished', 'uploadRatio', 'sizeWhenDone', 'leftUntilDone']),
key=attrgetter('date_added'))
torrents = filter(isForRemove, torrents)
if len(torrents) > 0:
_printInfo('Delete', torrents)
client.remove_torrent(_getHashStrings(torrents))
@trace(log)
def resume(client):
"""
Resume all not finished torrents
:type client: Client
"""
# addedDate is name of property of Transmission RPC ape, but the same property name of Torrent class is date_added
# this inconsistency can be confused
torrents = sorted(client.get_torrents(arguments=['id', 'name', 'hashString', 'addedDate', 'status', 'isFinished', 'uploadRatio']),
key=attrgetter('date_added'))
torrents = [t for t in torrents if t.status == 'stopped' and not t.isFinished]
if len(torrents) > 0:
_printInfo('Resume', torrents)
client.start_torrent(_getHashStrings(torrents))
@trace(log)
def truncate(client, count):
"""
Truncate amount of torrents to specific value, by removing old one
:type client: Client
"""
torrents = sorted(client.get_torrents(arguments=['id', 'name', 'hashString', 'addedDate', 'status', 'uploadRatio']),
key=attrgetter('date_added'))
torrents = torrents[:(max([len(torrents) - count, 0]))]
if len(torrents) > 0:
_printInfo('Delete', torrents)
client.remove_torrent(_getHashStrings(torrents))
config_parser = ArgumentParser(add_help=False)
config_parser.add_argument('-c', '--config', type=str)
parser = ArgumentParser(parents=[config_parser])
subparsers = parser.add_subparsers()
clear_parser = subparsers.add_parser('clear', help='Remove finished torrents with ration > threshold parameter')
clear_parser.add_argument('-r', '--ratio', type=float, default=1.5)
clear_parser.add_argument('-s', '--seeding', action='store_true', help="include seeding", dest='include_seeding')
clear_parser.set_defaults(func=clear)
resume_parser = subparsers.add_parser('resume', help='Resume all not finished paused torrents')
resume_parser.set_defaults(func=resume)
truncate_parser = subparsers.add_parser('truncate', help='Truncate amount of torrents, by removing old ones')
truncate_parser.add_argument('count', type=int, default=30)
truncate_parser.set_defaults(func=truncate)
parser.add_argument('-a', '--address', type=str)
parser.add_argument('-u', '--user', type=str)
parser.add_argument('-p', '--password', type=str)
args, remaining_argv = config_parser.parse_known_args()
defaults = {}
if args.config:
from ConfigParser import SafeConfigParser
config = SafeConfigParser()
config.read(args.config)
defaults = dict(config.items('Settings'))
if config.has_section('loggers'):
import logging.config
logging.config.fileConfig(args.config)
parser.set_defaults(**defaults)
args = parser.parse_args(remaining_argv)
delattr(args, 'config')
func = args.__dict__.pop('func')
for k in args.__dict__.iterkeys():
if not args.__dict__[k]:
parser.error('argument %s should be specified in args or in config file' % k)
client = Client(address=args.__dict__.pop('address'), user=args.__dict__.pop('user'), password=args.__dict__.pop('password'))
func(client, **args.__dict__)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment