SickGear/sickgear/notifiers/nmj.py

180 lines
7.4 KiB
Python
Raw Permalink Normal View History

# Author: Nico Berlee http://nico.berlee.nl/
#
# This file is part of SickGear.
#
# SickGear is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# SickGear is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
import re
try:
import telnetlib
except ImportError:
import lib.telnetlib313up as telnetlib
from .generic import BaseNotifier
import sickgear
from exceptions_helper import ex
from _23 import etree, urlencode
# noinspection PyUnresolvedReferences
from six.moves import urllib
class NMJNotifier(BaseNotifier):
def notify_settings(self, host):
"""
Retrieves the settings from a NMJ/Popcorn hour
host: The hostname/IP of the Popcorn Hour server
Returns: True if the settings were retrieved successfully, False otherwise
"""
# establish a terminal session to the PC
result, terminal = False, None
try:
terminal = telnetlib.Telnet(host)
except (BaseException, Exception):
self._log_warning(f'Unable to get a telnet session to {host}')
if result:
# tell the terminal to output the necessary info to the screen so we can search it later
self._log_debug(f'Connected to {host} via telnet')
terminal.read_until('sh-3.00# ')
terminal.write('cat /tmp/source\n')
terminal.write('cat /tmp/netshare\n')
terminal.write('exit\n')
tnoutput = terminal.read_all()
match = re.search(r'(.+\.db)\r\n?(.+)(?=sh-3.00# cat /tmp/netshare)', tnoutput)
# if we found the database in the terminal output then save that database to the config
if not match:
self._log_warning(f'Could not get current NMJ database on {host}, NMJ is probably not running!')
else:
database = match.group(1)
device = match.group(2)
self._log_debug(f'Found NMJ database {database} on device {device}')
sickgear.NMJ_DATABASE = database
# if the device is a remote host then try to parse the mounting URL and save it to the config
if device.startswith('NETWORK_SHARE/'):
match = re.search('.*(?=\r\n?%s)' % (re.escape(device[14:])), tnoutput)
if not match:
self._log_warning('Detected a network share on the Popcorn Hour, '
'but could not get the mounting url')
else:
mount = match.group().replace('127.0.0.1', host)
self._log_debug(f'Found mounting url on the Popcorn Hour in configuration: {mount}')
sickgear.NMJ_MOUNT = mount
result = True
if result:
return '{"message": "Got settings from %(host)s", "database": "%(database)s", "mount": "%(mount)s"}' % {
"host": host, "database": sickgear.NMJ_DATABASE, "mount": sickgear.NMJ_MOUNT}
return '{"message": "Failed! Make sure your Popcorn is on and NMJ is running. ' \
'(see Error Log -> Debug for detailed info)", "database": "", "mount": ""}'
def _send(self, host=None, database=None, mount=None):
"""
Sends a NMJ update command to the specified machine
host: The hostname/IP to send the request to (no port)
database: The database to send the request to
mount: The mount URL to use (optional)
Returns: True if the request succeeded, False otherwise
"""
host = self._choose(host, sickgear.NMJ_HOST)
database = self._choose(database, sickgear.NMJ_DATABASE)
mount = self._choose(mount, sickgear.NMJ_MOUNT)
self._log_debug('Sending scan command for NMJ')
# if a mount URL is provided then attempt to open a handle to that URL
if mount:
try:
req = urllib.request.Request(mount)
self._log_debug(f'Try to mount network drive via url: {mount}')
http_response_obj = urllib.request.urlopen(req) # PY2 http_response_obj has no `with` context manager
http_response_obj.close()
except IOError as e:
if hasattr(e, 'reason'):
self._log_warning(f'Could not contact Popcorn Hour on host {host}: {e.reason}')
elif hasattr(e, 'code'):
self._log_warning(f'Problem with Popcorn Hour on host {host}: {e.code}')
return False
except (BaseException, Exception) as e:
self._log_error(f'Unknown exception: {ex(e)}')
return False
# build up the request URL and parameters
params = dict(arg0='scanner_start', arg1=database, arg2='background', arg3='')
params = urlencode(params)
update_url = 'http://%(host)s:8008/metadata_database?%(params)s' % {'host': host, 'params': params}
# send the request to the server
try:
req = urllib.request.Request(update_url)
self._log_debug(f'Sending scan update command via url: {update_url}')
http_response_obj = urllib.request.urlopen(req)
response = http_response_obj.read()
http_response_obj.close()
except IOError as e:
if hasattr(e, 'reason'):
self._log_warning(f'Could not contact Popcorn Hour on host {host}: {e.reason}')
elif hasattr(e, 'code'):
self._log_warning(f'Problem with Popcorn Hour on host {host}: {e.code}')
return False
except (BaseException, Exception) as e:
self._log_error(f'Unknown exception: {ex(e)}')
return False
# try to parse the resulting XML
try:
et = etree.fromstring(response)
result = et.findtext('returnValue')
except SyntaxError as e:
self._log_error(f'Unable to parse XML returned from the Popcorn Hour: {ex(e)}')
return False
# if the result was a number, then consider that an error
if 0 < int(result):
self._log_error(f'Popcorn Hour returned an errorcode: {result}')
return False
self._log('NMJ started background scan')
return True
def _notify(self, host=None, database=None, mount=None, **kwargs):
result = self._send(host, database, mount)
return self._choose((('Success, started %s', 'Failed to start %s')[not result] % 'the scan update'), result)
def test_notify(self, host, database, mount):
self._testing = True
return self._notify(host, database, mount)
# notify_snatch() Not implemented: Start the scanner when snatched does not make sense
# notify_git_update() Not implemented, no reason to start scanner
def notify_download(self, *args, **kwargs):
self._notify()
def notify_subtitle_download(self, *args, **kwargs):
self._notify()
notifier = NMJNotifier