Merge branch 'DarkSir23-development' into development

This commit is contained in:
evilhero 2016-05-11 10:00:10 -04:00
commit 33a43262d2
7 changed files with 686 additions and 84 deletions

View File

@ -261,7 +261,7 @@
<td>
<fieldset>
<legend>Usenet</legend>
<input type="radio" name="nzb_downloader" id="nzb_downloader_sabnzbd" value="0" ${config['nzb_downloader_sabnzbd']}>Sabnzbd <input type="radio" name="nzb_downloader" id="nzb_downloader_nzbget" value="1" ${config['nzb_downloader_nzbget']}> NZBget <input type="radio" name="nzb_downloader" id="nzb_downloader_blackhole" value="2" ${config['nzb_downloader_blackhole']}>Black Hole
<input type="radio" name="nzb_downloader" id="nzb_downloader_sabnzbd" value="0" ${config['nzb_downloader_sabnzbd']}> Sabnzbd&nbsp;&nbsp;<input type="radio" name="nzb_downloader" id="nzb_downloader_nzbget" value="1" ${config['nzb_downloader_nzbget']}> NZBget&nbsp;&nbsp;<input type="radio" name="nzb_downloader" id="nzb_downloader_blackhole" value="2" ${config['nzb_downloader_blackhole']}> Black Hole
</fieldset>
<fieldset id="sabnzbd_options">
<div class="row">
@ -385,53 +385,123 @@
</td>
<td>
<legend>Torrents</legend>
<fieldset>
<div class="row checkbox">
<input id="enable_torrents" type="checkbox" onclick="initConfigCheckbox($(this));" name="enable_torrents" value=1 ${config['enable_torrents']} /><label>Use Torrents</label>
</div>
<div class="config">
<div class="row">
<fieldset>
<div class="row checkbox">
<input id="enable_torrents" type="checkbox" onclick="initConfigCheckbox($(this));" name="enable_torrents" value=1 ${config['enable_torrents']} /><label>Use Torrents</label>
</div>
<div class="config">
<div class="row">
<label>Minimum # of seeders</label>
<input type="text" name="minseeds" value="${config['minseeds']}" size="10">
</div>
<div class="row checkbox left clearfix">
<input id="torrent_local" type="checkbox" onclick="initConfigCheckbox($(this));" name="torrent_local" value=1 ${config['torrent_local']} /><label>Local Torrent Client</label>
</div>
<div class="config">
<div Class="row">
<label>Watch Directory</label>
<input type="text" name="local_watchdir" value="${config['local_watchdir']}" size="30"><br/>
<small>Local Folder your torrent client watches</small>
</div>
</div>
<div class="row checkbox left clearfix">
<input id="torrent_seedbox" type="checkbox" onclick="initConfigCheckbox($(this));" name="torrent_seedbox" value=1 ${config['torrent_seedbox']} /><label>Seedbox Client</label>
</div>
<div class="config">
<div class="row">
<label>Seedbox Host</label>
<input type="text" name="seedbox_host" value="${config['seedbox_host']}" size="30">
</div>
<div class="row">
<label>Seedbox Port (SFTP)</label>
<input type="text" name="seedbox_port" value="${config['seedbox_port']}" size="30">
</div>
<div class="row">
<label>Seedbox Username</label>
<input type="text" name="seedbox_user" value="${config['seedbox_user']}" size="30">
</div>
<div class="row">
<label>Seedbox Password</label>
<input type="password" name="seedbox_pass" value="${config['seedbox_pass']}" size="30">
</div>
<div class="row">
<label>Watch Directory</label>
<input type="text" name="seedbox_watchdir" value="${config['seedbox_watchdir']}" size="30"><br/>
<small>Folder path your torrent seedbox client watches</small>
</div>
</div>
</div>
</fieldset>
<input type="radio" name="torrent_downloader" id="torrent_downloader_watchlist" value="0" ${config['torrent_downloader_watchlist']}> Watchdir&nbsp;&nbsp;
<input type="radio" name="torrent_downloader" id="torrent_downloader_utorrent" value="1" ${config['torrent_downloader_utorrent']}> uTorrent&nbsp;&nbsp;
<input type="radio" name="torrent_downloader" id="torrent_downloader_rtorrent" value="2" ${config['torrent_downloader_rtorrent']}> rTorrent&nbsp;&nbsp;
<!--<input type="radio" name="torrent_downloader" id="torrent_downloader_transmission" value="3" ${config['torrent_downloader_transmission']}> Transmission-->
</div>
</fieldset>
<fieldset id="watchlist_options">
<div class="row checkbox left clearfix">
<input id="local_watchdir" type="checkbox" name="torrent_local" value="1" ${config['torrent_local']} /><label>Local Watch dir</label>
</div>
<div id="watchdir_local_options">
<div class="row">
<label>Watch Directory</label>
<input type="text" name="local_watchdir" value="${config['local_watchdir']}" size="30"><br/>
<small>Local Folder your torrent client watches</small>
</div>
</div>
<div class="row checkbox left clearfix">
<input id="remote_watchdir" type="checkbox" name="torrent_seedbox" value="1" ${config['torrent_seedbox']} /><label>Remote Watch dir</label>
</div>
<div id="watchdir_remote_options">
<div class="row">
<label>Seedbox Host</label>
<input type="text" name="seedbox_host" value="${config['seedbox_host']}" size="30">
</div>
<div class="row">
<label>Seedbox Port (SFTP)</label>
<input type="text" name="seedbox_port" value="${config['seedbox_port']}" size="30">
</div>
<div class="row">
<label>Seedbox Username</label>
<input type="text" name="seedbox_user" value="${config['seedbox_user']}" size="30">
</div>
<div class="row">
<label>Seedbox Password</label>
<input type="password" name="seedbox_pass" value="${config['seedbox_pass']}" size="30">
</div>
<div class="row">
<label>Watch Directory</label>
<input type="text" name="seedbox_watchdir" value="${config['seedbox_watchdir']}" size="30"><br/>
<small>Folder path your torrent seedbox client watches</small>
</div>
</fieldset>
<fieldset id="utorrent_options">
<div class="row">
<label>uTorrent Host</label>
<input type="text" name="utorrent_host" value="${config['utorrent_host']}" size="30">
</div>
<div class="row">
<label>uTorrent Username</label>
<input type="text" name="utorrent_username" value="${config['utorrent_username']}" size="30">
</div>
<div class="row">
<label>uTorrent Password</label>
<input type="password" name="utorrent_password" value="${config['utorrent_password']}" size="30">
</div>
<div class="row">
<label>uTorrent Label</label>
<input type="text" name="utorrent_label" value="${config['utorrent_label']}" size="30"><br/>
<small>Label for your uTorrent downloads</small>
</div>
</fieldset>
<fieldset id="rtorrent_options">
<small class="heading"><span style="float: left; margin-right: .3em; margin-top: 4px;" class="ui-icon ui-icon-info"></span>Will *ONLY* work if rtorrent has RPC Support</small>
<div class="row">
<label>rTorrent Host:Port/RPC</label>
<input type="text" name="rtorrent_host" value="${config['rtorrent_host']}" size="30">
<small>ie. https://my.rtorrent:80/myuser/RPC1</small>
</div>
<div class="row">
<label>rTorrent Username</label>
<input type="text" name="rtorrent_username" value="${config['rtorrent_username']}" size="30">
</div>
<div class="row">
<label>rTorrent Password</label>
<input type="password" name="rtorrent_password" value="${config['rtorrent_password']}" size="30">
</div>
<div class="row">
<label>Watch Directory</label>
<input type="text" name="rtorrent_directory" value="${config['rtorrent_directory']}" size="30"><br/>
<small>Folder path where torrent download will be assigned</small>
</div>
<div class="row">
<label>Label</label>
<input type="text" name="rtorrent_label" value="${config['rtorrent_label']}" size="30"><br/>
<small>Label to assign for torrents</small>
</div>
<div class="row checkbox left clearfix">
<input id="rtorrent_startonload" type="checkbox" name="rtorrent_startonload" value="1" ${config['rtorrent_startonload']} /><label>Start Torrent on Successful Load</label>
<small>Automatically start torrent on successful loading within rtorrent client</small>
</div>
</fieldset>
<!-- <fieldset id="transmission_options">
<div class="row">
<label>Transmission Host</label>
<input type="text" name="transmission_host" value="${config['transmission_host']}" size="30">
</div>
<div class="row">
<label>Transmission Username</label>
<input type="text" name="transmission_username" value="${config['transmission_username']}" size="30">
</div>
<div class="row">
<label>Transmission Password</label>
<input type="password" name="transmission_password" value="${config['transmission_password']}" size="30">
</div>
</fieldset>
-->
</td>
</tr>
@ -1269,6 +1339,46 @@
}
});
if ($("#local_watchdir").is(":checked"))
{
$("#watchdir_local_options").show();
}
else
{
$("#watchdir_local_options").hide();
}
$("#local_watchdir").click(function(){
if ($("#local_watchdir").is(":checked"))
{
$("#watchdir_local_options").slideDown();
}
else
{
$("#watchdir_local_options").slideUp();
}
});
if ($("#remote_watchdir").is(":checked"))
{
$("#watchdir_remote_options").show();
}
else
{
$("#watchdir_remote_options").hide();
}
$("#remote_watchdir").click(function(){
if ($("#remote_watchdir").is(":checked"))
{
$("#watchdir_remote_options").slideDown();
}
else
{
$("#watchdir_remote_options").slideUp();
}
});
if ($("#nzb_downloader_sabnzbd").is(":checked"))
{
$("#nzbget_options,#blackhole_options").hide();
@ -1285,6 +1395,28 @@
$("#blackhole_options").show();
}
if ($("#torrent_downloader_watchlist").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#transmission_options").hide();
$("#watchlist_options").show();
}
if ($("#torrent_downloader_utorrent").is(":checked"))
{
$("#watchlist_options,#rtorrent_options,#transmission_options").hide();
$("#utorrent_options").show();
}
if ($("#torrent_downloader_rtorrent").is(":checked"))
{
$("#utorrent_options,#watchlist_options,#transmission_options").hide();
$("#rtorrent_options").show();
}
if ($("#torrent_downloader_transmission").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options").hide();
$("#transmission_options").show();
}
$('input[type=radio]').change(function(){
if ($("#nzb_downloader_sabnzbd").is(":checked"))
{
@ -1298,6 +1430,22 @@
{
$("#sabnzbd_options,#nzbget_options").fadeOut("fast", function() { $("#blackhole_options").fadeIn() });
}
if ($("#torrent_downloader_watchlist").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#transmission_options").fadeOut("fast", function() { $("#watchlist_options").fadeIn() });
}
if ($("#torrent_downloader_utorrent").is(":checked"))
{
$("#watchlist_options,#rtorrent_options,#transmission_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() });
}
if ($("#torrent_downloader_rtorrent").is(":checked"))
{
$("#utorrent_options,#watchlist_options,#transmission_options").fadeOut("fast", function() { $("#rtorrent_options").fadeIn() });
}
if ($("#torrent_downloader_transmission").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() });
}
});
var deletedNewznabs = 0;
@ -1428,8 +1576,6 @@
initConfigCheckbox("#usenzbsu");
initConfigCheckbox("#usedognzb");
initConfigCheckbox("#enable_torrents");
initConfigCheckbox("#torrent_local");
initConfigCheckbox("#torrent_seedbox");
initConfigCheckbox("#enable_torrent_search");
initConfigCheckbox("#enable_32p");
initConfigCheckbox("#enable_rss");

