This commit is contained in:
2022-03-07 23:52:01 +01:00
commit 24144bb550
25 changed files with 2323 additions and 0 deletions

52
src/scripts/derailleur-add Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016-2017 Mads Michelsen (mail@brokkr.net)
# This file is part of Derailleur.
# Derailleur is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
"""Torrent starter"""
import sys
import derailleur
def get_parsed_args():
'''Parses arguments and return them'''
parser = derailleur.args.start_parser()
parser.add_argument("torrent", nargs='*',
help="Magnet URL(s) or .torrent(s)")
parsed_args = derailleur.args.end_parser(parser)
return parsed_args
def start_torrent(config, client, logger, torrent):
'''For each torrent in nargs, hand it over'''
outcome = client.download(torrent, config['Add']['pause_when_added'])
if outcome:
logger.info(outcome)
else:
logger.error('ERROR : ' + 'Failed to add torrent')
def main():
'''Putting it all together'''
args = get_parsed_args()
config, validation = derailleur.config.get_config()
if validation['Connection'] is not True or validation['Add'] is not True:
sys.exit('ERROR : Missing configuration')
logger = derailleur.loggers.Logger('Add', config, validation)
client = derailleur.client.get_client(config)
if not client:
logger.error('ERROR : Connect to Transmission failed')
sys.exit(1)
for torrent in args.torrent:
start_torrent(config, client, logger, torrent)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass

81
src/scripts/derailleur-feed Executable file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016-2017 Mads Michelsen (mail@brokkr.net)
# This file is part of Derailleur.
# Derailleur is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
import sys
import feedparser
import derailleur
def get_parsed_args():
'''Parses arguments and return them'''
parser = derailleur.args.start_parser()
parsed_args = derailleur.args.end_parser(parser)
return parsed_args
def get_feed(config):
'''Parses feed and returns dictionary of entries'''
doc = feedparser.parse(config['Feed']['url'])
get_edic = lambda x: {'title': x.title, 'url': x.link, 'done': False}
feed_dic = {exml.id: get_edic(exml) for exml in doc.entries}
return feed_dic
def get_fresh(feed_dic, jar_dic):
'''Go through feed entries'''
done_entries = [eid for eid in jar_dic if jar_dic[eid]['done'] is True]
fresh_entries = [eid for eid in feed_dic if eid not in done_entries]
return fresh_entries
def start_torrent(config, client, logger, feed_dic, eid):
'''Start an entry from the feed'''
edic = feed_dic[eid]
outcome = client.download(edic['url'], config['Feed']['pause_when_added'])
if outcome:
edic['done'] = True
logger.info(outcome)
else:
logger.error('ERROR : Failed to add %s', edic['title'])
return edic
def main():
'''Putting it all together'''
_args = get_parsed_args()
config, validation = derailleur.config.get_config()
# note that defaults should ensure always-valid configs but bad user
# input (e.g. a string for a port number) may invalidate it.
if validation['Connection'] is not True or validation['Feed'] is not True:
sys.exit('ERROR : Missing configuration')
logger = derailleur.loggers.Logger('Feed', config, validation)
client = derailleur.client.get_client(config)
if not client:
logger.error('ERROR : Connect to Transmission failed')
sys.exit(1)
feed_dic = get_feed(config)
if not feed_dic:
logger.error('ERROR : Cannot find feed or feed empty')
sys.exit(1)
jar = derailleur.history.Jar(config, 'derailleur-feed.db')
jar_dic = jar.load()
if jar_dic is False:
logger.error('ERROR : Failure loading %s', jar.db_filepath)
sys.exit(1)
fresh_entries = get_fresh(feed_dic, jar_dic)
for eid in fresh_entries:
edic = start_torrent(config, client, logger, feed_dic, eid)
jar_dic[eid] = edic
success = jar.save(jar_dic)
if success is False:
logger.error('ERROR : Failure saving %s', jar.db_filepath)
sys.exit(1)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass

47
src/scripts/derailleur-manager Executable file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016-2017 Mads Michelsen (mail@brokkr.net)
# This file is part of Derailleur.
# Derailleur is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
"""Torrent manager script"""
import sys
import derailleur
def get_parsed_args():
'''Parses arguments and return them'''
parser = derailleur.args.start_parser()
parser.add_argument("-v", "--verbose", help="Get info on current torrents",
action="store_true")
parsed_args = derailleur.args.end_parser(parser)
return parsed_args
def main():
'''Putting it all together'''
args = get_parsed_args()
config, validation = derailleur.config.get_config()
if validation['Connection'] is not True or \
validation['Manager'] is not True:
sys.exit('ERROR : Missing configuration')
logger = derailleur.loggers.Logger('Manager', config, validation,
verbose=args.verbose)
client = derailleur.client.get_client(config)
if not client:
logger.error('ERROR : Connect to Transmission failed')
sys.exit(1)
jar = derailleur.history.Jar(config, 'derailleur-manager.db')
manager = derailleur.manager.Manager(config, client, logger, jar)
manager.check_torrents()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass

124
src/scripts/derailleur-postproc Executable file
View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright 2016-2017 Mads Michelsen (mail@brokkr.net)
# This file is part of Derailleur.
# Derailleur is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
import os
import sys
from collections import namedtuple
import derailleur
try:
from xbmcjson import XBMC
import requests.packages.urllib3.exceptions
except ImportError:
XBMC = None
TorrentInfo = namedtuple('torrent_info', 'ppath name hash')
def get_parsed_args():
'''Parses arguments and return them'''
parser = derailleur.args.start_parser()
parser.add_argument("-t", "--target", help='''Set a target manually '''
'''rather than relying on environmental variables''')
parsed_args = derailleur.args.end_parser(parser)
return parsed_args
def get_torrent_info(args):
'''Get Transmission info on target'''
if args.target:
target = os.path.abspath(args.target)
if not os.path.isdir(target) and not os.path.isfile(target):
sys.exit('ERROR : Not a valid target')
get_pp = lambda x: os.path.abspath(os.path.join(x, os.path.pardir))
torrent_info = TorrentInfo(ppath=get_pp(target),
name=os.path.basename(target),
hash='abcdef123456')
else:
try:
torrent_info = TorrentInfo(ppath=os.environ['TR_TORRENT_DIR'],
name=os.environ['TR_TORRENT_NAME'],
hash=os.environ['TR_TORRENT_HASH'])
except KeyError:
torrent_info = None
return torrent_info
def get_type(config, keywords, stats):
'''Get torrent type'''
module_dic = {
'tv': derailleur.postproc.tv,
'film': derailleur.postproc.film,
'music': derailleur.postproc.audio,
'audiobook': derailleur.postproc.audio
}
if stats.identity in keywords:
type_module = derailleur.postproc.keywords
type_path = os.path.join(config['Postproc']['base_path'],
stats.identity)
elif stats.identity == 'generic':
type_module = derailleur.postproc.generic
type_path = os.path.join(config['Postproc']['base_path'], 'default')
else:
type_module = module_dic[stats.identity]
type_path = config['Postproc']['base_path_' + stats.identity]
return (type_module, type_path)
def get_log_str(torrent, stats, move_errors):
'''Logging'''
log_str = "ERRORS ENCOUNTERED IN FILE OPERATION. " if move_errors else ""
log_str += "NAME: " + stats.torrent_name + ". TYPE: " + stats.identity
log_str += ". FILES: "
type_count = [x + " " + str(torrent.move_type_lst.count(x))
for x in set(torrent.move_type_lst)]
log_str += ", ".join(type_count)
common_path = os.path.commonprefix([x[1] for x in torrent.move_lst])
log_str += ". PARENT: " + os.path.dirname(common_path)
return log_str
def update_kodi(config, stats):
'''Update kodi library'''
url = 'http://' + config['Kodi']['host'] + ':' \
+ str(config['Kodi']['port']) + '/jsonrpc'
try:
kodi = XBMC(url, config['Kodi']['user'], config['Kodi']['password'])
except requests.packages.urllib3.exceptions.NewConnectionError:
sys.exit(11)
if stats.identity in ['tv', 'film']:
kodi.VideoLibrary.Scan()
if stats.identity in ['music']:
kodi.AudioLibrary.Scan()
def main():
'''Putting the whole thing together'''
args = get_parsed_args()
config, validation = derailleur.config.get_config()
if validation['Postproc'] != True:
sys.exit('ERROR : Config not valid')
logger = derailleur.loggers.Logger('Postproc', config, validation)
torrent_info = get_torrent_info(args)
if not torrent_info:
logger.error('ERROR : Could not access Transmission variables')
sys.exit(1)
keywords = config['Postproc']['keywords']
stats = derailleur.postproc.stats.Stats(keywords, torrent_info)
type_module, type_path = get_type(config, keywords, stats)
torrent = type_module.Torrent(config, stats, type_path)
torrent.manipulate()
move_errors = torrent.move_files()
log_str = get_log_str(torrent, stats, move_errors)
logger.info(log_str)
if XBMC and config['Kodi']['connect_to_kodi']:
update_kodi(config, stats)
sys.exit(0)
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass