Last active
November 23, 2019 06:20
-
-
Save werwolfby/bea8a01c1928c6d79ebf86d621119da5 to your computer and use it in GitHub Desktop.
Transmission Helper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__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