View File

@ -349,10 +349,13 @@ FAILED_DOWNLOAD_HANDLING = 0
FAILED_AUTO = 0
ENABLE_TORRENTS = 0
TORRENT_DOWNLOADER = None #0 = watchfolder, #1 = uTorrent, #2 = rTorrent, #3 = transmission
MINSEEDS = 0
TORRENT_LOCAL = 0
USE_WATCHDIR = False
TORRENT_LOCAL = False
LOCAL_WATCHDIR = None
TORRENT_SEEDBOX = 0
TORRENT_SEEDBOX = False
SEEDBOX_HOST = None
SEEDBOX_PORT = None
SEEDBOX_USER = None
@ -376,6 +379,7 @@ FEEDINFO_32P = None
VERIFY_32P = 1
SNATCHEDTORRENT_NOTIFY = 0
USE_RTORRENT = False
RTORRENT_HOST = None
RTORRENT_USERNAME = None
RTORRENT_PASSWORD = None
@ -383,6 +387,17 @@ RTORRENT_STARTONLOAD = 0
RTORRENT_LABEL = None
RTORRENT_DIRECTORY = None
USE_UTORRENT = False
UTORRENT_HOST = None
UTORRENT_USERNAME = None
UTORRENT_PASSWORD = None
UTORRENT_LABEL = None
USE_TRANSMISSION = False
TRANSMISSION_HOST = None
TRANSMISSION_USERNAME = None
TRANSMISSION_PASSWORD = None
def CheckSection(sec):
""" Check if INI section exists, if not create it """
try:
@ -441,10 +456,11 @@ def initialize():
USE_NZBGET, NZBGET_HOST, NZBGET_PORT, NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_PRIORITY, NZBGET_DIRECTORY, NZBSU, NZBSU_UID, NZBSU_APIKEY, NZBSU_VERIFY, DOGNZB, DOGNZB_APIKEY, DOGNZB_VERIFY, \
NEWZNAB, NEWZNAB_NAME, NEWZNAB_HOST, NEWZNAB_APIKEY, NEWZNAB_VERIFY, NEWZNAB_UID, NEWZNAB_ENABLED, EXTRA_NEWZNABS, NEWZNAB_EXTRA, \
ENABLE_TORZNAB, TORZNAB_NAME, TORZNAB_HOST, TORZNAB_APIKEY, TORZNAB_CATEGORY, TORZNAB_VERIFY, \
EXPERIMENTAL, ALTEXPERIMENTAL, RTORRENT_HOST, RTORRENT_USERNAME, RTORRENT_PASSWORD, RTORRENT_STARTONLOAD, RTORRENT_LABEL, RTORRENT_DIRECTORY, \
EXPERIMENTAL, ALTEXPERIMENTAL, USE_RTORRENT, RTORRENT_HOST, RTORRENT_USERNAME, RTORRENT_PASSWORD, RTORRENT_STARTONLOAD, RTORRENT_LABEL, RTORRENT_DIRECTORY, \
USE_UTORRENT, UTORRENT_HOST, UTORRENT_USERNAME, UTORRENT_PASSWORD, UTORRENT_LABEL, USE_TRANSMISSION, TRANSMISSION_HOST, TRANSMISSION_USERNAME, TRANSMISSION_PASSWORD, \
ENABLE_META, CMTAGGER_PATH, CBR2CBZ_ONLY, CT_TAG_CR, CT_TAG_CBL, CT_CBZ_OVERWRITE, UNRAR_CMD, CT_SETTINGSPATH, UPDATE_ENDED, INDIE_PUB, BIGGIE_PUB, IGNORE_HAVETOTAL, SNATCHED_HAVETOTAL, PROVIDER_ORDER, \
dbUpdateScheduler, searchScheduler, RSSScheduler, WeeklyScheduler, VersionScheduler, FolderMonitorScheduler, \
ENABLE_TORRENTS, MINSEEDS, TORRENT_LOCAL, LOCAL_WATCHDIR, TORRENT_SEEDBOX, SEEDBOX_HOST, SEEDBOX_PORT, SEEDBOX_USER, SEEDBOX_PASS, SEEDBOX_WATCHDIR, \
ENABLE_TORRENTS, TORRENT_DOWNLOADER, MINSEEDS, USE_WATCHDIR, TORRENT_LOCAL, LOCAL_WATCHDIR, TORRENT_SEEDBOX, SEEDBOX_HOST, SEEDBOX_PORT, SEEDBOX_USER, SEEDBOX_PASS, SEEDBOX_WATCHDIR, \
ENABLE_RSS, RSS_CHECKINTERVAL, RSS_LASTRUN, FAILED_DOWNLOAD_HANDLING, FAILED_AUTO, ENABLE_TORRENT_SEARCH, ENABLE_KAT, KAT_PROXY, KAT_VERIFY, ENABLE_32P, MODE_32P, KEYS_32P, RSSFEED_32P, USERNAME_32P, PASSWORD_32P, AUTHKEY_32P, PASSKEY_32P, FEEDINFO_32P, VERIFY_32P, SNATCHEDTORRENT_NOTIFY, \
PROWL_ENABLED, PROWL_PRIORITY, PROWL_KEYS, PROWL_ONSNATCH, NMA_ENABLED, NMA_APIKEY, NMA_PRIORITY, NMA_ONSNATCH, PUSHOVER_ENABLED, PUSHOVER_PRIORITY, PUSHOVER_APIKEY, PUSHOVER_USERKEY, PUSHOVER_ONSNATCH, BOXCAR_ENABLED, BOXCAR_ONSNATCH, BOXCAR_TOKEN, \
PUSHBULLET_ENABLED, PUSHBULLET_APIKEY, PUSHBULLET_DEVICEID, PUSHBULLET_ONSNATCH, LOCMOVE, NEWCOM_DIR, FFTONEWCOM_DIR, \
@ -464,6 +480,8 @@ def initialize():
CheckSection('Newznab')
CheckSection('Torznab')
CheckSection('Torrents')
CheckSection('uTorrent')
CheckSection('Transmission')
# Set global variables based on config file or use defaults
try:
HTTP_PORT = check_setting_int(CFG, 'General', 'http_port', 8090)
@ -513,6 +531,7 @@ def initialize():
CHECK_GITHUB_ON_STARTUP = bool(check_setting_int(CFG, 'General', 'check_github_on_startup', 1))
CHECK_GITHUB_INTERVAL = check_setting_int(CFG, 'General', 'check_github_interval', 360)
GIT_USER = check_setting_str(CFG, 'General', 'git_user', 'evilhero')
GIT_BRANCH = check_setting_str(CFG,'General', 'git_branch', 'master')
DESTINATION_DIR = check_setting_str(CFG, 'General', 'destination_dir', '')
MULTIPLE_DEST_DIRS = check_setting_str(CFG, 'General', 'multiple_dest_dirs', '')
@ -748,7 +767,25 @@ def initialize():
PR_NUM = 0 # provider counter here (used for provider orders)
PR = []
TORRENT_DOWNLOADER = check_setting_int(CFG, 'General', 'torrent_downloader', 0)
if TORRENT_DOWNLOADER == 0: USE_WATCHDIR = True
elif TORRENT_DOWNLOADER == 1: USE_UTORRENT = True
elif TORRENT_DOWNLOADER == 2: USE_RTORRENT = True
elif TORRENT_DOWNLOADER == 3: USE_TRANSMISSION = True
else:
TORRENT_DOWNLOADER = 0
USE_WATCHDIR = True
TORRENT_LOCAL = True
#USE_UTORRENT = bool(check_setting_int(CFG, 'uTorrent', 'use_utorrent', 0))
UTORRENT_HOST = check_setting_str(CFG, 'uTorrent', 'utorrent_host', '')
UTORRENT_USERNAME = check_setting_str(CFG, 'uTorrent', 'utorrent_username', '')
UTORRENT_PASSWORD = check_setting_str(CFG, 'uTorrent', 'utorrent_password', '')
UTORRENT_LABEL = check_setting_str(CFG, 'uTorrent', 'utorrent_label', '')
TRANSMISSION_HOST = check_setting_str(CFG, 'Transmission', 'transmission_host', '')
TRANSMISSION_USERNAME = check_setting_str(CFG, 'Transmission', 'transmission_username', '')
TRANSMISSION_PASSWORD = check_setting_str(CFG, 'Transmission', 'transmission_password', '')
#add torrents to provider counter.
if ENABLE_TORRENT_SEARCH:
if ENABLE_32P:
@ -827,6 +864,7 @@ def initialize():
EXTRA_NEWZNABS = list(itertools.izip(*[itertools.islice(flattened_newznabs, i, None, EN_NUM) for i in range(EN_NUM)]))
#if ConfigV3 add the nzb_name to it..
#if ConfigV3 add the nzb_name to it..
if CONFIG_VERSION != '6': #just bump it up to V6 and throw in the VERIFY too.
ENABS = []
@ -961,7 +999,7 @@ def initialize():
CONFIG_VERSION = '2'
if 'http://' not in SAB_HOST[:7] and 'https://' not in SAB_HOST[:8]:
if all(['http://' not in SAB_HOST[:7], 'https://' not in SAB_HOST[:8], SAB_HOST != '', SAB_HOST is not None]):
SAB_HOST = 'http://' + SAB_HOST
if not LOG_DIR:
@ -1379,6 +1417,7 @@ def config_write():
new_config['General']['provider_order'] = flattened_providers
new_config['General']['nzb_downloader'] = int(NZB_DOWNLOADER)
new_config['General']['torrent_downloader'] = int(TORRENT_DOWNLOADER)
new_config['Torrents'] = {}
new_config['Torrents']['enable_torrents'] = int(ENABLE_TORRENTS)
@ -1458,6 +1497,17 @@ def config_write():
new_config['Newznab'] = {}
new_config['Newznab']['newznab'] = int(NEWZNAB)
new_config['uTorrent'] = {}
new_config['uTorrent']['utorrent_host'] = UTORRENT_HOST
new_config['uTorrent']['utorrent_username'] = UTORRENT_USERNAME
new_config['uTorrent']['utorrent_password'] = UTORRENT_PASSWORD
new_config['uTorrent']['utorrent_label'] = UTORRENT_LABEL
new_config['Transmission'] = {}
new_config['Transmission']['transmission_host'] = TRANSMISSION_HOST
new_config['Transmission']['transmission_username'] = TRANSMISSION_USERNAME
new_config['Transmission']['transmission_password'] = TRANSMISSION_PASSWORD
# Need to unpack the extra newznabs for saving in config.ini
flattened_newznabs = []
for newznab in EXTRA_NEWZNABS:

131
mylar/bencode.py Normal file
View File

@ -0,0 +1,131 @@
# Got this from here: https://gist.github.com/1126793
# The contents of this file are subject to the Python Software Foundation
# License Version 2.3 (the License). You may not copy or use this file, in
# either source code or executable form, except in compliance with the License.
# You may obtain a copy of the License at http://www.python.org/license.
#
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
# Written by Petru Paler
# Minor modifications made by Andrew Resch to replace the BTFailure errors with Exceptions
def decode_int(x, f):
f += 1
newf = x.index('e', f)
n = int(x[f:newf])
if x[f] == '-':
if x[f + 1] == '0':
raise ValueError
elif x[f] == '0' and newf != f+1:
raise ValueError
return (n, newf+1)
def decode_string(x, f):
colon = x.index(':', f)
n = int(x[f:colon])
if x[f] == '0' and colon != f+1:
raise ValueError
colon += 1
return (x[colon:colon+n], colon+n)
def decode_list(x, f):
r, f = [], f+1
while x[f] != 'e':
v, f = decode_func[x[f]](x, f)
r.append(v)
return (r, f + 1)
def decode_dict(x, f):
r, f = {}, f+1
while x[f] != 'e':
k, f = decode_string(x, f)
r[k], f = decode_func[x[f]](x, f)
return (r, f + 1)
decode_func = {}
decode_func['l'] = decode_list
decode_func['d'] = decode_dict
decode_func['i'] = decode_int
decode_func['0'] = decode_string
decode_func['1'] = decode_string
decode_func['2'] = decode_string
decode_func['3'] = decode_string
decode_func['4'] = decode_string
decode_func['5'] = decode_string
decode_func['6'] = decode_string
decode_func['7'] = decode_string
decode_func['8'] = decode_string
decode_func['9'] = decode_string
def bdecode(x):
try:
r, l = decode_func[x[0]](x, 0)
except (IndexError, KeyError, ValueError):
raise Exception("not a valid bencoded string")
return r
from types import StringType, IntType, LongType, DictType, ListType, TupleType
class Bencached(object):
__slots__ = ['bencoded']
def __init__(self, s):
self.bencoded = s
def encode_bencached(x,r):
r.append(x.bencoded)
def encode_int(x, r):
r.extend(('i', str(x), 'e'))
def encode_bool(x, r):
if x:
encode_int(1, r)
else:
encode_int(0, r)
def encode_string(x, r):
r.extend((str(len(x)), ':', x))
def encode_list(x, r):
r.append('l')
for i in x:
encode_func[type(i)](i, r)
r.append('e')
def encode_dict(x,r):
r.append('d')
ilist = x.items()
ilist.sort()
for k, v in ilist:
r.extend((str(len(k)), ':', k))
encode_func[type(v)](v, r)
r.append('e')
encode_func = {}
encode_func[Bencached] = encode_bencached
encode_func[IntType] = encode_int
encode_func[LongType] = encode_int
encode_func[StringType] = encode_string
encode_func[ListType] = encode_list
encode_func[TupleType] = encode_list
encode_func[DictType] = encode_dict
try:
from types import BooleanType
encode_func[BooleanType] = encode_bool
except ImportError:
pass
def bencode(x):
r = []
encode_func[type(x)](x, r)
return ''.join(r)

View File

@ -7,10 +7,12 @@ import lib.requests as requests
import ftpsshup
import datetime
import gzip
import time
from StringIO import StringIO
import mylar
from mylar import db, logger, ftpsshup, helpers, auth32p
from mylar import db, logger, ftpsshup, helpers, auth32p, utorrent
def _start_newznab_attr(self, attrsD):
@ -724,17 +726,20 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
if linkit[-7:] != "torrent": # and site != "KAT":
filename += ".torrent"
if mylar.TORRENT_LOCAL and mylar.LOCAL_WATCHDIR is not None:
filepath = os.path.join(mylar.LOCAL_WATCHDIR, filename)
logger.fdebug('filename for torrent set to : ' + filepath)
elif mylar.TORRENT_SEEDBOX and mylar.SEEDBOX_WATCHDIR is not None:
if any([mylar.USE_UTORRENT, mylar.USE_RTORRENT]):
filepath = os.path.join(mylar.CACHE_DIR, filename)
logger.fdebug('filename for torrent set to : ' + filepath)
else:
logger.error('No Local Watch Directory or Seedbox Watch Directory specified. Set it and try again.')
return "fail"
elif mylar.USE_WATCHDIR:
if mylar.TORRENT_LOCAL and mylar.LOCAL_WATCHDIR is not None:
filepath = os.path.join(mylar.LOCAL_WATCHDIR, filename)
logger.fdebug('filename for torrent set to : ' + filepath)
elif mylar.TORRENT_SEEDBOX and mylar.SEEDBOX_WATCHDIR is not None:
filepath = os.path.join(mylar.CACHE_DIR, filename)
logger.fdebug('filename for torrent set to : ' + filepath)
else:
logger.error('No Local Watch Directory or Seedbox Watch Directory specified. Set it and try again.')
return "fail"
if site == '32P':
url = 'https://32pag.es/torrents.php'
@ -888,25 +893,34 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
f.flush()
logger.fdebug('[' + site + '] Saved torrent file to : ' + filepath)
if mylar.TORRENT_LOCAL:
if mylar.USE_UTORRENT:
utorrent.addTorrent(url)
if mylar.UTORRENT_LABEL:
torfile = open(filepath, 'rb')
tordata = torfile.read()
torfile.close()
hash = utorrent.calculate_torrent_hash(url, tordata)
time.sleep(10)
utorrent.labelTorrent(hash)
return "pass"
elif mylar.TORRENT_SEEDBOX:
if mylar.RTORRENT_HOST:
import test
rp = test.RTorrent()
torrent_info = rp.main(filepath=filepath)
logger.info(torrent_info)
if torrent_info:
return "pass"
else:
return "fail"
elif mylar.USE_WATCHDIR:
if mylar.TORRENT_LOCAL:
return "pass"
else:
tssh = ftpsshup.putfile(filepath, filename)
return tssh
elif mylar.USE_RTORRENT:
import test
rp = test.RTorrent()
torrent_info = rp.main(filepath=filepath)
logger.info(torrent_info)
if torrent_info:
return "pass"
else:
return "fail"
if __name__ == '__main__':
#torrents(sys.argv[1])

