IMP: Added Qbittorrent download client option, FIX:(#1604)Folder Name with a . at the end appears mess up on windows, FIX:(#1607) invalid reference to arc variable during post-processing, IMP: added an auto-snatch option for rutorrent/deluge seedbox users on nix systems (will automatically download the file to a local client for immediate post-processing), IMP: can now run custom script on snatch, FIX: Fixed a problem with volume labels getting reset on series refreshes to None, FIX: When recreating the pull (either automated/manual), will now wipe out the existing entries from the table prior to getting new information, IMP: Will now store hash of torrent (if applicable) when storing snatch information

This commit is contained in:
evilhero 2017-04-28 02:12:45 -04:00
parent 13cbe739c6
commit c5e46e552f
18 changed files with 1553 additions and 177 deletions

View File

@ -402,13 +402,15 @@
<label>Minimum # of seeders</label>
<input type="text" name="minseeds" value="${config['minseeds']}" size="10">
</div>
<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
<input type="radio" name="torrent_downloader" id="torrent_downloader_deluge" value="4" ${config['torrent_downloader_deluge']}> Deluge
</div>
<center>
<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</br>
<input type="radio" name="torrent_downloader" id="torrent_downloader_transmission" value="3" ${config['torrent_downloader_transmission']}> Transmission&nbsp;&nbsp;
<input type="radio" name="torrent_downloader" id="torrent_downloader_deluge" value="4" ${config['torrent_downloader_deluge']}> Deluge&nbsp;&nbsp;
<input type="radio" name="torrent_downloader" id="torrent_downloader_qbittorrent" value="5" ${config['torrent_downloader_qbittorrent']}> qBittorrent
</center>
</div>
</fieldset>
<fieldset id="watchlist_options">
<div class="row checkbox left clearfix">
@ -560,6 +562,36 @@
<small>Label to be used on the torrents</small>
</div>
</fieldset>
</fieldset>
<fieldset id="qbittorrent_options">
<div class="row">
<label>qBittorrent Host:Port </label>
<input type="text" name="qbittorrent_host" value="${config['qbittorrent_host']}" size="30">
</div>
<div class="row">
<label>qBittorrent Username</label>
<input type="text" name="qbittorrent_username" value="${config['qbittorrent_username']}" size="30">
</div>
<div class="row">
<label>qBittorrent Password</label>
<input type="password" name="qbittorrent_password" value="${config['qbittorrent_password']}" size="30">
</div>
<div class="row">
<label>qBittorrent Label</label>
<input type="text" name="qbittorrent_label" value="${config['qbittorrent_label']}" size="30"><br/>
<small>Label to be used on the torrents</small>
</div>
<div class="row">
<label>qBittorrent Folder</label>
<input type="text" name="qbittorrent_folder" value="${config['qbittorrent_folder']}" size="30"><br/>
<small>Folder path where torrents will be assigned to</small>
</div>
<div class="row checkbox left clearfix">
<input id="qbittorrent_startonload" type="checkbox" name="qbittorrent_startonload" value="1" ${config['qbittorrent_startonload']} /><label>Start Torrent on Successful Load</label>
<small>Automatically start torrent on successful loading within qBittorrent client</small>
</div>
</fieldset>
</td>
</tr>
@ -913,7 +945,7 @@
</div>
</div>
<div class="row checkbox left clearfix">
<input type="checkbox" id="enable_pre_scripts" onclick="initConfigCheckbox($this));" name="enable_pre_scripts" value="1" ${config['enable_pre_scripts']} /><label>Use Extra Script BEFORE Post-Processing</label>
<input type="checkbox" id="enable_pre_scripts" onclick="initConfigCheckbox($this));" name="enable_pre_scripts" value="1" ${config['enable_pre_scripts']} /><label>Run script BEFORE Post-Processing</label>
</div>
<div class="config">
<div class="row">
@ -921,9 +953,19 @@
<input type="text" name="pre_scripts" value="${config['pre_scripts']}" size="30">
<small>enter in the absolute path to the script</small>
</div>
</div>
</div>
<div class="row checkbox left clearfix">
<input type="checkbox" id="enable_extra_scripts" onclick="initConfigCheckbox($this));" name="enable_extra_scripts" value="1" ${config['enable_extra_scripts']} /><label>Use Extra Script AFTER Post-Processing</label>
<input type="checkbox" id="enable_snatch_script" onclick="initConfigCheckbox($this));" name="enable_snatch_script" value="1" ${config['enable_snatch_script']} /><label>Run script AFTER an item has been snatched and sent to client</label>
</div>
<div class="config">
<div class="row">
<label>On Snatch Script Location</label>
<input type="text" name="snatch_script" value="${config['snatch_script']}" size="30">
<small>enter in the absolute path to the script</small>
</div>
</div>
<div class="row checkbox left clearfix">
<input type="checkbox" id="enable_extra_scripts" onclick="initConfigCheckbox($this));" name="enable_extra_scripts" value="1" ${config['enable_extra_scripts']} /><label>Run script AFTER Post-Processing</label>
</div>
<div class="config">
<div class="row">
@ -1520,29 +1562,34 @@
if ($("#torrent_downloader_watchlist").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#transmission_options,#deluge_options").hide();
$("#utorrent_options,#rtorrent_options,#transmission_options,#deluge_options,#qbittorrent_options").hide();
$("#watchlist_options").show();
}
if ($("#torrent_downloader_utorrent").is(":checked"))
{
$("#watchlist_options,#rtorrent_options,#transmission_options,#deluge_options").hide();
$("#watchlist_options,#rtorrent_options,#transmission_options,#deluge_options,#qbittorrent_options").hide();
$("#utorrent_options").show();
}
if ($("#torrent_downloader_rtorrent").is(":checked"))
if ($("#torrent_downloader_rtorrent").is(":checked"))
{
$("#utorrent_options,#watchlist_options,#transmission_options,#deluge_options").hide();
$("#utorrent_options,#watchlist_options,#transmission_options,#deluge_options,#qbittorrent_options").hide();
$("#rtorrent_options").show();
}
if ($("#torrent_downloader_transmission").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#deluge_options").hide();
$("#utorrent_options,#rtorrent_options,#watchlist_options,#deluge_options,#qbittorrent_options").hide();
$("#transmission_options").show();
}
if ($("#torrent_downloader_deluge").is(":checked"))
if ($("#torrent_downloader_deluge").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options").hide();
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options,#qbittorrent_options").hide();
$("#deluge_options").show();
}
if ($("#torrent_downloader_qbittorrent").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options,#deluge_options").hide();
$("#qbittorrent_options").show();
}
$('input[type=radio]').change(function(){
if ($("#nzb_downloader_sabnzbd").is(":checked"))
@ -1559,24 +1606,28 @@
}
if ($("#torrent_downloader_watchlist").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#transmission_options,#deluge_options").fadeOut("fast", function() { $("#watchlist_options").fadeIn() });
$("#utorrent_options,#rtorrent_options,#transmission_options,#deluge_options,#qbittorrent_options").fadeOut("fast", function() { $("#watchlist_options").fadeIn() });
}
if ($("#torrent_downloader_utorrent").is(":checked"))
{
$("#watchlist_options,#rtorrent_options,#transmission_options,#deluge_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() });
$("#watchlist_options,#rtorrent_options,#transmission_options,#deluge_options,#qbittorrent_options").fadeOut("fast", function() { $("#utorrent_options").fadeIn() });
}
if ($("#torrent_downloader_rtorrent").is(":checked"))
{
$("#utorrent_options,#watchlist_options,#transmission_options,#deluge_options").fadeOut("fast", function() { $("#rtorrent_options").fadeIn() });
$("#utorrent_options,#watchlist_options,#transmission_options,#deluge_options,#qbittorrent_options").fadeOut("fast", function() { $("#rtorrent_options").fadeIn() });
}
if ($("#torrent_downloader_transmission").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#deluge_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() });
$("#utorrent_options,#rtorrent_options,#watchlist_options,#deluge_options,#qbittorrent_options").fadeOut("fast", function() { $("#transmission_options").fadeIn() });
}
if ($("#torrent_downloader_deluge").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options").fadeOut("fast", function() { $("#deluge_options").fadeIn() });
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options,#qbittorrent_options").fadeOut("fast", function() { $("#deluge_options").fadeIn() });
}
if ($("#torrent_downloader_qbittorrent").is(":checked"))
{
$("#utorrent_options,#rtorrent_options,#watchlist_options,#transmission_options,#deluge_options").fadeOut("fast", function() { $("#qbittorrent_options").fadeIn() });
}
});
var deletedNewznabs = 0;
@ -1749,6 +1800,7 @@
initConfigCheckbox("#post_processing");
initConfigCheckbox("#enable_check_folder");
initConfigCheckbox("#enable_pre_scripts");
initConfigCheckbox("#enable_snatch_script");
initConfigCheckbox("#enable_extra_scripts");
}
$(document).ready(function() {

View File

@ -63,12 +63,8 @@
<td id="filename"><a href="comicDetails?ComicID=${item['ComicID']}">${item['ComicName']}</a></td>
<td id="issue">${item['Issue_Number']}</td>
<td id="status">${item['Status']}
%if item['Provider'] == '32P' or item['Provider'] == 'KAT' or item['Provider'] == 'CBT':
<img src="interfaces/default/images/torrent-icon.png" height="20" width="20" title="${item['Provider']}" />
%else:
%if item['Status'] != 'Downloaded' and item['Status'] != 'Post-Processed':
(${item['Provider']})
%endif
%if item['Status'] == 'Snatched':
(${item['Provider']})
%endif
</td>
<td id="action">[<a href="#" onclick="doAjaxCall('retryit?ComicName=${item['ComicName'] |u}&ComicID=${item['ComicID']}&IssueID=${item['IssueID']}&IssueNumber=${item['Issue_Number']}&redirect=history', $(this),'table')" data-success="Successful re-download of '${item['ComicName']}' '${item['Issue_Number']}'">retry</a>]</td>

22
lib/qbittorrent/LICENSE Normal file
View File

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Vikas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,2 @@
from .client import Client

633
lib/qbittorrent/client.py Normal file
View File

@ -0,0 +1,633 @@
import requests
import json
class LoginRequired(Exception):
def __str__(self):
return 'Please login first.'
class Client(object):
"""class to interact with qBittorrent WEB API"""
def __init__(self, url):
if not url.endswith('/'):
url += '/'
self.url = url
session = requests.Session()
check_prefs = session.get(url+'query/preferences')
if check_prefs.status_code == 200:
self._is_authenticated = True
self.session = session
elif check_prefs.status_code == 404:
self._is_authenticated = False
raise RuntimeError("""
This wrapper only supports qBittorrent applications
with version higher than 3.1.x.
Please use the latest qBittorrent release.
""")
else:
self._is_authenticated = False
def _get(self, endpoint, **kwargs):
"""
Method to perform GET request on the API.
:param endpoint: Endpoint of the API.
:param kwargs: Other keyword arguments for requests.
:return: Response of the GET request.
"""
return self._request(endpoint, 'get', **kwargs)
def _post(self, endpoint, data, **kwargs):
"""
Method to perform POST request on the API.
:param endpoint: Endpoint of the API.
:param data: POST DATA for the request.
:param kwargs: Other keyword arguments for requests.
:return: Response of the POST request.
"""
return self._request(endpoint, 'post', data, **kwargs)
def _request(self, endpoint, method, data=None, **kwargs):
"""
Method to hanle both GET and POST requests.
:param endpoint: Endpoint of the API.
:param method: Method of HTTP request.
:param data: POST DATA for the request.
:param kwargs: Other keyword arguments.
:return: Response for the request.
"""
final_url = self.url + endpoint
if not self._is_authenticated:
raise LoginRequired
rq = self.session
if method == 'get':
request = rq.get(final_url, **kwargs)
else:
request = rq.post(final_url, data, **kwargs)
request.raise_for_status()
request.encoding = 'utf_8'
if len(request.text) == 0:
data = json.loads('{}')
else:
try:
data = json.loads(request.text)
except ValueError:
data = request.text
return data
def login(self, username='admin', password='admin'):
"""
Method to authenticate the qBittorrent Client.
Declares a class attribute named ``session`` which
stores the authenticated session if the login is correct.
Else, shows the login error.
:param username: Username.
:param password: Password.
:return: Response to login request to the API.
"""
self.session = requests.Session()
login = self.session.post(self.url+'login',
data={'username': username,
'password': password})
if login.text == 'Ok.':
self._is_authenticated = True
else:
return login.text
def logout(self):
"""
Logout the current session.
"""
response = self._get('logout')
self._is_authenticated = False
return response
@property
def qbittorrent_version(self):
"""
Get qBittorrent version.
"""
return self._get('version/qbittorrent')
@property
def api_version(self):
"""
Get WEB API version.
"""
return self._get('version/api')
@property
def api_min_version(self):
"""
Get minimum WEB API version.
"""
return self._get('version/api_min')
def shutdown(self):
"""
Shutdown qBittorrent.
"""
return self._get('command/shutdown')
def torrents(self, **filters):
"""
Returns a list of torrents matching the supplied filters.
:param filter: Current status of the torrents.
:param category: Fetch all torrents with the supplied label.
:param sort: Sort torrents by.
:param reverse: Enable reverse sorting.
:param limit: Limit the number of torrents returned.
:param offset: Set offset (if less than 0, offset from end).
:return: list() of torrent with matching filter.
"""
params = {}
for name, value in filters.items():
# make sure that old 'status' argument still works
name = 'filter' if name == 'status' else name
params[name] = value
return self._get('query/torrents', params=params)
def get_torrent(self, infohash):
"""
Get details of the torrent.
:param infohash: INFO HASH of the torrent.
"""
return self._get('query/propertiesGeneral/' + infohash.lower())
def get_torrent_trackers(self, infohash):
"""
Get trackers for the torrent.
:param infohash: INFO HASH of the torrent.
"""
return self._get('query/propertiesTrackers/' + infohash.lower())
def get_torrent_webseeds(self, infohash):
"""
Get webseeds for the torrent.
:param infohash: INFO HASH of the torrent.
"""
return self._get('query/propertiesWebSeeds/' + infohash.lower())
def get_torrent_files(self, infohash):
"""
Get list of files for the torrent.
:param infohash: INFO HASH of the torrent.
"""
return self._get('query/propertiesFiles/' + infohash.lower())
@property
def global_transfer_info(self):
"""
Get JSON data of the global transfer info of qBittorrent.
"""
return self._get('query/transferInfo')
@property
def preferences(self):
"""
Get the current qBittorrent preferences.
Can also be used to assign individual preferences.
For setting multiple preferences at once,
see ``set_preferences`` method.
Note: Even if this is a ``property``,
to fetch the current preferences dict, you are required
to call it like a bound method.
Wrong::
qb.preferences
Right::
qb.preferences()
"""
prefs = self._get('query/preferences')
class Proxy(Client):
"""
Proxy class to to allow assignment of individual preferences.
this class overrides some methods to ease things.
Because of this, settings can be assigned like::
In [5]: prefs = qb.preferences()
In [6]: prefs['autorun_enabled']
Out[6]: True
In [7]: prefs['autorun_enabled'] = False
In [8]: prefs['autorun_enabled']
Out[8]: False
"""
def __init__(self, url, prefs, auth, session):
super(Proxy, self).__init__(url)
self.prefs = prefs
self._is_authenticated = auth
self.session = session
def __getitem__(self, key):
return self.prefs[key]
def __setitem__(self, key, value):
kwargs = {key: value}
return self.set_preferences(**kwargs)
def __call__(self):
return self.prefs
return Proxy(self.url, prefs, self._is_authenticated, self.session)
def sync(self, rid=0):
"""
Sync the torrents by supplied LAST RESPONSE ID.
Read more @ http://git.io/vEgXr
:param rid: Response ID of last request.
"""
return self._get('sync/maindata', params={'rid': rid})
def download_from_link(self, link, **kwargs):
"""
Download torrent using a link.
:param link: URL Link or list of.
:param savepath: Path to download the torrent.
:param category: Label or Category of the torrent(s).
:return: Empty JSON data.
"""
# old:new format
old_arg_map = {'save_path': 'savepath'} # , 'label': 'category'}
# convert old option names to new option names
options = kwargs.copy()
for old_arg, new_arg in old_arg_map.items():
if options.get(old_arg) and not options.get(new_arg):
options[new_arg] = options[old_arg]
options['urls'] = link
# workaround to send multipart/formdata request
# http://stackoverflow.com/a/23131823/4726598
dummy_file = {'_dummy': (None, '_dummy')}
return self._post('command/download', data=options, files=dummy_file)
def download_from_file(self, file_buffer, **kwargs):
"""
Download torrent using a file.
:param file_buffer: Single file() buffer or list of.
:param save_path: Path to download the torrent.
:param label: Label of the torrent(s).
:return: Empty JSON data.
"""
if isinstance(file_buffer, list):
torrent_files = {}
for i, f in enumerate(file_buffer):
torrent_files.update({'torrents%s' % i: f})
else:
torrent_files = {'torrents': file_buffer}
data = kwargs.copy()
if data.get('save_path'):
data.update({'savepath': data['save_path']})
return self._post('command/upload', data=data, files=torrent_files)
def add_trackers(self, infohash, trackers):
"""
Add trackers to a torrent.
:param infohash: INFO HASH of torrent.
:param trackers: Trackers.
"""
data = {'hash': infohash.lower(),
'urls': trackers}
return self._post('command/addTrackers', data=data)
@staticmethod
def _process_infohash_list(infohash_list):
"""
Method to convert the infohash_list to qBittorrent API friendly values.
:param infohash_list: List of infohash.
"""
if isinstance(infohash_list, list):
data = {'hashes': '|'.join([h.lower() for h in infohash_list])}
else:
data = {'hashes': infohash_list.lower()}
return data
def pause(self, infohash):
"""
Pause a torrent.
:param infohash: INFO HASH of torrent.
"""
return self._post('command/pause', data={'hash': infohash.lower()})
def pause_all(self):
"""
Pause all torrents.
"""
return self._get('command/pauseAll')
def pause_multiple(self, infohash_list):
"""
Pause multiple torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/pauseAll', data=data)
def set_label(self, infohash_list, label):
"""
Set the label on multiple torrents.
IMPORTANT: OLD API method, kept as it is to avoid breaking stuffs.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
data['label'] = label
return self._post('command/setLabel', data=data)
def set_category(self, infohash_list, category):
"""
Set the category on multiple torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
data['category'] = category
return self._post('command/setCategory', data=data)
def resume(self, infohash):
"""
Resume a paused torrent.
:param infohash: INFO HASH of torrent.
"""
return self._post('command/resume', data={'hash': infohash.lower()})
def resume_all(self):
"""
Resume all torrents.
"""
return self._get('command/resumeAll')
def resume_multiple(self, infohash_list):
"""
Resume multiple paused torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/resumeAll', data=data)
def delete(self, infohash_list):
"""
Delete torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/delete', data=data)
def delete_permanently(self, infohash_list):
"""
Permanently delete torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/deletePerm', data=data)
def recheck(self, infohash_list):
"""
Recheck torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/recheck', data=data)
def increase_priority(self, infohash_list):
"""
Increase priority of torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/increasePrio', data=data)
def decrease_priority(self, infohash_list):
"""
Decrease priority of torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/decreasePrio', data=data)
def set_max_priority(self, infohash_list):
"""
Set torrents to maximum priority level.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/topPrio', data=data)
def set_min_priority(self, infohash_list):
"""
Set torrents to minimum priority level.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/bottomPrio', data=data)
def set_file_priority(self, infohash, file_id, priority):
"""
Set file of a torrent to a supplied priority level.
:param infohash: INFO HASH of torrent.
:param file_id: ID of the file to set priority.
:param priority: Priority level of the file.
"""
if priority not in [0, 1, 2, 7]:
raise ValueError("Invalid priority, refer WEB-UI docs for info.")
elif not isinstance(file_id, int):
raise TypeError("File ID must be an int")
data = {'hash': infohash.lower(),
'id': file_id,
'priority': priority}
return self._post('command/setFilePrio', data=data)
# Get-set global download and upload speed limits.
def get_global_download_limit(self):
"""
Get global download speed limit.
"""
return self._get('command/getGlobalDlLimit')
def set_global_download_limit(self, limit):
"""
Set global download speed limit.
:param limit: Speed limit in bytes.
"""
return self._post('command/setGlobalDlLimit', data={'limit': limit})
global_download_limit = property(get_global_download_limit,
set_global_download_limit)
def get_global_upload_limit(self):
"""
Get global upload speed limit.
"""
return self._get('command/getGlobalUpLimit')
def set_global_upload_limit(self, limit):
"""
Set global upload speed limit.
:param limit: Speed limit in bytes.
"""
return self._post('command/setGlobalUpLimit', data={'limit': limit})
global_upload_limit = property(get_global_upload_limit,
set_global_upload_limit)
# Get-set download and upload speed limits of the torrents.
def get_torrent_download_limit(self, infohash_list):
"""
Get download speed limit of the supplied torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/getTorrentsDlLimit', data=data)
def set_torrent_download_limit(self, infohash_list, limit):
"""
Set download speed limit of the supplied torrents.
:param infohash_list: Single or list() of infohashes.
:param limit: Speed limit in bytes.
"""
data = self._process_infohash_list(infohash_list)
data.update({'limit': limit})
return self._post('command/setTorrentsDlLimit', data=data)
def get_torrent_upload_limit(self, infohash_list):
"""
Get upoload speed limit of the supplied torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/getTorrentsUpLimit', data=data)
def set_torrent_upload_limit(self, infohash_list, limit):
"""
Set upload speed limit of the supplied torrents.
:param infohash_list: Single or list() of infohashes.
:param limit: Speed limit in bytes.
"""
data = self._process_infohash_list(infohash_list)
data.update({'limit': limit})
return self._post('command/setTorrentsUpLimit', data=data)
# setting preferences
def set_preferences(self, **kwargs):
"""
Set preferences of qBittorrent.
Read all possible preferences @ http://git.io/vEgDQ
:param kwargs: set preferences in kwargs form.
"""
json_data = "json={}".format(json.dumps(kwargs))
headers = {'content-type': 'application/x-www-form-urlencoded'}
return self._post('command/setPreferences', data=json_data,
headers=headers)
def get_alternative_speed_status(self):
"""
Get Alternative speed limits. (1/0)
"""
return self._get('command/alternativeSpeedLimitsEnabled')
alternative_speed_status = property(get_alternative_speed_status)
def toggle_alternative_speed(self):
"""
Toggle alternative speed limits.
"""
return self._get('command/toggleAlternativeSpeedLimits')
def toggle_sequential_download(self, infohash_list):
"""
Toggle sequential download in supplied torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/toggleSequentialDownload', data=data)
def toggle_first_last_piece_priority(self, infohash_list):
"""
Toggle first/last piece priority of supplied torrents.
:param infohash_list: Single or list() of infohashes.
"""
data = self._process_infohash_list(infohash_list)
return self._post('command/toggleFirstLastPiecePrio', data=data)
def force_start(self, infohash_list, value=True):
"""
Force start selected torrents.
:param infohash_list: Single or list() of infohashes.
:param value: Force start value (bool)
"""
data = self._process_infohash_list(infohash_list)
data.update({'value': json.dumps(value)})
return self._post('command/setForceStart', data=data)

View File

@ -932,7 +932,7 @@ class PostProcessor(object):
comicid = tmpiss['ComicID']
comicname = tmpiss['ComicName']
issuenumber = tmpiss['Issue_Number']
#use issueid to get publisher, series, year, issue number
annchk = "no"
@ -1031,7 +1031,7 @@ class PostProcessor(object):
else:
arcpub = arcdata['Publisher']
grdst = helpers.arcformat(arc['StoryArc'], helpers.spantheyears(arcdata['StoryArcID']), arcpub)
grdst = helpers.arcformat(arcdata['StoryArc'], helpers.spantheyears(arcdata['StoryArcID']), arcpub)
if comicid is None:
comicid = arcdata['ComicID']

View File

@ -83,7 +83,7 @@ WeeklyScheduler = None
VersionScheduler = None
FolderMonitorScheduler = None
QUEUE = Queue.Queue()
SNATCHED_QUEUE = Queue.Queue()
DATA_DIR = None
DBLOCK = False
@ -298,10 +298,13 @@ QUAL_SCANNER = None
QUAL_TYPE = None
QUAL_QUALITY = None
ENABLE_EXTRA_SCRIPTS = 1
ENABLE_EXTRA_SCRIPTS = False
EXTRA_SCRIPTS = None
ENABLE_PRE_SCRIPTS = 1
ENABLE_SNATCH_SCRIPT = False
SNATCH_SCRIPT = None
ENABLE_PRE_SCRIPTS = False
PRE_SCRIPTS = None
COUNT_COMICS = 0
@ -328,7 +331,7 @@ ARC_FOLDERFORMAT = None
ARC_FILEOPS = 'copy'
CVURL = None
CV_VERIFY = 0
CV_VERIFY = True
CURRENT_WEEKNUMBER = None
CURRENT_YEAR = None
PULL_REFRESH = None
@ -369,9 +372,10 @@ FAILED_DOWNLOAD_HANDLING = 0
FAILED_AUTO = 0
ENABLE_TORRENTS = 0
TORRENT_DOWNLOADER = None #0 = watchfolder, #1 = uTorrent, #2 = rTorrent, #3 = transmission
TORRENT_DOWNLOADER = None #0 = watchfolder, #1 = uTorrent, #2 = rTorrent, #3 = transmission, #4 = deluge, #5 = qbittorrent
MINSEEDS = 0
AUTO_SNATCH = False
ALLOW_PACKS = False
USE_WATCHDIR = False
@ -433,6 +437,13 @@ DELUGE_USERNAME = None
DELUGE_PASSWORD = None
DELUGE_LABEL = None
USE_QBITTORRENT = False
QBITTORRENT_HOST = None
QBITTORRENT_USERNAME = None
QBITTORRENT_PASSWORD = None
QBITTORRENT_LABEL = None
QBITTORRENT_FOLDER = None
QBITTORRENT_STARTONLOAD = 0
def CheckSection(sec):
""" Check if INI section exists, if not create it """
@ -484,7 +495,7 @@ def initialize():
with INIT_LOCK:
global __INITIALIZED__, DBCHOICE, DBUSER, DBPASS, DBNAME, DYNAMIC_UPDATE, COMICVINE_API, DEFAULT_CVAPI, CVAPI_RATE, CV_HEADERS, BLACKLISTED_PUBLISHERS, FULL_PATH, PROG_DIR, VERBOSE, DAEMON, UPCOMING_SNATCHED, COMICSORT, DATA_DIR, CONFIG_FILE, CFG, CONFIG_VERSION, LOG_DIR, CACHE_DIR, MAX_LOGSIZE, OLDCONFIG_VERSION, OS_DETECT, \
queue, WANTED_TAB_OFF, LOCAL_IP, EXT_IP, HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, HTTPS_CHAIN, HTTPS_FORCE_ON, HOST_RETURN, API_ENABLED, API_KEY, DOWNLOAD_APIKEY, LAUNCH_BROWSER, GIT_PATH, SAFESTART, NOWEEKLY, AUTO_UPDATE, \
SNATCHED_QUEUE, SNPOOL, AUTO_SNATCH, WANTED_TAB_OFF, LOCAL_IP, EXT_IP, HTTP_PORT, HTTP_HOST, HTTP_USERNAME, HTTP_PASSWORD, HTTP_ROOT, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, HTTPS_CHAIN, HTTPS_FORCE_ON, HOST_RETURN, API_ENABLED, API_KEY, DOWNLOAD_APIKEY, LAUNCH_BROWSER, GIT_PATH, SAFESTART, NOWEEKLY, AUTO_UPDATE, \
IMPORT_STATUS, IMPORT_FILES, IMPORT_TOTALFILES, IMPORT_CID_COUNT, IMPORT_PARSED_COUNT, IMPORT_FAILURE_COUNT, CHECKENABLED, \
CURRENT_VERSION, LATEST_VERSION, CHECK_GITHUB, CHECK_GITHUB_ON_STARTUP, CHECK_GITHUB_INTERVAL, GIT_USER, GIT_BRANCH, USER_AGENT, DESTINATION_DIR, MULTIPLE_DEST_DIRS, CREATE_FOLDERS, DELETE_REMOVE_DIR, \
DOWNLOAD_DIR, USENET_RETENTION, SEARCH_INTERVAL, NZB_STARTUP_SEARCH, INTERFACE, DUPECONSTRAINT, DDUMP, DUPLICATE_DUMP, AUTOWANT_ALL, AUTOWANT_UPCOMING, ZERO_LEVEL, ZERO_LEVEL_N, COMIC_COVER_LOCAL, HIGHCOUNT, \
@ -494,6 +505,7 @@ def initialize():
ENABLE_TORZNAB, TORZNAB_NAME, TORZNAB_HOST, TORZNAB_APIKEY, TORZNAB_CATEGORY, TORZNAB_VERIFY, EXPERIMENTAL, ALTEXPERIMENTAL, \
USE_RTORRENT, RTORRENT_HOST, RTORRENT_AUTHENTICATION, RTORRENT_RPC_URL, RTORRENT_SSL, RTORRENT_VERIFY, RTORRENT_CA_BUNDLE, 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, TRANSMISSION_DIRECTORY, USE_DELUGE, DELUGE_HOST, DELUGE_USERNAME, DELUGE_PASSWORD, DELUGE_LABEL, \
USE_QBITTORRENT, QBITTORRENT_HOST, QBITTORRENT_USERNAME, QBITTORRENT_PASSWORD, QBITTORRENT_LABEL, QBITTORRENT_FOLDER, QBITTORRENT_STARTONLOAD, \
ENABLE_META, CMTAGGER_PATH, CBR2CBZ_ONLY, CT_TAG_CR, CT_TAG_CBL, CT_CBZ_OVERWRITE, UNRAR_CMD, CT_SETTINGSPATH, CMTAG_VOLUME, CMTAG_START_YEAR_AS_VOLUME, UPDATE_ENDED, INDIE_PUB, BIGGIE_PUB, IGNORE_HAVETOTAL, SNATCHED_HAVETOTAL, PROVIDER_ORDER, TMP_PROV, \
dbUpdateScheduler, searchScheduler, RSSScheduler, WeeklyScheduler, VersionScheduler, FolderMonitorScheduler, \
ALLOW_PACKS, ENABLE_TORRENTS, TORRENT_DOWNLOADER, MINSEEDS, USE_WATCHDIR, TORRENT_LOCAL, LOCAL_WATCHDIR, TORRENT_SEEDBOX, SEEDBOX_HOST, SEEDBOX_PORT, SEEDBOX_USER, SEEDBOX_PASS, SEEDBOX_WATCHDIR, \
@ -504,7 +516,7 @@ def initialize():
FOLDER_FORMAT, SETDEFAULTVOLUME, FILE_FORMAT, REPLACE_CHAR, REPLACE_SPACES, ADD_TO_CSV, CVINFO, LOG_LEVEL, POST_PROCESSING, POST_PROCESSING_SCRIPT, \
FILE_OPTS, SEARCH_DELAY, GRABBAG_DIR, READ2FILENAME, SEND2READ, MAINTAINSERIESFOLDER, TAB_ENABLE, TAB_HOST, TAB_USER, TAB_PASS, TAB_DIRECTORY, \
STORYARCDIR, COPY2ARCDIR, ARC_FOLDERFORMAT, ARC_FILEOPS, CVURL, CV_VERIFY, CHECK_FOLDER, ENABLE_CHECK_FOLDER, \
COMIC_LOCATION, QUAL_ALTVERS, QUAL_SCANNER, QUAL_TYPE, QUAL_QUALITY, ENABLE_EXTRA_SCRIPTS, EXTRA_SCRIPTS, ENABLE_PRE_SCRIPTS, PRE_SCRIPTS, PULLNEW, ALT_PULL, PULLBYFILE, COUNT_ISSUES, COUNT_HAVES, COUNT_COMICS, \
COMIC_LOCATION, QUAL_ALTVERS, QUAL_SCANNER, QUAL_TYPE, QUAL_QUALITY, ENABLE_EXTRA_SCRIPTS, EXTRA_SCRIPTS, ENABLE_SNATCH_SCRIPT, SNATCH_SCRIPT, ENABLE_PRE_SCRIPTS, PRE_SCRIPTS, PULLNEW, ALT_PULL, PULLBYFILE, COUNT_ISSUES, COUNT_HAVES, COUNT_COMICS, \
SYNO_FIX, ENFORCE_PERMS, CHMOD_FILE, CHMOD_DIR, CHOWNER, CHGROUP, ANNUALS_ON, CV_ONLY, CV_ONETIMER, CURRENT_WEEKNUMBER, CURRENT_YEAR, PULL_REFRESH, WEEKFOLDER, WEEKFOLDER_LOC, WEEKFOLDER_FORMAT, UMASK, \
TELEGRAM_ENABLED, TELEGRAM_TOKEN, TELEGRAM_USERID
@ -550,7 +562,7 @@ def initialize():
if not COMICVINE_API:
COMICVINE_API = None
CVAPI_RATE = check_setting_int(CFG, 'General', 'cvapi_rate', 2)
CV_VERIFY = bool(check_setting_int(CFG, 'General', 'cv_verify', 0))
CV_VERIFY = bool(check_setting_int(CFG, 'General', 'cv_verify', 1))
HTTP_HOST = check_setting_str(CFG, 'General', 'http_host', '0.0.0.0')
HTTP_USERNAME = check_setting_str(CFG, 'General', 'http_username', '')
HTTP_PASSWORD = check_setting_str(CFG, 'General', 'http_password', '')
@ -707,7 +719,8 @@ def initialize():
LOG_LEVEL = check_setting_str(CFG, 'General', 'log_level', '')
ENABLE_EXTRA_SCRIPTS = bool(check_setting_int(CFG, 'General', 'enable_extra_scripts', 0))
EXTRA_SCRIPTS = check_setting_str(CFG, 'General', 'extra_scripts', '')
ENABLE_SNATCH_SCRIPT = bool(check_setting_int(CFG, 'General', 'enable_snatch_script', 0))
SNATCH_SCRIPT = check_setting_str(CFG, 'General', 'snatch_script', '')
ENABLE_PRE_SCRIPTS = bool(check_setting_int(CFG, 'General', 'enable_pre_scripts', 0))
PRE_SCRIPTS = check_setting_str(CFG, 'General', 'pre_scripts', '')
POST_PROCESSING = bool(check_setting_int(CFG, 'General', 'post_processing', 1))
@ -753,6 +766,7 @@ def initialize():
SEEDBOX_WATCHDIR = check_setting_str(CFG, 'Torrents', 'seedbox_watchdir', '')
ENABLE_TORRENT_SEARCH = bool(check_setting_int(CFG, 'Torrents', 'enable_torrent_search', 0))
AUTO_SNATCH = bool(check_setting_int(CFG, 'Torrents', 'auto_snatch', 0))
ENABLE_TPSE = bool(check_setting_int(CFG, 'Torrents', 'enable_tpse', 0))
TPSE_PROXY = check_setting_str(CFG, 'Torrents', 'tpse_proxy', '')
TPSE_VERIFY = bool(check_setting_int(CFG, 'Torrents', 'tpse_verify', 1))
@ -854,6 +868,9 @@ def initialize():
elif TORRENT_DOWNLOADER == 4:
TORRENT_LOCAL = False
USE_DELUGE = True
elif TORRENT_DOWNLOADER == 5:
TORRENT_LOCAL = False
USE_QBITTORRENT = True
else:
TORRENT_DOWNLOADER = 0
USE_WATCHDIR = True
@ -873,6 +890,13 @@ def initialize():
DELUGE_USERNAME = check_setting_str(CFG, 'Deluge', 'deluge_username', '')
DELUGE_PASSWORD = check_setting_str(CFG, 'Deluge', 'deluge_password', '')
DELUGE_LABEL = check_setting_str(CFG, 'Deluge', 'deluge_label', '')
QBITTORRENT_HOST = check_setting_str(CFG, 'qBittorrent', 'qbittorrent_host', '')
QBITTORRENT_USERNAME = check_setting_str(CFG, 'qBittorrent', 'qbittorrent_username', '')
QBITTORRENT_PASSWORD = check_setting_str(CFG, 'qBittorrent', 'qbittorrent_password', '')
QBITTORRENT_LABEL = check_setting_str(CFG, 'qBittorrent', 'qbitttorent_label', '')
QBITTORRENT_FOLDER = check_setting_str(CFG, 'qBittorrent', 'qbitttorent_folder', '')
QBITTORRENT_STARTONLOAD = bool(check_setting_int(CFG, 'qBittorrent', 'qbitttorent_startonload', 0))
#add torrents to provider counter.
if ENABLE_TORRENT_SEARCH:
@ -1237,6 +1261,8 @@ def initialize():
if LOCMOVE:
helpers.updateComicLocation()
SNPOOL = None
#logger.fdebug('platform detected as : ' + OS_DETECT)
#Ordering comics here
@ -1288,7 +1314,6 @@ def initialize():
runImmediately=True,
delay=60)
# Store the original umask
UMASK = os.umask(0)
os.umask(UMASK)
@ -1485,6 +1510,8 @@ def config_write():
new_config['General']['log_level'] = LOG_LEVEL
new_config['General']['enable_extra_scripts'] = int(ENABLE_EXTRA_SCRIPTS)
new_config['General']['extra_scripts'] = EXTRA_SCRIPTS
new_config['General']['enable_snatch_script'] = int(ENABLE_SNATCH_SCRIPT)
new_config['General']['snatch_script'] = SNATCH_SCRIPT
new_config['General']['enable_pre_scripts'] = int(ENABLE_PRE_SCRIPTS)
new_config['General']['pre_scripts'] = PRE_SCRIPTS
new_config['General']['post_processing'] = int(POST_PROCESSING)
@ -1531,6 +1558,7 @@ def config_write():
new_config['Torrents'] = {}
new_config['Torrents']['enable_torrents'] = int(ENABLE_TORRENTS)
new_config['Torrents']['auto_snatch'] = int(AUTO_SNATCH)
new_config['Torrents']['minseeds'] = int(MINSEEDS)
new_config['Torrents']['torrent_local'] = int(TORRENT_LOCAL)
new_config['Torrents']['local_watchdir'] = LOCAL_WATCHDIR
@ -1591,12 +1619,12 @@ def config_write():
new_config['NZBsu']['nzbsu'] = int(NZBSU)
new_config['NZBsu']['nzbsu_uid'] = NZBSU_UID
new_config['NZBsu']['nzbsu_apikey'] = NZBSU_APIKEY
new_config['NZBsu']['nzbsu_verify'] = NZBSU_VERIFY
new_config['NZBsu']['nzbsu_verify'] = int(NZBSU_VERIFY)
new_config['DOGnzb'] = {}
new_config['DOGnzb']['dognzb'] = int(DOGNZB)
new_config['DOGnzb']['dognzb_apikey'] = DOGNZB_APIKEY
new_config['DOGnzb']['dognzb_verify'] = DOGNZB_VERIFY
new_config['DOGnzb']['dognzb_verify'] = int(DOGNZB_VERIFY)
new_config['Experimental'] = {}
new_config['Experimental']['experimental'] = int(EXPERIMENTAL)
@ -1608,7 +1636,7 @@ def config_write():
new_config['Torznab']['torznab_host'] = TORZNAB_HOST
new_config['Torznab']['torznab_apikey'] = TORZNAB_APIKEY
new_config['Torznab']['torznab_category'] = TORZNAB_CATEGORY
new_config['Torznab']['torznab_verify'] = TORZNAB_VERIFY
new_config['Torznab']['torznab_verify'] = int(TORZNAB_VERIFY)
new_config['Newznab'] = {}
new_config['Newznab']['newznab'] = int(NEWZNAB)
@ -1630,7 +1658,15 @@ def config_write():
new_config['Deluge']['deluge_username'] = DELUGE_USERNAME
new_config['Deluge']['deluge_password'] = DELUGE_PASSWORD
new_config['Deluge']['deluge_label'] = DELUGE_LABEL
new_config['qBittorrent'] = {}
new_config['qBittorrent']['qbittorrent_host'] = QBITTORRENT_HOST
new_config['qBittorrent']['qbittorrent_username'] = QBITTORRENT_USERNAME
new_config['qBittorrent']['qbittorrent_password'] = QBITTORRENT_PASSWORD
new_config['qBittorrent']['qbittorrent_label'] = QBITTORRENT_LABEL
new_config['qBittorrent']['qbittorrent_folder'] = QBITTORRENT_FOLDER
new_config['qBittorrent']['qbittorrent_startonload'] = int(QBITTORRENT_STARTONLOAD)
# Need to unpack the extra newznabs for saving in config.ini
flattened_newznabs = []
for newznab in EXTRA_NEWZNABS:
@ -1694,6 +1730,12 @@ def start():
#SCHED.add_interval_job(updater.dbUpdate, hours=48)
#SCHED.add_interval_job(search.searchforissue, minutes=SEARCH_INTERVAL)
if all([ENABLE_TORRENTS, AUTO_SNATCH, OS_DETECT != 'Windows']) and any([TORRENT_DOWNLOADER == 2, TORRENT_DOWNLOADER == 4]):
logger.info('Auto-Snatch of comleted torrents enabled & attempting to backgroun load....')
SNPOOL = threading.Thread(target=helpers.worker_main, args=(SNATCHED_QUEUE,), name="AUTO-SNATCHER")
SNPOOL.start()
logger.info('Succesfully started Auto-Snatch add-on - will now monitor for completed torrents on client....')
#start the db updater scheduler
logger.info('Initializing the DB Updater.')
dbUpdateScheduler.thread.start()
@ -2396,6 +2438,17 @@ def halt():
except:
pass
if SNPOOL is not None:
logger.info('Terminating the auto-snatch thread.')
try:
SNPOOL.join(10)
logger.info('Joined pool for termination - successful')
except KeyboardInterrupt:
SNATCHED_QUEUE.put('exit')
SNPOOL.join(5)
except AssertionError:
os._exit(0)
__INITIALIZED__ = False
def shutdown(restart=False, update=False):

View File

@ -1,4 +1,5 @@
# This file is part of Mylar.
# -*- coding: utf-8 -*-
#
# Mylar is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -17,7 +18,11 @@ import time
from operator import itemgetter
import datetime
from datetime import timedelta, date
import subprocess
import shlex
import json
import re
import sys
import platform
import itertools
import shutil
@ -247,7 +252,12 @@ def decimal_issue(iss):
def rename_param(comicid, comicname, issue, ofilename, comicyear=None, issueid=None, annualize=None, arc=False):
import db, logger
myDB = db.DBConnection()
logger.fdebug('comicid: ' + str(comicid))
comicid = str(comicid) # it's coming in unicoded...
logger.fdebug(type(comicid))
logger.fdebug(type(issueid))
logger.fdebug(type(issue))
logger.fdebug('comicid: ' + comicid)
logger.fdebug('issue#: ' + issue)
# the issue here is a non-decimalized version, we need to see if it's got a decimal and if not, add '.00'
# iss_find = issue.find('.')
@ -275,7 +285,7 @@ def rename_param(comicid, comicname, issue, ofilename, comicyear=None, issueid=N
#this has to be adjusted to be able to include story arc issues that span multiple arcs
chkissue = myDB.selectone("SELECT * from readinglist WHERE ComicID=? AND Issue_Number=?", [comicid, issue]).fetchone()
else:
if annualize is None:
if all([annualize is None, not mylar.ANNUALS_ON]):
chkissue = myDB.selectone("SELECT * from issues WHERE ComicID=? AND Issue_Number=?", [comicid, issue]).fetchone()
else:
chkissue = myDB.selectone("SELECT * from annuals WHERE ComicID=? AND Issue_Number=?", [comicid, issue]).fetchone()
@ -286,13 +296,12 @@ def rename_param(comicid, comicname, issue, ofilename, comicyear=None, issueid=N
chkissue = myDB.selectone("SELECT * from readinglist WHERE ComicID=? AND Int_IssueNumber=?", [comicid, issuedigits(issue)]).fetchone()
else:
chkissue = myDB.selectone("SELECT * from issues WHERE ComicID=? AND Int_IssueNumber=?", [comicid, issuedigits(issue)]).fetchone()
if annualize:
if all([annualize == 'yes', mylar.ANNUALS_ON]):
chkissue = myDB.selectone("SELECT * from annuals WHERE ComicID=? AND Int_IssueNumber=?", [comicid, issuedigits(issue)]).fetchone()
if chkissue is None:
if chkissue is None:
logger.error('Invalid Issue_Number - please validate.')
return
logger.error('Invalid Issue_Number - please validate.')
return
else:
logger.info('Int Issue_number compare found. continuing...')
issueid = chkissue['IssueID']
@ -371,7 +380,7 @@ def rename_param(comicid, comicname, issue, ofilename, comicyear=None, issueid=N
for issexcept in issue_exceptions:
if issexcept.lower() in issuenum.lower():
logger.fdebug('ALPHANUMERIC EXCEPTION : [' + issexcept + ']')
v_chk = [v in issuenum for v in valid_spaces]
v_chk = [v for v in valid_spaces if v in issuenum]
if v_chk:
iss_space = v_chk[0]
logger.fdebug('character space denoted as : ' + iss_space)
@ -960,9 +969,9 @@ def issuedigits(issnum):
x = [vals[key] for key in vals if key in issnum]
if x:
logger.fdebug('Unicode Issue present - adjusting.')
#logger.fdebug('Unicode Issue present - adjusting.')
int_issnum = x[0] * 1000
logger.fdebug('int_issnum: ' + str(int_issnum))
#logger.fdebug('int_issnum: ' + str(int_issnum))
else:
if any(['.' in issnum, ',' in issnum]):
#logger.fdebug('decimal detected.')
@ -2544,6 +2553,110 @@ def arcformat(arc, spanyears, publisher):
return dstloc
def torrentinfo(issueid=None, torrent_hash=None, download=False):
import db
from base64 import b16encode, b32decode
#check the status of the issueid to make sure it's in Snatched status and was grabbed via torrent.
if issueid:
myDB = db.DBConnection()
cinfo = myDB.selectone('SELECT a.Issue_Number, a.ComicName, a.Status, b.Hash from issues as a inner join snatched as b ON a.IssueID=b.IssueID WHERE a.IssueID=?', [issueid]).fetchone()
if cinfo is None:
logger.warn('Unable to locate IssueID of : ' + issueid)
snatch_status = 'ERROR'
if cinfo['Status'] != 'Snatched' or cinfo['Hash'] is None:
logger.warn(cinfo['ComicName'] + ' #' + cinfo['Issue_Number'] + ' is currently in a ' + cinfo['Status'] + ' Status.')
snatch_status = 'ERROR'
torrent_hash = cinfo['Hash']
logger.fdebug("Working on torrent: " + torrent_hash)
if len(torrent_hash) == 32:
torrent_hash = b16encode(b32decode(torrent_hash))
if not len(torrent_hash) == 40:
logger.error("Torrent hash is missing, or an invalid hash value has been passed")
snatch_status = 'ERROR'
else:
if mylar.USE_RTORRENT:
import test
rp = test.RTorrent()
torrent_info = rp.main(torrent_hash, check=True)
elif mylar.USE_DELUGE:
#need to set the connect here as well....
import torrent.clients.deluge as delu
dp = delu.TorrentClient()
if not dp.connect(mylar.DELUGE_HOST, mylar.DELUGE_USERNAME, mylar.DELUGE_PASSWORD):
logger.warn('Not connected to Deluge!')
torrent_info = dp.get_torrent(torrent_hash)
else:
snatch_status = 'ERROR'
return
if torrent_info is False or len(torrent_info) == 0:
logger.warn('torrent returned no information. Check logs - aborting auto-snatch at this time.')
snatch_status = 'ERROR'
else:
if mylar.USE_DELUGE:
torrent_status = torrent_info['is_finished']
torrent_files = torrent_info['num_files']
torrent_folder = torrent_info['save_path']
elif mylar.USE_RTORRENT:
torrent_status = torrent_info['completed']
torrent_files = len(torrent_info['files'])
torrent_folder = torrent_info['folder']
if all([torrent_status is True, download is True]):
if not issueid:
torrent_info['snatch_status'] = 'STARTING...'
#yield torrent_info
import shlex, subprocess
logger.info('Torrent is completed and status is currently Snatched. Attempting to auto-retrieve.')
with open(mylar.SNATCH_SCRIPT, 'r') as f:
first_line = f.readline()
if mylar.SNATCH_SCRIPT.endswith('.sh'):
shell_cmd = re.sub('#!', '', first_line)
if shell_cmd == '' or shell_cmd is None:
shell_cmd = '/bin/bash'
else:
shell_cmd = sys.executable
curScriptName = shell_cmd + ' ' + str(mylar.SNATCH_SCRIPT).decode("string_escape")
if torrent_files > 1:
downlocation = torrent_folder
else:
downlocation = os.path.join(torrent_folder, torrent_info['name'])
downlocation = re.sub("'", "\\'", downlocation)
script_cmd = shlex.split(curScriptName, posix=False) + [downlocation]
logger.fdebug(u"Executing command " +str(script_cmd))
try:
p = subprocess.Popen(script_cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=mylar.PROG_DIR)
out, err = p.communicate()
logger.fdebug(u"Script result: " + out)
except OSError, e:
logger.warn(u"Unable to run extra_script: " + e)
snatch_status = 'ERROR'
else:
if 'Access failed: No such file' in out:
logger.fdebug('Not located in location it is supposed to be in - probably has been moved by some script and I got the wrong location due to timing. Trying again...')
snatch_status = 'IN PROGRESS'
else:
snatch_status = 'COMPLETED'
else:
if download is True:
snatch_status = 'IN PROGRESS'
else:
snatch_status = 'NOT SNATCHED'
torrent_info['snatch_status'] = snatch_status
return torrent_info
def weekly_info(week=None, year=None):
#find the current week and save it as a reference point.
todaydate = datetime.datetime.today()
@ -2636,6 +2749,99 @@ def latestdate_update():
ctrlVal = {'ComicID': a['ComicID']}
logger.info('updating latest date for : ' + a['ComicID'] + ' to ' + a['LatestDate'] + ' #' + a['LatestIssue'])
myDB.upsert("comics", newVal, ctrlVal)
def worker_main(queue):
while True:
item = queue.get(True)
logger.info('Now loading from queue: ' + item)
if item == 'exit':
logger.info('Cleaning up workers for shutdown')
break
snstat = torrentinfo(torrent_hash=item, download=True)
if snstat['snatch_status'] == 'IN PROGRESS':
logger.info('Still downloading in client....let us try again momentarily.')
time.sleep(15)
mylar.SNATCHED_QUEUE.put(item)
def script_env(mode, vars):
#mode = on-snatch, pre-postprocess, post-postprocess
#var = dictionary containing variables to pass
if mode == 'on-snatch':
runscript = mylar.SNATCH_SCRIPT
if 'torrentinfo' in vars:
os.environ['mylar_release_hash'] = vars['torrentinfo']['hash']
os.environ['mylar_release_name'] = vars['torrentinfo']['name']
os.environ['mylar_release_folder'] = vars['torrentinfo']['folder']
os.environ['mylar_release_label'] = vars['torrentinfo']['label']
os.environ['mylar_release_filesize'] = str(vars['torrentinfo']['total_filesize'])
os.environ['mylar_release_start'] = str(vars['torrentinfo']['time_started'])
try:
os.environ['mylar_release_files'] = "|".join(vars['torrentinfo']['files'])
except TypeError:
os.environ['mylar_release_files'] = "|".join(json.dumps(vars['torrentinfo']['files']))
elif 'nzbinfo' in vars:
os.environ['mylar_release_id'] = vars['nzbinfo']['id']
os.environ['mylar_release_nzbname'] = vars['nzbinfo']['nzbname']
os.environ['mylar_release_link'] = vars['nzbinfo']['link']
os.environ['mylar_release_nzbpath'] = vars['nzbinfo']['nzbpath']
if 'blackhole' in vars['nzbinfo']:
os.environ['mylar_release_blackhole'] = vars['nzbinfo']['blackhole']
os.environ['mylar_release_provider'] = vars['provider']
if 'comicinfo' in vars:
os.environ['mylar_comicid'] = vars['comicinfo']['comicid']
os.environ['mylar_issueid'] = vars['comicinfo']['issueid']
os.environ['mylar_comicname'] = vars['comicinfo']['comicname']
os.environ['mylar_issuenumber'] = vars['comicinfo']['issuenumber']
try:
os.environ['mylar_comicvolume'] = str(vars['comicinfo']['volume'])
except:
pass
try:
os.environ['mylar_seriesyear'] = vars['comicinfo']['seriesyear']
except:
pass
try:
os.environ['mylar_issuedate'] = vars['comicinfo']['issuedate']
except:
pass
os.environ['mylar_release_pack'] = str(vars['pack'])
if vars['pack'] is True:
os.environ['mylar_release_pack_numbers'] = vars['pack_numbers']
os.environ['mylar_release_pack_issuelist'] = vars['pack_issuelist']
os.environ['mylar_method'] = vars['method']
os.environ['mylar_client'] = vars['clientmode']
elif mode == 'post-process':
#to-do
runscript = mylar.EXTRA_SCRIPTS
elif mode == 'pre-process':
#to-do
runscript = mylar.PRE_SCRIPTS
logger.fdebug('Initiating ' + mode + ' script detection.')
with open(runscript, 'r') as f:
first_line = f.readline()
if runscript.endswith('.sh'):
shell_cmd = re.sub('#!', '', first_line)
if shell_cmd == '' or shell_cmd is None:
shell_cmd = '/bin/bash'
else:
shell_cmd = sys.executable
curScriptName = shell_cmd + ' ' + runscript.decode("string_escape")
logger.fdebug("snatch script detected...enabling: " + str(curScriptName))
script_cmd = shlex.split(curScriptName)
logger.fdebug(u"Executing command " +str(script_cmd))
try:
subprocess.call(script_cmd, env=dict(os.environ))
except OSError, e:
logger.warn(u"Unable to run extra_script: " + str(script_cmd))
return False
else:
return True
def file_ops(path,dst,arc=False,one_off=False):
# # path = source path + filename

View File

@ -193,8 +193,6 @@ def addComictoDB(comicid, mismatch=None, pullupd=None, imported=None, ogcname=No
comicVol = oldcomversion
if all([mylar.SETDEFAULTVOLUME is True, comicVol is None]):
comicVol = 'v1'
else:
comicVol = None
@ -206,6 +204,9 @@ def addComictoDB(comicid, mismatch=None, pullupd=None, imported=None, ogcname=No
if comlocation is None:
comicdir = comicname_filesafe
series = comicdir
if series[-1:] == '.':
series[:-1]
publisher = re.sub('!', '', comic['ComicPublisher']) # thanks Boom!
publisher = helpers.filesafe(publisher)
year = SeriesYear
@ -395,6 +396,7 @@ def addComictoDB(comicid, mismatch=None, pullupd=None, imported=None, ogcname=No
"ComicPublisher": comic['ComicPublisher'],
# "Description": Cdesc, #.dencode('utf-8', 'replace'),
"DetailURL": comic['ComicURL'],
# "AlternateSearch": comic['Aliases'],
# "ComicPublished": gcdinfo['resultPublished'],
"ComicPublished": "Unknown",
"Type": comic['Type'],

View File

@ -84,11 +84,13 @@ def locg(pulldate=None,weeknumber=None,year=None):
shipdate = x['shipdate']
myDB = db.DBConnection()
#myDB.action("drop table if exists weekly")
myDB.action("CREATE TABLE IF NOT EXISTS weekly (SHIPDATE, PUBLISHER text, ISSUE text, COMIC VARCHAR(150), EXTRA text, STATUS text, ComicID text, IssueID text, CV_Last_Update text, DynamicName text, weeknumber text, year text, rowid INTEGER PRIMARY KEY)")
#clear out the upcoming table here so they show the new values properly.
#myDB.action('DELETE FROM UPCOMING WHERE IssueDate=?',[shipdate])
if pulldate == '00000000':
logger.info('Re-creating pullist to ensure everything\'s fresh.')
myDB.action('DELETE FROM weekly WHERE weeknumber=? AND year=?',[str(weeknumber), str(year)])
for x in pull:
comicid = None

View File

@ -17,6 +17,7 @@ import mylar
from mylar import db, logger, ftpsshup, helpers, auth32p, utorrent
import torrent.clients.transmission as transmission
import torrent.clients.deluge as deluge
import torrent.clients.qbittorrent as qbittorrent
def _start_newznab_attr(self, attrsD):
context = self._getContext()
@ -226,7 +227,11 @@ def torrents(pickfeed=None, seriesname=None, issue=None, feedinfo=None):
for entry in feedme['entries']:
#TP.SE RSS SEARCH RESULT
if pickfeed == "2":
tmpenc = feedme.entries[i].enclosures[0]
try:
tmpenc = feedme.entries[i].enclosures[0]
except AttributeError:
logger.warn('Unable to retrieve results - probably just hitting it too fast...')
continue
torthetpse.append({
'site': picksite,
'title': feedme.entries[i].title,
@ -777,7 +782,7 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
if linkit[-7:] != "torrent":
filename += ".torrent"
if any([mylar.USE_UTORRENT, mylar.USE_RTORRENT, mylar.USE_TRANSMISSION,mylar.USE_DELUGE]):
if any([mylar.USE_UTORRENT, mylar.USE_RTORRENT, mylar.USE_TRANSMISSION, mylar.USE_DELUGE, mylar.USE_QBITTORRENT]):
filepath = os.path.join(mylar.CACHE_DIR, filename)
logger.fdebug('filename for torrent set to : ' + filepath)
@ -921,7 +926,6 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
except ImportError:
logger.warn('[EPIC FAILURE] Cannot load the requests module')
return "fail"
try:
scraper = cfscrape.create_scraper()
if cf_cookievalue:
@ -1003,27 +1007,36 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
logger.fdebug('[' + site + '] Saved torrent file to : ' + filepath)
if mylar.USE_UTORRENT:
uTC = utorrent.utorrentclient()
resp = uTC.addfile(filepath, filename)
return resp #resp = pass / fail
torrent_info = uTC.addfile(filepath, filename)
if torrent_info:
torrent_info['clientmode'] = 'utorrent'
torrent_info['link'] = linkit
return torrent_info
else:
return "fail"
elif mylar.USE_RTORRENT:
import test
rp = test.RTorrent()
torrent_info = rp.main(filepath=filepath)
logger.info(torrent_info)
if torrent_info:
return "pass"
torrent_info['clientmode'] = 'rtorrent'
torrent_info['link'] = linkit
return torrent_info
else:
return "fail"
return 'fail'
elif mylar.USE_TRANSMISSION:
try:
rpc = transmission.TorrentClient()
if not rpc.connect(mylar.TRANSMISSION_HOST, mylar.TRANSMISSION_USERNAME, mylar.TRANSMISSION_PASSWORD):
return "fail"
if rpc.load_torrent(filepath):
return "pass"
torrent_info = rpc.load_torrent(filepath)
if torrent_info:
torrent_info['clientmode'] = 'transmission'
torrent_info['link'] = linkit
return torrent_info
else:
return "fail"
except Exception as e:
@ -1035,18 +1048,42 @@ def torsend2client(seriesname, issue, seriesyear, linkit, site):
dc = deluge.TorrentClient()
if not dc.connect(mylar.DELUGE_HOST, mylar.DELUGE_USERNAME, mylar.DELUGE_PASSWORD):
return "fail"
logger.info('Not connected to Deluge! (rsscheck)')
logger.info('Not connected to Deluge!')
else:
logger.info('Connected to Deluge! Will try to add torrent now! (rsscheck)')
if dc.load_torrent(filepath):
return "pass"
logger.info('Connected to Deluge! Will try to add torrent now!')
torrent_info = dc.load_torrent(filepath)
if torrent_info:
torrent_info['clientmode'] = 'deluge'
torrent_info['link'] = linkit
return torrent_info
else:
return "fail"
logger.info('Unable to connect to Deluge (rsscheck)')
logger.info('Unable to connect to Deluge!')
except Exception as e:
logger.error(e)
return "fail"
elif mylar.USE_QBITTORRENT:
try:
qc = qbittorrent.TorrentClient()
if not qc.connect(mylar.QBITTORRENT_HOST, mylar.QBITTORRENT_USERNAME, mylar.QBITTORRENT_PASSWORD):
logger.info('Not connected to qBittorrent - Make sure the Web UI is enabled and the port is correct!')
return "fail"
else:
logger.info('Connected to qBittorrent! Will try to add torrent now!')
torrent_info = qc.load_torrent(filepath)
if torrent_info:
torrent_info['clientmode'] = 'qbittorrent'
torrent_info['link'] = linkit
return torrent_info
else:
logger.info('Unable to add torrent to qBittorrent')
return "fail"
except Exception as e:
logger.error(e)
return "fail"
elif mylar.USE_WATCHDIR:
if mylar.TORRENT_LOCAL:

View File

@ -147,13 +147,14 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
#nzbpr = providercount - 1
#if nzbpr < 0:
# nzbpr == 0
findit = 'no'
findit = {}
findit['status'] = False
totalproviders = providercount + torp
if totalproviders == 0:
logger.error('[WARNING] You have ' + str(totalproviders) + ' search providers enabled. I need at least ONE provider to work. Aborting search.')
findit = "no"
findit['status'] = False
nzbprov = None
return findit, nzbprov
@ -193,7 +194,7 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
if i == 1: searchmode = 'rss' #order of ops - this will be used first.
elif i == 2: searchmode = 'api'
if findit == 'yes':
if findit['status'] is True:
logger.fdebug('Found result on first run, exiting search module now.')
break
@ -236,10 +237,7 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
continue
if searchmode == 'rss':
findit = NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDate, StoreDate, searchprov, send_prov_count, IssDateFix, IssueID, UseFuzzy, newznab_host, ComicVersion=ComicVersion, SARC=SARC, IssueArcID=IssueArcID, RSS="yes", ComicID=ComicID, issuetitle=issuetitle, unaltered_ComicName=unaltered_ComicName)
if findit == 'yes':
logger.fdebug("findit = found!")
break
else:
if findit['status'] is False:
if AlternateSearch is not None and AlternateSearch != "None":
chkthealt = AlternateSearch.split('##')
if chkthealt == 0:
@ -249,16 +247,17 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
AS_Alternate = re.sub('##', '', calt)
logger.info(u"Alternate Search pattern detected...re-adjusting to : " + str(AS_Alternate))
findit = NZB_SEARCH(AS_Alternate, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDate, StoreDate, searchprov, send_prov_count, IssDateFix, IssueID, UseFuzzy, newznab_host, ComicVersion=ComicVersion, SARC=SARC, IssueArcID=IssueArcID, RSS="yes", ComicID=ComicID, issuetitle=issuetitle, unaltered_ComicName=AS_Alternate, allow_packs=allow_packs)
if findit == 'yes':
if findit['status'] is True:
break
if findit == 'yes': break
if findit['status'] is True:
break
else:
logger.fdebug("findit = found!")
break
else:
findit = NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDate, StoreDate, searchprov, send_prov_count, IssDateFix, IssueID, UseFuzzy, newznab_host, ComicVersion=ComicVersion, SARC=SARC, IssueArcID=IssueArcID, RSS="no", ComicID=ComicID, issuetitle=issuetitle, unaltered_ComicName=unaltered_ComicName, allow_packs=allow_packs)
if findit == 'yes':
logger.fdebug("findit = found!")
break
else:
if findit['status'] is False:
if AlternateSearch is not None and AlternateSearch != "None":
chkthealt = AlternateSearch.split('##')
if chkthealt == 0:
@ -268,9 +267,13 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
AS_Alternate = re.sub('##', '', calt)
logger.info(u"Alternate Search pattern detected...re-adjusting to : " + str(AS_Alternate))
findit = NZB_SEARCH(AS_Alternate, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDate, StoreDate, searchprov, send_prov_count, IssDateFix, IssueID, UseFuzzy, newznab_host, ComicVersion=ComicVersion, SARC=SARC, IssueArcID=IssueArcID, RSS="no", ComicID=ComicID, issuetitle=issuetitle, unaltered_ComicName=unaltered_ComicName, allow_packs=allow_packs)
if findit == 'yes':
if findit['status'] is True:
break
if findit == 'yes': break
if findit['status'] is True:
break
else:
logger.fdebug("findit = found!")
break
if searchprov == 'newznab':
searchprov = newznab_host[0].rstrip()
@ -278,7 +281,7 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
prov_count+=1
#torprtmp+=1 #torprtmp-=1
if findit == 'yes':
if findit['status'] is True:
#check for snatched_havetotal being enabled here and adjust counts now.
#IssueID being the catch/check for one-offs as they won't exist on the watchlist and error out otherwise.
if mylar.SNATCHED_HAVETOTAL and IssueID is not None:
@ -305,8 +308,10 @@ def search_init(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueD
def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDate, StoreDate, nzbprov, prov_count, IssDateFix, IssueID, UseFuzzy, newznab_host=None, ComicVersion=None, SARC=None, IssueArcID=None, RSS=None, ComicID=None, issuetitle=None, unaltered_ComicName=None, allow_packs=None):
if any([allow_packs is None, allow_packs == 'None', allow_packs == 0]) and all([mylar.ENABLE_TORRENT_SEARCH, mylar.ENABLE_32P]):
if any([allow_packs is None, allow_packs == 'None', allow_packs == 0, allow_packs == '0']) and all([mylar.ENABLE_TORRENT_SEARCH, mylar.ENABLE_32P]):
allow_packs = False
elif any([allow_packs == 1, allow_packs == '1']) and all([mylar.ENABLE_TORRENT_SEARCH, mylar.ENABLE_32P]):
allow_packs = True
newznab_local = False
@ -471,6 +476,8 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
#print ("------RESULTS OF SEARCH-------------------")
findloop = 0
foundcomic = []
foundc = {}
foundc['status'] = False
done = False
seperatealpha = "no"
#---issue problem
@ -481,7 +488,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
#logger.fdebug('findloop: ' + str(findloop) + ' / findcount: ' + str(findcount))
comsrc = comsearch
if nzbprov == 'dognzb' and not mylar.DOGNZB:
foundc = "no"
foundc['status'] = False
done = True
break
while (cmloopit >= 1):
@ -643,16 +650,18 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
r = requests.get(findurl, params=payload, verify=verify, headers=headers)
except requests.exceptions.Timeout as e:
logger.warn('Timeout occured fetching data from %s: %s' % (nzbprov, e))
foundc['status'] = False
break
except requests.exceptions.ConnectionError as e:
logger.warn('Connection error trying to retrieve data from %s: %s' % (nzbprov, e))
foundc['status'] = False
break
except requests.exceptions.RequestException as e:
logger.warn('General Error fetching data from %s: %s' % (nzbprov, e))
if e.r.status_code == 503:
#HTTP Error 503
logger.warn('Aborting search due to Provider unavailability')
foundc = "no"
foundc['status'] = False
break
try:
@ -675,11 +684,11 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
if bb['feed']['error']['code'] == '910':
logger.warn('DAILY API limit reached. Disabling provider usage until 12:01am')
mylar.DOGNZB = 0
foundc = False
foundc['status'] = False
done = True
else:
logger.warn('API Error. Check the error message and take action if required.')
foundc = False
foundc['status'] = False
done = True
break
except:
@ -692,12 +701,8 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
#cmloopit == 1
done = False
foundc = "no"
log2file = ""
if bb == "no results":
pass
foundc = "no"
else:
if not bb == "no results":
for entry in bb['entries']:
#logger.info(entry) #<--- uncomment this to see what the search result(s) are
#brief match here against 32p since it returns the direct issue number
@ -1231,9 +1236,9 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
else:
nzbprov = 'DEM'
if nzbprov == '32P' and allow_packs and RSS == 'no':
if all([nzbprov == '32P', allow_packs == True, RSS == 'no']):
logger.fdebug('pack:' + entry['pack'])
if all([nzbprov == '32P', RSS == 'no', allow_packs]) and any([entry['pack'] == '1', entry['pack'] == '2']):
if all([nzbprov == '32P', RSS == 'no', allow_packs == True]) and any([entry['pack'] == '1', entry['pack'] == '2']):
if nzbprov == '32P':
if entry['pack'] == '2':
logger.fdebug('[PACK-QUEUE] Diamond FreeLeech Pack detected.')
@ -1255,7 +1260,9 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
#pack support.
comicinfo = []
comicinfo.append({"ComicName": ComicName,
"ComicVolume": ComicVersion,
"IssueNumber": IssueNumber,
"IssueDate": IssueDate,
"comyear": comyear,
"pack": True,
"pack_numbers": pack_issuelist,
@ -1272,6 +1279,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
hyphensplit = None
hyphenfail = False
issue_firstword = None
#issue_pack = None
if unaltered_ComicName is not None:
ComicName = unaltered_ComicName
for m in re.finditer('[-/:]', comic_andiss):
@ -1285,6 +1293,29 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
logger.fdebug('Assuming position start is : ' + str(m.start()))
hyphensplit = comic_andiss[m.start():].split()
try:
#test for packs here as they will be like #1-20, #1-7.3, 1-20+Annuals
#thisentry = Fear Itself vol0 #1-7.3
#if '#' in thisentry:
# issue_pack_startpos = thisentry.find('#') + 1 #(take first digit after dash)
# issue_pack_dash = hyphensplit[1] #this should be the end of the pack sequence
# issue_pack_endpos = thisentry.find('-', issue_pack_startpos)
# issue_pack_start = thisentry[issue_pack_startpos:issue_pack_endpos]
# if thisentry.find(' ', issue_pack_endpos) == -1:
# endit = len(thisentry)
# else:
# endit = thisentry.find(' ', issue_pack_endpos)
# issue_pack_end = thisentry[issue_pack_endpos+1:endit].strip()
# if issue_pack_start.isdigit():
# logger.fdebug('first position prior to hyphen is digit [' + str(issue_pack_start) + ']')
# try:
# float(issue_pack_end)
# except:
# pass
# else:
# issue_pack = str(issue_pack_start) + '-' + str(issue_pack_end)
# logger.info('This should be a pack: ' + issue_pack)
#if issue_pack is None:
issue_firstword = hyphensplit[1]
logger.fdebug('First word of issue stored as : ' + str(issue_firstword))
except:
@ -1380,6 +1411,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
else:
comic_iss = tmpiss
splitst = len(splitit) - 1
logger.fdebug("adjusting from: " + str(comic_iss_b4) + " to: " + str(comic_iss))
# make sure that things like - in watchcomic are accounted for when comparing to nzb.
@ -1545,17 +1577,19 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
else:
cyear = comyear
comicinfo.append({"ComicName": ComicName,
"IssueNumber": IssueNumber,
"IssueDate": IssueDate,
"comyear": cyear,
"pack": False,
"pack_numbers": None,
"modcomicname": modcomicname})
comicinfo.append({"ComicName": ComicName,
"ComicVolume": ComicVersion,
"IssueNumber": IssueNumber,
"IssueDate": IssueDate,
"comyear": cyear,
"pack": False,
"pack_numbers": None,
"pack_issuelist": None,
"modcomicname": modcomicname})
else:
log2file = log2file + "issues don't match.." + "\n"
downloadit = False
foundc = "no"
foundc['status'] = False
if downloadit:
try:
@ -1576,14 +1610,16 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
if searchresult == 'downloadchk-fail':
continue
elif searchresult == 'torrent-fail' or searchresult == 'nzbget-fail' or searchresult == 'sab-fail' or searchresult == 'blackhole-fail':
return
else:
#nzbid, nzbname, sent_to
nzbid = searchresult[0]['nzbid']
nzbname = searchresult[0]['nzbname']
sent_to = searchresult[0]['sent_to']
alt_nzbname = searchresult[0]['alt_nzbname']
foundc = "yes"
return foundc
#nzbid, nzbname, sent_to
nzbid = searchresult['nzbid']
nzbname = searchresult['nzbname']
sent_to = searchresult['sent_to']
alt_nzbname = searchresult['alt_nzbname']
t_hash = searchresult['t_hash']
foundc['info'] = searchresult
foundc['status'] = True
done = True
break
@ -1591,13 +1627,13 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
cmloopit == 1 #let's make sure it STOPS searching after a sucessful match.
break
cmloopit-=1
if cmloopit < 1 and c_alpha is not None and seperatealpha == "no" and foundc == "no":
if cmloopit < 1 and c_alpha is not None and seperatealpha == "no" and foundc['status'] is False:
logger.info("Alphanumerics detected within IssueNumber. Seperating from Issue # and re-trying.")
cmloopit = origcmloopit
seperatealpha = "yes"
findloop+=1
if foundc == "yes":
if foundc['status'] is True:
if 'TPSE' in tmpprov and any([nzbprov == 'WWT', nzbprov == 'DEM']):
tmpprov = re.sub('TPSE', nzbprov, tmpprov)
foundcomic.append("yes")
@ -1629,7 +1665,7 @@ def NZB_SEARCH(ComicName, IssueNumber, ComicYear, SeriesYear, Publisher, IssueDa
mylar.TMP_PROV = nzbprov
return foundc
if foundc == "no":# and prov_count == 0:
else:
#logger.fdebug('prov_count: ' + str(prov_count))
foundcomic.append("no")
if IssDateFix == "no":
@ -1724,14 +1760,11 @@ def searchforissue(issueid=None, new=False, rsscheck=None):
else:
AllowPacks = False
mode = result['mode']
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_TPSE or mylar.ENABLE_32P) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_TPSE or mylar.ENABLE_32P or mylar.ENABLE_TORZNAB) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
foundNZB, prov = search_init(comic['ComicName'], result['Issue_Number'], str(ComicYear), comic['ComicYear'], Publisher, IssueDate, StoreDate, result['IssueID'], AlternateSearch, UseFuzzy, ComicVersion, SARC=None, IssueArcID=None, mode=mode, rsscheck=rsscheck, ComicID=result['ComicID'], filesafe=comic['ComicName_Filesafe'], allow_packs=AllowPacks)
if foundNZB == "yes":
#print ("found!")
updater.foundsearch(result['ComicID'], result['IssueID'], mode=mode, provider=prov)
else:
pass
#print ("not found!")
if foundNZB['status'] is True:
logger.info(foundNZB)
updater.foundsearch(result['ComicID'], result['IssueID'], mode=mode, provider=prov, hash=foundNZB['info']['t_hash'])
if rsscheck:
logger.info('Completed RSS Search scan')
@ -1768,14 +1801,11 @@ def searchforissue(issueid=None, new=False, rsscheck=None):
AllowPacks = False
foundNZB = "none"
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_TPSE or mylar.ENABLE_32P) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_TPSE or mylar.ENABLE_32P or mylar.ENABLE_TORZNAB) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
foundNZB, prov = search_init(comic['ComicName'], result['Issue_Number'], str(IssueYear), comic['ComicYear'], Publisher, IssueDate, StoreDate, result['IssueID'], AlternateSearch, UseFuzzy, ComicVersion, SARC=None, IssueArcID=None, mode=mode, rsscheck=rsscheck, ComicID=result['ComicID'], filesafe=comic['ComicName_Filesafe'], allow_packs=AllowPacks)
if foundNZB == "yes":
if foundNZB['status'] is True:
logger.fdebug("I found " + comic['ComicName'] + ' #:' + str(result['Issue_Number']))
updater.foundsearch(ComicID=result['ComicID'], IssueID=result['IssueID'], mode=mode, provider=prov)
else:
pass
#print ("not found!")
updater.foundsearch(ComicID=result['ComicID'], IssueID=result['IssueID'], mode=mode, provider=prov, hash=foundNZB['info']['t_hash'])
return
def searchIssueIDList(issuelist):
@ -1810,14 +1840,10 @@ def searchIssueIDList(issuelist):
else:
AllowPacks = False
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_32P or mylar.ENABLE_TPSE) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
if (mylar.NZBSU or mylar.DOGNZB or mylar.EXPERIMENTAL or mylar.NEWZNAB or mylar.ENABLE_32P or mylar.ENABLE_TPSE or mylar.ENABLE_TORZNAB) and (mylar.USE_SABNZBD or mylar.USE_NZBGET or mylar.ENABLE_TORRENTS or mylar.USE_BLACKHOLE):
foundNZB, prov = search_init(comic['ComicName'], issue['Issue_Number'], str(IssueYear), comic['ComicYear'], Publisher, issue['IssueDate'], issue['ReleaseDate'], issue['IssueID'], AlternateSearch, UseFuzzy, ComicVersion, SARC=None, IssueArcID=None, mode=mode, ComicID=issue['ComicID'], filesafe=comic['ComicName_Filesafe'], allow_packs=AllowPacks)
if foundNZB == "yes":
#print ("found!")
updater.foundsearch(ComicID=issue['ComicID'], IssueID=issue['IssueID'], mode=mode, provider=prov)
else:
pass
#print ("not found!")
if foundNZB['status'] is True:
updater.foundsearch(ComicID=issue['ComicID'], IssueID=issue['IssueID'], mode=mode, provider=prov, hash=foundNZB['info']['t_hash'])
@ -2163,6 +2189,7 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
#blackhole
sent_to = None
t_hash = None
if mylar.USE_BLACKHOLE and all([nzbprov != '32P', nzbprov != 'TPSE', nzbprov != 'WWT', nzbprov != 'DEM', nzbprov != 'Torznab']):
logger.fdebug("using blackhole directory at : " + str(mylar.BLACKHOLE_DIR))
if os.path.exists(mylar.BLACKHOLE_DIR):
@ -2175,6 +2202,37 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
logger.fdebug("filename saved to your blackhole as : " + nzbname)
logger.info(u"Successfully sent .nzb to your Blackhole directory : " + os.path.join(mylar.BLACKHOLE_DIR, nzbname))
sent_to = "your Blackhole Directory"
if mylar.ENABLE_SNATCH_SCRIPT:
if comicinfo[0]['pack'] is False:
pnumbers = None
plist = None
else:
pnumbers = '|'.join(comicinfo[0]['pack_numbers'])
plist= '|'.join(comicinfo[0]['pack_issuelist'])
snatch_vars = {'nzbinfo': {'link': link,
'id': nzbid,
'nzbname': nzbname,
'nzbpath': nzbpath,
'blackhole': mylar.BLACKHOLE_DIR},
'comicinfo': {'comicname': ComicName,
'volume': comicinfo[0]['ComicVolume'],
'comicid': ComicID,
'issueid': IssueID,
'issuenumber': IssueNumber,
'issuedate': comicinfo[0]['IssueDate'],
'seriesyear': comyear},
'pack': comicinfo[0]['pack'],
'pack_numbers': pnumbers,
'pack_issuelist': plist,
'provider': nzbprov,
'method': 'nzb',
'clientmode': 'blackhole'}
snatchitup = helpers.script_env('on-snatch',snatch_vars)
if snatchitup is True:
logger.info('Successfully submitted on-grab script as requested.')
else:
logger.info('Could not Successfully submit on-grab script as requested. Please check logs...')
#end blackhole
#torrents (32P & TPSE & DEM)
@ -2182,7 +2240,6 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
logger.fdebug("ComicName:" + ComicName)
logger.fdebug("link:" + link)
logger.fdebug("Torrent Provider:" + nzbprov)
foundc = "yes"
rcheck = rsscheck.torsend2client(ComicName, IssueNumber, comyear, link, nzbprov)
if rcheck == "fail":
@ -2202,6 +2259,43 @@ 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"
else:
#start the auto-snatch segway here (if rcheck isn't False, it contains the info of the torrent)
#since this is torrentspecific snatch, the vars will be different than nzb snatches.
#torrent_info{'folder','name',['total_filesize','label','hash','files','time_started'}
t_hash = rcheck['hash']
if any([mylar.USE_RTORRENT, mylar.USE_DELUGE]) and mylar.AUTO_SNATCH:
mylar.SNATCHED_QUEUE.put(rcheck['hash'])
else:
if mylar.ENABLE_SNATCH_SCRIPT:
if comicinfo[0]['pack'] is False:
pnumbers = None
plist = None
else:
pnumbers = '|'.join(comicinfo[0]['pack_numbers'])
plist= '|'.join(comicinfo[0]['pack_issuelist'])
snatch_vars = {'comicinfo': {'comicname': ComicName,
'volume': comicinfo[0]['ComicVolume'],
'issuenumber': IssueNumber,
'issuedate': comicinfo[0]['IssueDate'],
'seriesyear': comyear,
'comicid': ComicID,
'issueid': IssueID},
'pack': comicinfo[0]['pack'],
'pack_numbers': pnumbers,
'pack_issuelist': plist,
'provider': nzbprov,
'method': 'torrent',
'clientmode': rcheck['clientmode'],
'torrentinfo': rcheck}
snatchitup = helpers.script_env('on-snatch',snatch_vars)
if snatchitup is True:
logger.info('Successfully submitted on-grab script as requested.')
else:
logger.info('Could not Successfully submit on-grab script as requested. Please check logs...')
if mylar.USE_WATCHDIR:
if mylar.TORRENT_LOCAL:
sent_to = "your local Watch folder"
@ -2214,7 +2308,9 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
elif mylar.USE_TRANSMISSION:
sent_to = "your Transmission client"
elif mylar.USE_DELUGE:
sent_to = "your Deluge client"
sent_to = "your Deluge client"
elif mylar.USE_QBITTORRENT:
sent_to = "your qBittorrent client"
#end torrents
else:
@ -2382,15 +2478,51 @@ def searcher(nzbprov, nzbname, comicinfo, link, IssueID, ComicID, tmpprov, direc
sent_to = "SABnzbd+"
logger.info(u"Successfully sent nzb file to SABnzbd")
if mylar.ENABLE_SNATCH_SCRIPT:
if mylar.USE_NZBGET:
clientmode = 'nzbget'
elif mylar.USE_SABNZBD:
clientmode = 'sabnzbd'
if comicinfo[0]['pack'] is False:
pnumbers = None
plist = None
else:
pnumbers = '|'.join(comicinfo[0]['pack_numbers'])
plist= '|'.join(comicinfo[0]['pack_issuelist'])
snatch_vars = {'nzbinfo': {'link': link,
'id': nzbid,
'nzbname': nzbname,
'nzbpath': nzbpath},
'comicinfo': {'comicname': comicinfo[0]['ComicName'],
'volume': comicinfo[0]['ComicVolume'],
'comicid': ComicID,
'issueid': IssueID,
'issuenumber': IssueNumber,
'issuedate': comicinfo[0]['IssueDate'],
'seriesyear': comyear},
'pack': comicinfo[0]['pack'],
'pack_numbers': pnumbers,
'pack_issuelist': plist,
'provider': nzbprov,
'method': 'nzb',
'clientmode': clientmode}
snatchitup = helpers.script_env('on-snatch',snatch_vars)
if snatchitup is True:
logger.info('Successfully submitted on-grab script as requested.')
else:
logger.info('Could not Successfully submit on-grab script as requested. Please check logs...')
#nzbid, nzbname, sent_to
nzbname = re.sub('.nzb', '', nzbname).strip()
return_val = []
return_val.append({"nzbid": nzbid,
"nzbname": nzbname,
"sent_to": sent_to,
"alt_nzbname": alt_nzbname})
return_val = {}
return_val = {"nzbid": nzbid,
"nzbname": nzbname,
"sent_to": sent_to,
"alt_nzbname": alt_nzbname,
"t_hash": t_hash}
#if it's a directsend link (ie. via a retry).
if directsend is None:

View File

@ -44,14 +44,15 @@ class TorrentClient(object):
return False
def get_torrent(self, hash):
logger.debug('Getting Torrent info hash: ' + hash)
logger.debug('Getting Torrent info from hash: ' + hash)
try:
torrent_info = self.client.call('core.get_torrent_status', hash, '')
except Exception as e:
logger.error('Could not get torrent info for ' + hash)
return False
else:
logger.info('Getting Torrent Info!')
if torrent_info is None:
torrent_info = False
return torrent_info
@ -80,7 +81,7 @@ class TorrentClient(object):
self.client.call('core.pause_torrent', hash)
except Exception as e:
logger.error('Torrent failed to be stopped: ' + e)
return false
return False
else:
logger.info('Torrent ' + hash + ' was stopped')
return True
@ -104,6 +105,8 @@ class TorrentClient(object):
#Check if torrent already added
if self.find_torrent(str.lower(hash)):
logger.info('load_torrent: Torrent already exists!')
#should set something here to denote that it's already loaded, and then the failed download checker not run so it doesn't download
#multiple copies of the same issues that's already downloaded
else:
logger.info('Torrent not added yet, trying to add it now!')
try:
@ -111,8 +114,6 @@ class TorrentClient(object):
except Exception as e:
logger.debug('Torrent not added')
return False
else:
logger.debug('TorrentID: ' + torrent_id)
# If label enabled put label on torrent in Deluge
if torrent_id and mylar.DELUGE_LABEL:
@ -126,17 +127,25 @@ class TorrentClient(object):
self.client.call('label.set_torrent', torrent_id, mylar.DELUGE_LABEL)
except:
logger.warn('Unable to set label - Either try to create it manually within Deluge, and/or ensure there are no spaces, capitalization or special characters in label')
return False
logger.info('Succesfully set label to ' + mylar.DELUGE_LABEL)
else:
logger.info('Succesfully set label to ' + mylar.DELUGE_LABEL)
try:
self.find_torrent(torrent_id)
logger.info('Double checking torrent was added.')
torrent_info = self.get_torrent(torrent_id)
logger.info('Double checking that the torrent was added.')
except Exception as e:
logger.warn('Torrent was not added! Please check logs')
return False
else:
logger.info('Torrent successfully added!')
return True
return {'hash': torrent_info['hash'],
'label': torrent_info['label'],
'folder': torrent_info['save_path'],
'total_filesize': torrent_info['total_size'],
'name': torrent_info['name'],
'files': torrent_info['files'],
'time_started': torrent_info['active_time'],
'completed': torrent_info['is_finished']}
def delete_torrent(self, hash, removeData=False):

View File

@ -0,0 +1,130 @@
import os
import mylar
import base64
import time
from mylar import logger, helpers
from lib.qbittorrent import client
class TorrentClient(object):
def __init__(self):
self.conn = None
def connect(self, host, username, password):
if self.conn is not None:
return self.connect
if not host:
return False
try:
logger.info(host)
self.client = client.Client(host)
except Exception as e:
logger.error('Could not create qBittorrent Object' + str(e))
return False
else:
try:
self.client.login(username, password)
except Exception as e:
logger.error('Could not connect to qBittorrent ' + host)
else:
return self.client
def find_torrent(self, hash):
logger.debug('Finding Torrent hash: ' + hash)
torrent_info = self.get_torrent(hash)
if torrent_info:
return True
else:
return False
def get_torrent(self, hash):
logger.debug('Getting Torrent info hash: ' + hash)
try:
torrent_info = self.client.get_torrent(hash)
except Exception as e:
logger.error('Could not get torrent info for ' + hash)
return False
else:
logger.info('Successfully located information for torrent')
return torrent_info
def load_torrent(self, filepath):
logger.info('filepath to torrent file set to : ' + filepath)
if self.client._is_authenticated is True:
logger.info('Checking if Torrent Exists!')
hash = self.get_the_hash(filepath)
logger.debug('Torrent Hash (load_torrent): "' + hash + '"')
logger.debug('FileName (load_torrent): ' + str(os.path.basename(filepath)))
#Check if torrent already added
if self.find_torrent(hash):
logger.info('load_torrent: Torrent already exists!')
return False
#should set something here to denote that it's already loaded, and then the failed download checker not run so it doesn't download
#multiple copies of the same issues that's already downloaded
else:
logger.info('Torrent not added yet, trying to add it now!')
try:
torrent_content = open(filepath, 'rb')
tid = self.client.download_from_file(torrent_content, label=mylar.QBITTORRENT_LABEL)
except Exception as e:
logger.debug('Torrent not added')
return False
else:
logger.debug('Successfully submitted for add. Verifying item is now on client.')
if mylar.QBITTORRENT_STARTONLOAD:
logger.info('attempting to start')
startit = self.client.force_start(hash)
logger.info('startit returned:' + str(startit))
else:
logger.info('attempting to pause torrent incase it starts')
try:
startit = self.client.pause(hash)
logger.info('startit paused:' + str(startit))
except:
logger.warn('Unable to pause torrent - possibly already paused?')
try:
time.sleep(5) # wait 5 in case it's not populated yet.
tinfo = self.get_torrent(hash)
except Exception as e:
logger.warn('Torrent was not added! Please check logs')
return False
else:
torrent_info = []
logger.info('Torrent successfully added!')
torrent_info['hash'] = hash
filelist = self.client.get_torrent_files(hash)
if len(filelist) == 1:
torrent_info['name'] = filelist['name']
else:
torrent_info['name'] = tinfo['save_path']
torrent_info['total_filesize'] = tinfo['total_size']
torrent_info['folder'] = tinfo['save_path']
torrent_info['files'] = filelist
torrent_info['time_started'] = tinfo['addition_date']
torrent_info['label'] = mylar.QBITTORRENT_LABEL
return torrent_info
def get_the_hash(self, filepath):
import hashlib, StringIO
import bencode
# Open torrent file
torrent_file = open(filepath, "rb")
metainfo = bencode.decode(torrent_file.read())
info = metainfo['info']
thehash = hashlib.sha1(bencode.encode(info)).hexdigest().upper()
logger.debug('Hash: ' + thehash)
return thehash

View File

@ -55,6 +55,7 @@ class TorrentClient(object):
'name': torrent.name,
'folder': torrent.downloadDir,
'completed': torrent.progress == 100,
'label': 'None', ## labels not supported in transmission - for when it's in transmission
'files': torrent_files,
'upload_total': torrent.uploadedEver,
'download_total': torrent.downloadedEver,

View File

@ -1218,19 +1218,44 @@ class WebInterface(object):
logger.error("Unable to send torrent - check logs and settings.")
continue
else:
logger.info('Successfully retried issue.')
break
if mylar.ENABLE_SNATCH_SCRIPT:
#packs not supported on retry atm - Volume and Issuedate also not included due to limitations...
snatch_vars = {'comicinfo': {'comicname': ComicName,
'issuenumber': IssueNumber,
'seriesyear': ComicYear,
'comicid': ComicID,
'issueid': IssueID},
'pack': False,
'pack_numbers': None,
'pack_issuelist': None,
'provider': fullprov,
'method': 'torrent',
'clientmode': rcheck['clientmode'],
'torrentinfo': rcheck}
snatchitup = helpers.script_env('on-snatch',snatch_vars)
if snatchitup is True:
logger.info('Successfully submitted on-grab script as requested.')
else:
logger.info('Could not Successfully submit on-grab script as requested. Please check logs...')
logger.info('Successfully retried issue.')
break
else:
annualize = myDB.selectone('SELECT * FROM annuals WHERE IssueID=?', [IssueID]).fetchone()
if annualize is None:
modcomicname = ComicName
ckthis = myDB.selectone('SELECT a.ComicID, a.ComicName, a.ComicVersion, a.ComicYear, b.IssueID, b.IssueNumber, b.IssueDate FROM comics as a INNER JOIN annuals as b ON a.ComicID = b.ComicID WHERE IssueID=?', [IssueID]).fetchone()
if ckthis is None:
ckthis = myDB.selectone('SELECT a.ComicID, a.ComicName, a.Volume, a.ComicYear, b.IssueID, b.IssueNumber, b.IssueDate FROM comics as a INNER JOIN issues as b ON a.ComicID = b.ComicID WHERE IssueID=?', [IssueID]).fetchone()
modcomicname = chkthis['ComicName']
else:
modcomicname = ComicName + ' Annual'
modcomicname = chkthis['ComicName'] + ' Annual'
comicinfo = []
comicinfo.append({"ComicName": ComicName,
"IssueNumber": IssueNumber,
"comyear": ComicYear,
comicinfo.append({"ComicName": chkthis['ComicName'],
"ComicVolume": chkthis['ComicVersion'],
"IssueNumber": chkthis['IssueNumber'],
"comyear": chkthis['ComicYear'],
"IssueDate": chkthis['IssueDate'],
"modcomicname": modcomicname})
newznabinfo = None
@ -1343,7 +1368,7 @@ class WebInterface(object):
newStatus = {"Status": "Wanted"}
myDB.upsert("readinglist", newStatus, controlValueDict)
foundcom, prov = search.search_init(ComicName=ComicName, IssueNumber=ComicIssue, ComicYear=ComicYear, SeriesYear=None, Publisher=Publisher, IssueDate=IssueDate, StoreDate=StoreDate, IssueID=None, AlternateSearch=None, UseFuzzy=None, ComicVersion=dateload['Volume'], SARC=SARC, IssueArcID=IssueArcID)
if foundcom == "yes":
if foundcom['status'] is True:
logger.info(u"Downloaded " + ComicName + " #" + ComicIssue + " (" + str(ComicYear) + ")")
controlValueDict = {"IssueArcID": IssueArcID}
newStatus = {"Status": "Snatched"}
@ -1363,7 +1388,7 @@ class WebInterface(object):
if Publisher == 'COMICS': Publisher = None
logger.info(u"Marking " + ComicName + " " + ComicIssue + " as wanted...")
foundcom, prov = search.search_init(ComicName=ComicName, IssueNumber=ComicIssue, ComicYear=ComicYear, SeriesYear=None, Publisher=Publisher, IssueDate=IssueDate, StoreDate=IssueDate, IssueID=None, AlternateSearch=None, UseFuzzy=None, ComicVersion=None, allow_packs=False)
if foundcom == "yes":
if foundcom['status'] is True:
logger.info(u"Downloaded " + ComicName + " " + ComicIssue)
raise cherrypy.HTTPRedirect("pullist")
#return
@ -1423,7 +1448,7 @@ class WebInterface(object):
#UseAFuzzy = miy['UseFuzzy']
#ComicVersion = miy['ComicVersion']
foundcom, prov = search.search_init(ComicName, ComicIssue, ComicYear, SeriesYear, Publisher, issues['IssueDate'], storedate, IssueID, AlternateSearch, UseAFuzzy, ComicVersion, mode=mode, ComicID=ComicID, manualsearch=manualsearch, filesafe=ComicName_Filesafe, allow_packs=AllowPacks)
if foundcom == "yes":
if foundcom['status'] is True:
# file check to see if issue exists and update 'have' count
if IssueID is not None:
logger.info("passing to updater.")
@ -2079,7 +2104,7 @@ class WebInterface(object):
annualize = 'yes'
else:
annualize = None
renameiss = helpers.rename_param(comicid, comicname, issue['Issue_Number'], filename, comicyear=None, issueid=None, annualize=annualize)
renameiss = helpers.rename_param(comicid, comicname, issue['Issue_Number'], filename, comicyear=None, issueid=issue['IssueID'], annualize=annualize)
nfilename = renameiss['nfilename']
srciss = os.path.join(comicdir, filename)
if filename != nfilename:
@ -3147,7 +3172,7 @@ class WebInterface(object):
logger.fdebug(issuechk['ComicName'] + " -- #" + str(issuechk['Issue_Number']))
foundcom, prov = search.search_init(ComicName=issuechk['ComicName'], IssueNumber=issuechk['Issue_Number'], ComicYear=issuechk['IssueYear'], SeriesYear=issuechk['SeriesYear'], Publisher=None, IssueDate=None, StoreDate=issuechk['ReleaseDate'], IssueID=issuechk['IssueID'], AlternateSearch=None, UseFuzzy=None, ComicVersion=None, SARC=SARC, IssueArcID=IssueArcID)
if foundcom == "yes":
if foundcom['status'] is True:
logger.fdebug('sucessfully found.')
#update the status - this is necessary for torrents as they are in 'snatched' status.
updater.foundsearch(s_comicid, s_issueid, mode=mode, provider=prov, SARC=SARC, IssueArcID=IssueArcID)
@ -3206,7 +3231,7 @@ class WebInterface(object):
logger.fdebug("-- watched series queue.")
logger.fdebug(issuechk['ComicName'] + " -- #" + str(issuechk['Issue_Number']))
foundcom, prov = search.search_init(ComicName=issuechk['ComicName'], IssueNumber=issuechk['Issue_Number'], ComicYear=issuechk['IssueYear'], SeriesYear=issuechk['SeriesYear'], Publisher=None, IssueDate=None, StoreDate=issuechk['ReleaseDate'], IssueID=issuechk['IssueID'], AlternateSearch=None, UseFuzzy=None, ComicVersion=None, SARC=SARC, IssueArcID=IssueArcID, mode=None, rsscheck=None, ComicID=None)
if foundcom == "yes":
if foundcom['status'] is True:
updater.foundsearch(s_comicid, s_issueid, mode=mode, provider=prov, SARC=SARC, IssueArcID=IssueArcID)
else:
logger.fdebug('Watchlist issue not sucessfully found')
@ -4103,6 +4128,7 @@ class WebInterface(object):
"torrent_downloader_rtorrent": helpers.radio(mylar.TORRENT_DOWNLOADER, 2),
"torrent_downloader_transmission": helpers.radio(mylar.TORRENT_DOWNLOADER, 3),
"torrent_downloader_deluge": helpers.radio(mylar.TORRENT_DOWNLOADER, 4),
"torrent_downloader_qbittorrent": helpers.radio(mylar.TORRENT_DOWNLOADER, 5),
"utorrent_host": mylar.UTORRENT_HOST,
"utorrent_username": mylar.UTORRENT_USERNAME,
"utorrent_password": mylar.UTORRENT_PASSWORD,
@ -4121,10 +4147,16 @@ class WebInterface(object):
"transmission_username": mylar.TRANSMISSION_USERNAME,
"transmission_password": mylar.TRANSMISSION_PASSWORD,
"transmission_directory": mylar.TRANSMISSION_DIRECTORY,
"deluge_host": mylar.DELUGE_HOST,
"deluge_host": mylar.DELUGE_HOST,
"deluge_username": mylar.DELUGE_USERNAME,
"deluge_password": mylar.DELUGE_PASSWORD,
"deluge_label": mylar.DELUGE_LABEL,
"qbittorrent_host": mylar.QBITTORRENT_HOST,
"qbittorrent_username": mylar.QBITTORRENT_USERNAME,
"qbittorrent_password": mylar.QBITTORRENT_PASSWORD,
"qbittorrent_label": mylar.QBITTORRENT_LABEL,
"qbittorrent_folder": mylar.QBITTORRENT_FOLDER,
"qbittorrent_startonload": mylar.QBITTORRENT_STARTONLOAD,
"blackhole_dir": mylar.BLACKHOLE_DIR,
"usenet_retention": mylar.USENET_RETENTION,
"use_nzbsu": helpers.checked(mylar.NZBSU),
@ -4230,6 +4262,10 @@ class WebInterface(object):
"telegram_userid": mylar.TELEGRAM_USERID,
"enable_extra_scripts": helpers.checked(mylar.ENABLE_EXTRA_SCRIPTS),
"extra_scripts": mylar.EXTRA_SCRIPTS,
"enable_snatch_script": helpers.checked(mylar.ENABLE_SNATCH_SCRIPT),
"snatch_script": mylar.SNATCH_SCRIPT,
"enable_pre_scripts": helpers.checked(mylar.ENABLE_PRE_SCRIPTS),
"pre_scripts": mylar.PRE_SCRIPTS,
"post_processing": helpers.checked(mylar.POST_PROCESSING),
"file_opts": mylar.FILE_OPTS,
"enable_meta": helpers.checked(mylar.ENABLE_META),
@ -4251,8 +4287,6 @@ class WebInterface(object):
"config_file": mylar.CONFIG_FILE,
"branch_history": 'None',
# "branch_history" : br_hist,
"enable_pre_scripts": helpers.checked(mylar.ENABLE_PRE_SCRIPTS),
"pre_scripts": mylar.PRE_SCRIPTS,
"log_dir": mylar.LOG_DIR
}
return serve_template(templatename="config.html", title="Settings", config=config, comicinfo=comicinfo)
@ -4469,7 +4503,8 @@ class WebInterface(object):
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, telegram_enabled=0, telegram_token=None, telegram_userid=None, telegram_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_ssl=0, rtorrent_verify=0, rtorrent_authentication='basic', rtorrent_rpc_url=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, transmission_directory=None,deluge_host=None, deluge_username=None, deluge_password=None, deluge_label=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, enforce_perms=0, chmod_dir=0777, chmod_file=0660, chowner=None, chgroup=None,
qbittorrent_host=None, qbittorrent_username=None, qbittorrent_password=None, qbittorrent_label=None, qbittorrent_folder=None, qbittorrent_startonload=0,
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_snatch_script=0, snatch_script=None, enable_pre_scripts=0, pre_scripts=None, post_processing=0, file_opts=None, syno_fix=0, search_delay=None, enforce_perms=0, 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
mylar.HTTP_HOST = http_host
@ -4564,6 +4599,12 @@ class WebInterface(object):
mylar.DELUGE_USERNAME = deluge_username
mylar.DELUGE_PASSWORD = deluge_password
mylar.DELUGE_LABEL = deluge_label
mylar.QBITTORRENT_HOST = qbittorrent_host
mylar.QBITTORRENT_USERNAME = qbittorrent_username
mylar.QBITTORRENT_PASSWORD = qbittorrent_password
mylar.QBITTORRENT_LABEL = qbittorrent_label
mylar.QBITTORRENT_FOLDER = qbittorrent_folder
mylar.QBITTORRENT_STARTONLOAD = int(qbittorrent_startonload)
mylar.ENABLE_TORRENT_SEARCH = int(enable_torrent_search)
mylar.ENABLE_TPSE = int(enable_tpse)
mylar.ENABLE_32P = int(enable_32p)
@ -4627,10 +4668,12 @@ class WebInterface(object):
mylar.DUPLICATE_DUMP = duplicate_dump
mylar.ENABLE_EXTRA_SCRIPTS = enable_extra_scripts
mylar.EXTRA_SCRIPTS = extra_scripts
mylar.ENABLE_SNATCH_SCRIPT = enable_snatch_script
mylar.SNATCH_SCRIPT = snatch_script
mylar.ENABLE_PRE_SCRIPTS = enable_pre_scripts
mylar.PRE_SCRIPTS = pre_scripts
mylar.POST_PROCESSING = post_processing
mylar.FILE_OPTS = file_opts
mylar.PRE_SCRIPTS = pre_scripts
mylar.ENABLE_META = enable_meta
mylar.CBR2CBZ_ONLY = cbr2cbz_only
mylar.CMTAGGER_PATH = cmtagger_path

View File

@ -0,0 +1,7 @@
[rtorrent]
HOST=hostname/ip
PORT=port#
USER=username
PASSWD=password
LOCALCD=local directory where torrents are to be saved to
KEYFILE=if you use a keyfile for ssh access, enter full path here to public key file (password above can be left blank then)

49
post-processing/getlftp.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
##-- start configuration
#this needs to be edited to the full path to the get.conf file containing the torrent client information
configfile=''
#this is the temporary location where it will make sure the conf is safe for use (by default this should be fine if left alone)
configfile_secured='/tmp/get.conf'
##-- end configuration
## --- don't change stuff below here ----
# check if the file contains something we don't want
if egrep -q -v '^#|^[^ ]*=[^;]*' "$configfile"; then
# echo "Config file is unclean, cleaning it..." >&2
# filter the original to a new file
egrep '^#|^[^ ]*=[^;&]*' "$configfile" > "$configfile_secured"
configfile="$configfile_secured"
fi
# now source it, either the original or the filtered variant
source "$configfile"
cd $LOCALCD
filename="$1"
if [[ "${filename##*.}" == "cbr" || "${filename##*.}" == "cbz" ]]; then
LCMD="pget -n 6 '$1'"
else
LCMD="mirror -P 2 --use-pget-n=6 '$1'"
fi
if [[ -z $KEYFILE ]]; then
PARAM="$USER $PASSWD"
else
PARAM="$USER $KEYFILE"
fi
lftp<<END_SCRIPT
open sftp://$HOST:$PORT
user $PARAM
$LCMD
bye
END_SCRIPT
echo "Successfully ran script."