View File

@ -2015,7 +2015,6 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
#torrents (32P & KAT)
elif nzbprov == '32P' or nzbprov == 'KAT' or nzbprov == 'Torznab':
logger.fdebug("sending .torrent to watchdir.")
logger.fdebug("ComicName:" + ComicName)
logger.fdebug("link:" + link)
logger.fdebug("Torrent Provider:" + nzbprov)
@ -2040,10 +2039,17 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
else:
logger.error('Unable to send torrent - check logs and settings (this would be marked as a BAD torrent if Failed Handling was enabled)')
return "torrent-fail"
if mylar.TORRENT_LOCAL:
sent_to = "your local Watch folder"
else:
sent_to = "your seedbox Watch folder"
if mylar.USE_WATCHDIR:
if TORRENT_LOCAL:
sent_to = "your local Watch folder"
else:
sent_to = "your seedbox Watch folder"
elif mylar.USE_UTORRENT:
sent_to = "your uTorrent client"
elif mylar.USE_RTORRENT:
sent_to = "your rTorrent client"
elif mylar.USE_TRANSMISSION:
sent_to = "your Transmission client"
#end torrents
else:

218
mylar/utorrent.py Normal file
View File

@ -0,0 +1,218 @@
# This file is part of Mylar and is adapted from Headphones.
import hashlib
import urllib
import json
import time
from collections import namedtuple
import urllib2
import urlparse
import cookielib
import re
import os
import mylar
from mylar import logger
from bencode import bencode, bdecode
from hashlib import sha1
class utorrentclient(object):
TOKEN_REGEX = "<div id='token' style='display:none;'>([^<>]+)</div>"
UTSetting = namedtuple("UTSetting", ["name", "int", "str", "access"])
def __init__(self, base_url=None, username=None, password=None, ):
host = mylar.UTORRENT_HOST
if not host.startswith('http'):
host = 'http://' + host
if host.endswith('/'):
host = host[:-1]
if host.endswith('/gui'):
host = host[:-4]
self.base_url = host
self.username = mylar.UTORRENT_USERNAME
self.password = mylar.UTORRENT_PASSWORD
self.opener = self._make_opener('uTorrent', self.base_url, self.username, self.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 = urllib2.HTTPBasicAuthHandler()
auth.add_password(realm=realm, uri=base_url, user=username, passwd=password)
opener = urllib2.build_opener(auth)
urllib2.install_opener(opener)
cookie_jar = cookielib.CookieJar()
cookie_handler = urllib2.HTTPCookieProcessor(cookie_jar)
handlers = [auth, cookie_handler]
opener = urllib2.build_opener(*handlers)
return opener
def _get_token(self):
url = urlparse.urljoin(self.base_url, 'gui/token.html')
try:
response = self.opener.open(url)
except urllib2.HTTPError as err:
logger.debug('URL: ' + str(url))
logger.debug('Error getting Token. uTorrent responded with error: ' + str(err))
return
match = re.search(utorrentclient.TOKEN_REGEX, response.read())
return match.group(1)
def list(self, **kwargs):
params = [('list', '1')]
params += kwargs.items()
return self._action(params)
def add_url(self, url):
# can receive magnet or normal .torrent link
params = [('action', 'add-url'), ('s', url)]
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 setprops(self, hash, s, val):
params = [('action', 'setprops'), ('hash', hash), ("s", s), ("v", val)]
logger.debug('Params: ' + str(params))
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 get_settings(self, key=None):
params = [('action', 'getsettings'), ]
status, value = self._action(params)
settings = {}
for args in value['settings']:
settings[args[0]] = self.UTSetting(*args)
if key:
return settings[key]
return settings
def remove(self, hash, remove_data=False):
if remove_data:
params = [('action', 'removedata'), ('hash', hash)]
else:
params = [('action', 'remove'), ('hash', hash)]
return self._action(params)
def _action(self, params, body=None, content_type=None):
if not self.token:
return
url = self.base_url + '/gui/' + '?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 as err:
logger.debug('URL: ' + str(url))
logger.debug('uTorrent webUI raised the following error: ' + str(err))
def labelTorrent(hash):
label = mylar.UTORRENT_LABEL
uTorrentClient = utorrentclient()
if label:
uTorrentClient.setprops(hash, 'label', str(label))
def removeTorrent(hash, remove_data=False):
uTorrentClient = utorrentclient()
status, torrentList = uTorrentClient.list()
torrents = torrentList['torrents']
for torrent in torrents:
if torrent[0].upper() == hash.upper():
if torrent[21] == 'Finished':
logger.info('%s has finished seeding, removing torrent and data' % torrent[2])
uTorrentClient.remove(hash, remove_data)
return True
else:
logger.info(
'%s has not finished seeding yet, torrent will not be removed, will try again on next run' %
torrent[2])
return False
return False
def setSeedRatio(hash, ratio):
uTorrentClient = utorrentclient()
uTorrentClient.setprops(hash, 'seed_override', '1')
if ratio != 0:
uTorrentClient.setprops(hash, 'seed_ratio', ratio * 10)
else:
# TODO passing -1 should be unlimited
uTorrentClient.setprops(hash, 'seed_ratio', -10)
def addTorrent(link):
uTorrentClient = utorrentclient()
uTorrentClient.add_url(link)
def calculate_torrent_hash(link, data=None):
"""
Calculate the torrent hash from a magnet link or data. Raises a ValueError
when it cannot create a torrent hash given the input data.
"""
if link.startswith("magnet:"):
torrent_hash = re.findall("urn:btih:([\w]{32,40})", link)[0]
if len(torrent_hash) == 32:
torrent_hash = b16encode(b32decode(torrent_hash)).lower()
elif data:
info = bdecode(data)["info"]
torrent_hash = sha1(bencode(info)).hexdigest()
else:
raise ValueError("Cannot calculate torrent hash without magnet link " \
"or data")
logger.debug("Torrent hash: " + torrent_hash)
return torrent_hash.upper()

View File

@ -3585,6 +3585,23 @@ class WebInterface(object):
"nzbget_cat": mylar.NZBGET_CATEGORY,
"nzbget_priority": mylar.NZBGET_PRIORITY,
"nzbget_directory": mylar.NZBGET_DIRECTORY,
"torrent_downloader_watchlist": helpers.radio(mylar.TORRENT_DOWNLOADER, 0),
"torrent_downloader_utorrent": helpers.radio(mylar.TORRENT_DOWNLOADER, 1),
"torrent_downloader_rtorrent": helpers.radio(mylar.TORRENT_DOWNLOADER, 2),
"torrent_downloader_transmission": helpers.radio(mylar.TORRENT_DOWNLOADER, 3),
"utorrent_host": mylar.UTORRENT_HOST,
"utorrent_username": mylar.UTORRENT_USERNAME,
"utorrent_password": mylar.UTORRENT_PASSWORD,
"utorrent_label": mylar.UTORRENT_LABEL,
"rtorrent_host": mylar.RTORRENT_HOST,
"rtorrent_username": mylar.RTORRENT_USERNAME,
"rtorrent_password": mylar.RTORRENT_PASSWORD,
"rtorrent_directory": mylar.RTORRENT_DIRECTORY,
"rtorrent_label": mylar.RTORRENT_LABEL,
"rtorrent_startonload": helpers.checked(mylar.RTORRENT_STARTONLOAD),
"transmission_host": mylar.TRANSMISSION_HOST,
"transmission_username": mylar.TRANSMISSION_USERNAME,
"transmission_password": mylar.TRANSMISSION_PASSWORD,
"blackhole_dir": mylar.BLACKHOLE_DIR,
"usenet_retention": mylar.USENET_RETENTION,
"use_nzbsu": helpers.checked(mylar.NZBSU),
@ -3907,9 +3924,10 @@ class WebInterface(object):
usenet_retention=None, nzbsu=0, nzbsu_uid=None, nzbsu_apikey=None, nzbsu_verify=0, dognzb=0, dognzb_apikey=None, dognzb_verify=0, newznab=0, newznab_host=None, newznab_name=None, newznab_verify=0, newznab_apikey=None, newznab_uid=None, newznab_enabled=0,
enable_torznab=0, torznab_name=None, torznab_host=None, torznab_apikey=None, torznab_category=None, experimental=0, check_folder=None, enable_check_folder=0,
enable_meta=0, cbr2cbz_only=0, cmtagger_path=None, ct_tag_cr=0, ct_tag_cbl=0, ct_cbz_overwrite=0, unrar_cmd=None, enable_rss=0, rss_checkinterval=None, failed_download_handling=0, failed_auto=0, enable_torrent_search=0, enable_kat=0, enable_32p=0, mode_32p=0, rssfeed_32p=None, passkey_32p=None, username_32p=None, password_32p=None, snatchedtorrent_notify=0,
enable_torrents=0, minseeds=0, torrent_local=0, local_watchdir=None, torrent_seedbox=0, seedbox_watchdir=None, seedbox_user=None, seedbox_pass=None, seedbox_host=None, seedbox_port=None,
enable_torrents=0, minseeds=0, local_watchdir=None, seedbox_watchdir=None, seedbox_user=None, seedbox_pass=None, seedbox_host=None, seedbox_port=None,
prowl_enabled=0, prowl_onsnatch=0, prowl_keys=None, prowl_priority=None, nma_enabled=0, nma_apikey=None, nma_priority=0, nma_onsnatch=0, pushover_enabled=0, pushover_onsnatch=0, pushover_apikey=None, pushover_userkey=None, pushover_priority=None, boxcar_enabled=0, boxcar_onsnatch=0, boxcar_token=None,
pushbullet_enabled=0, pushbullet_apikey=None, pushbullet_deviceid=None, pushbullet_onsnatch=0,
pushbullet_enabled=0, pushbullet_apikey=None, pushbullet_deviceid=None, pushbullet_onsnatch=0, torrent_downloader=0, torrent_local=0, torrent_seedbox=0, utorrent_host=None, utorrent_username=None, utorrent_password=None, utorrent_label=None,
rtorrent_host=None, rtorrent_username=None, rtorrent_password=None, rtorrent_directory=None, rtorrent_label=None, rtorrent_startonload=0, transmission_host=None, transmission_username=None, transmission_password=None,
preferred_quality=0, move_files=0, rename_files=0, add_to_csv=1, cvinfo=0, lowercase_filenames=0, folder_format=None, file_format=None, enable_extra_scripts=0, extra_scripts=None, enable_pre_scripts=0, pre_scripts=None, post_processing=0, file_opts=None, syno_fix=0, search_delay=None, chmod_dir=0777, chmod_file=0660, chowner=None, chgroup=None,
tsab=None, destination_dir=None, create_folders=1, replace_spaces=0, replace_char=None, use_minsize=0, minsize=None, use_maxsize=0, maxsize=None, autowant_all=0, autowant_upcoming=0, comic_cover_local=0, zero_level=0, zero_level_n=None, interface=None, dupeconstraint=None, ddump=0, duplicate_dump=None, **kwargs):
mylar.COMICVINE_API = comicvine_api
@ -3974,6 +3992,7 @@ class WebInterface(object):
mylar.RSS_CHECKINTERVAL = rss_checkinterval
mylar.ENABLE_TORRENTS = int(enable_torrents)
mylar.MINSEEDS = int(minseeds)
mylar.TORRENT_DOWNLOADER = int(torrent_downloader)
mylar.TORRENT_LOCAL = int(torrent_local)
mylar.LOCAL_WATCHDIR = local_watchdir
mylar.TORRENT_SEEDBOX = int(torrent_seedbox)
@ -3982,6 +4001,19 @@ class WebInterface(object):
mylar.SEEDBOX_PORT = seedbox_port
mylar.SEEDBOX_USER = seedbox_user
mylar.SEEDBOX_PASS = seedbox_pass
mylar.UTORRENT_HOST = utorrent_host
mylar.UTORRENT_USERNAME = utorrent_username
mylar.UTORRENT_PASSWORD = utorrent_password
mylar.UTORRENT_LABEL = utorrent_label
mylar.RTORRENT_HOST = rtorrent_host
mylar.RTORRENT_USERNAME = rtorrent_username
mylar.RTORRENT_PASSWORD = rtorrent_password
mylar.RTORRENT_DIRECTORY = rtorrent_directory
mylar.RTORRENT_LABEL = rtorrent_label
mylar.RTORRENT_STARTONLOAD = int(rtorrent_startonload)
mylar.TRANSMISSION_HOST = transmission_host
mylar.TRANSMISSION_USERNAME = transmission_username
mylar.TRANSMISSION_PASSWORD = transmission_password
mylar.ENABLE_TORRENT_SEARCH = int(enable_torrent_search)
mylar.ENABLE_KAT = int(enable_kat)
mylar.ENABLE_32P = int(enable_32p)
@ -4138,6 +4170,11 @@ class WebInterface(object):
if mylar.NZB_DOWNLOADER == 0: mylar.USE_SABNZBD = True
elif mylar.NZB_DOWNLOADER == 1: mylar.USE_NZBGET = True
elif mylar.NZB_DOWNLOADER == 2: mylar.USE_BLACKHOLE = True
if mylar.TORRENT_DOWNLOADER == 0: mylar.USE_WATCHDIR = True
elif mylar.TORRENT_DOWNLOADER == 1: mylar.USE_UTORRENT = True
elif mylar.TORRENT_DOWNLOADER == 2: mylar.USE_RTORRENT = True
elif mylar.TORRENT_DOWNLOADER == 3: mylar.USE_TRANSMISSION = True
# Write the config
mylar.config_write()