Update server connection code

This commit is contained in:
JonnyWong16 2017-12-24 14:01:16 -08:00
parent 29632b0805
commit 15faccfa2f
16 changed files with 530 additions and 535 deletions

View file

@ -653,7 +653,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label for="pms_token">PMS Token</label> <label for="pms_token">Plex.tv Account Token</label>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<div class="input-group"> <div class="input-group">

View file

@ -36,12 +36,14 @@ import activity_handler
import activity_pinger import activity_pinger
import config import config
import database import database
import libraries
import logger import logger
import mobile_app import mobile_app
import notification_handler import notification_handler
import notifiers import notifiers
import plextv import plextv
import pmsconnect import pmsconnect
import users
import versioncheck import versioncheck
import plexpy.config import plexpy.config
@ -213,16 +215,15 @@ def initialize(config_file):
# Get the real PMS urls for SSL and remote access # Get the real PMS urls for SSL and remote access
if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT: if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT:
plextv.get_real_pms_url() plextv.get_server_resources()
pmsconnect.get_server_friendly_name()
# Refresh the users list on startup # Refresh the users list on startup
if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP: if CONFIG.PMS_TOKEN and CONFIG.REFRESH_USERS_ON_STARTUP:
plextv.refresh_users() users.refresh_users()
# Refresh the libraries list on startup # Refresh the libraries list on startup
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN and CONFIG.REFRESH_LIBRARIES_ON_STARTUP: if CONFIG.PMS_IP and CONFIG.PMS_TOKEN and CONFIG.REFRESH_LIBRARIES_ON_STARTUP:
pmsconnect.refresh_libraries() libraries.refresh_libraries()
# Store the original umask # Store the original umask
UMASK = os.umask(0) UMASK = os.umask(0)
@ -323,14 +324,8 @@ def initialize_scheduler():
hours=backup_hours, minutes=0, seconds=0, args=(True, True)) hours=backup_hours, minutes=0, seconds=0, args=(True, True))
if WS_CONNECTED and CONFIG.PMS_IP and CONFIG.PMS_TOKEN: if WS_CONNECTED and CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
#schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions', schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
# hours=0, minutes=0, seconds=1)
#schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
# hours=0, minutes=0, seconds=monitor_seconds * bool(CONFIG.NOTIFY_RECENTLY_ADDED))
schedule_job(plextv.get_real_pms_url, 'Refresh Plex server URLs',
hours=12 * (not bool(CONFIG.PMS_URL_MANUAL)), minutes=0, seconds=0) hours=12 * (not bool(CONFIG.PMS_URL_MANUAL)), minutes=0, seconds=0)
schedule_job(pmsconnect.get_server_friendly_name, 'Refresh Plex server name',
hours=12, minutes=0, seconds=0)
schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access', schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access',
hours=0, minutes=0, seconds=60 * bool(CONFIG.MONITOR_REMOTE_ACCESS)) hours=0, minutes=0, seconds=60 * bool(CONFIG.MONITOR_REMOTE_ACCESS))
@ -341,9 +336,9 @@ def initialize_scheduler():
user_hours = CONFIG.REFRESH_USERS_INTERVAL if 1 <= CONFIG.REFRESH_USERS_INTERVAL <= 24 else 12 user_hours = CONFIG.REFRESH_USERS_INTERVAL if 1 <= CONFIG.REFRESH_USERS_INTERVAL <= 24 else 12
library_hours = CONFIG.REFRESH_LIBRARIES_INTERVAL if 1 <= CONFIG.REFRESH_LIBRARIES_INTERVAL <= 24 else 12 library_hours = CONFIG.REFRESH_LIBRARIES_INTERVAL if 1 <= CONFIG.REFRESH_LIBRARIES_INTERVAL <= 24 else 12
schedule_job(plextv.refresh_users, 'Refresh users list', schedule_job(users.refresh_users, 'Refresh users list',
hours=user_hours, minutes=0, seconds=0) hours=user_hours, minutes=0, seconds=0)
schedule_job(pmsconnect.refresh_libraries, 'Refresh libraries list', schedule_job(libraries.refresh_libraries, 'Refresh libraries list',
hours=library_hours, minutes=0, seconds=0) hours=library_hours, minutes=0, seconds=0)
schedule_job(activity_pinger.check_server_response, 'Check server response', schedule_job(activity_pinger.check_server_response, 'Check server response',
@ -351,9 +346,7 @@ def initialize_scheduler():
else: else:
# Cancel all jobs # Cancel all jobs
schedule_job(plextv.get_real_pms_url, 'Refresh Plex server URLs', schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
hours=0, minutes=0, seconds=0)
schedule_job(pmsconnect.get_server_friendly_name, 'Refresh Plex server name',
hours=0, minutes=0, seconds=0) hours=0, minutes=0, seconds=0)
schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access', schedule_job(activity_pinger.check_server_access, 'Check for Plex remote access',
@ -361,9 +354,9 @@ def initialize_scheduler():
schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates', schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates',
hours=0, minutes=0, seconds=0) hours=0, minutes=0, seconds=0)
schedule_job(plextv.refresh_users, 'Refresh users list', schedule_job(users.refresh_users, 'Refresh users list',
hours=0, minutes=0, seconds=0) hours=0, minutes=0, seconds=0)
schedule_job(pmsconnect.refresh_libraries, 'Refresh libraries list', schedule_job(libraries.refresh_libraries, 'Refresh libraries list',
hours=0, minutes=0, seconds=0) hours=0, minutes=0, seconds=0)
# Schedule job to reconnect websocket # Schedule job to reconnect websocket

View file

@ -278,7 +278,6 @@ def check_server_response():
def check_server_access(): def check_server_access():
with monitor_lock: with monitor_lock:
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
server_response = pms_connect.get_server_response() server_response = pms_connect.get_server_response()

View file

@ -32,10 +32,10 @@ import xmltodict
import plexpy import plexpy
import config import config
import database import database
import libraries
import logger import logger
import mobile_app import mobile_app
import plextv import users
import pmsconnect
class API2: class API2:
@ -345,14 +345,14 @@ class API2:
def refresh_libraries_list(self, **kwargs): def refresh_libraries_list(self, **kwargs):
""" Refresh the Tautulli libraries list.""" """ Refresh the Tautulli libraries list."""
data = pmsconnect.refresh_libraries() data = libraries.refresh_libraries()
self._api_result_type = 'success' if data else 'error' self._api_result_type = 'success' if data else 'error'
return data return data
def refresh_users_list(self, **kwargs): def refresh_users_list(self, **kwargs):
""" Refresh the Tautulli users list.""" """ Refresh the Tautulli users list."""
data = plextv.refresh_users() data = users.refresh_users()
self._api_result_type = 'success' if data else 'error' self._api_result_type = 'success' if data else 'error'
return data return data

View file

@ -140,10 +140,10 @@ SCHEDULER_LIST = ['Check GitHub for updates',
'Check for recently added items', 'Check for recently added items',
'Check for Plex updates', 'Check for Plex updates',
'Check for Plex remote access', 'Check for Plex remote access',
'Check server response',
'Refresh users list', 'Refresh users list',
'Refresh libraries list', 'Refresh libraries list',
'Refresh Plex server URLs', 'Refresh Plex server URLs',
'Refresh Plex server name',
'Backup Tautulli database', 'Backup Tautulli database',
'Backup Tautulli config' 'Backup Tautulli config'
] ]

View file

@ -45,6 +45,7 @@ _CONFIG_DEFINITIONS = {
'PLEXWATCH_DATABASE': (str, 'PlexWatch', ''), 'PLEXWATCH_DATABASE': (str, 'PlexWatch', ''),
'PMS_IDENTIFIER': (str, 'PMS', ''), 'PMS_IDENTIFIER': (str, 'PMS', ''),
'PMS_IP': (str, 'PMS', '127.0.0.1'), 'PMS_IP': (str, 'PMS', '127.0.0.1'),
'PMS_IS_CLOUD': (int, 'PMS', 0),
'PMS_IS_REMOTE': (int, 'PMS', 0), 'PMS_IS_REMOTE': (int, 'PMS', 0),
'PMS_LOGS_FOLDER': (str, 'PMS', ''), 'PMS_LOGS_FOLDER': (str, 'PMS', ''),
'PMS_LOGS_LINE_CAP': (int, 'PMS', 1000), 'PMS_LOGS_LINE_CAP': (int, 'PMS', 1000),

View file

@ -1,24 +1,28 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of Tautulli. # This file is part of PlexPy.
# #
# Tautulli is free software: you can redistribute it and/or modify # PlexPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or # the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version. # (at your option) any later version.
# #
# Tautulli is distributed in the hope that it will be useful, # PlexPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>. # along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from httplib import HTTPSConnection from functools import partial
from httplib import HTTPConnection from multiprocessing.dummy import Pool as ThreadPool
import ssl from urlparse import urljoin
import certifi
from requests.packages import urllib3
from requests.packages.urllib3.exceptions import InsecureRequestWarning
import plexpy import plexpy
import helpers import helpers
@ -30,94 +34,144 @@ class HTTPHandler(object):
Retrieve data from Plex Server Retrieve data from Plex Server
""" """
def __init__(self, host, port, token, ssl_verify=True): def __init__(self, urls, token=None, timeout=10, ssl_verify=True):
self.host = host if isinstance(urls, basestring):
self.port = str(port) self.urls = urls.split() or urls.split(',')
else:
self.urls = urls
self.token = token self.token = token
if self.token:
self.headers = {'X-Plex-Token': self.token}
else:
self.headers = {}
self.timeout = timeout
self.ssl_verify = ssl_verify self.ssl_verify = ssl_verify
""" self.valid_request_types = ('GET', 'POST', 'PUT', 'DELETE')
Handle the HTTP requests.
Output: object
"""
def make_request(self, def make_request(self,
uri=None, proto='HTTP', uri=None,
request_type='GET',
headers=None, headers=None,
request_type='GET',
output_format='raw', output_format='raw',
return_type=False, return_type=False,
no_token=False, no_token=False,
timeout=None): timeout=None,
callback=None):
"""
Handle the HTTP requests.
if timeout is None: Output: list
timeout = plexpy.CONFIG.PMS_TIMEOUT """
valid_request_types = ['GET', 'POST', 'PUT', 'DELETE'] self.uri = uri
self.request_type = request_type.upper()
self.output_format = output_format.lower()
self.return_type = return_type
self.callback = callback
self.timeout = timeout or self.timeout
if request_type.upper() not in valid_request_types: if self.request_type not in self.valid_request_types:
logger.debug(u"HTTP request made but unsupported request type given.") logger.debug(u"HTTP request made but unsupported request type given.")
return None return None
if uri: if uri:
if proto.upper() == 'HTTPS': request_urls = [urljoin(url, self.uri) for url in self.urls]
if not self.ssl_verify and hasattr(ssl, '_create_unverified_context'):
context = ssl._create_unverified_context()
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout, context=context)
logger.warn(u"Tautulli HTTP Handler :: Unverified HTTPS request made. This connection is not secure.")
else:
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout)
else:
handler = HTTPConnection(host=self.host, port=self.port, timeout=timeout)
if not no_token: if no_token and headers:
if headers: self.headers = headers
headers.update({'X-Plex-Token': self.token}) elif headers:
else: self.headers.update(headers)
headers = {'X-Plex-Token': self.token}
try: responses = []
if headers: for r in self._http_requests_pool(request_urls):
handler.request(request_type, uri, headers=headers) responses.append(r)
else:
handler.request(request_type, uri)
response = handler.getresponse()
request_status = response.status
request_content = response.read()
content_type = response.getheader('content-type')
except IOError as e:
logger.warn(u"Failed to access uri endpoint %s with error %s" % (uri, e))
return None
except Exception as e:
logger.warn(u"Failed to access uri endpoint %s. Is your server maybe accepting SSL connections only? %s" % (uri, e))
return None
except:
logger.warn(u"Failed to access uri endpoint %s with Uncaught exception." % uri)
return None
if request_status in (200, 201): return responses[0]
try:
if output_format == 'dict':
output = helpers.convert_xml_to_dict(request_content)
elif output_format == 'json':
output = helpers.convert_xml_to_json(request_content)
elif output_format == 'xml':
output = helpers.parse_xml(request_content)
else:
output = request_content
if return_type:
return output, content_type
return output
except Exception as e:
logger.warn(u"Failed format response from uri %s to %s error %s" % (uri, output_format, e))
return None
else:
logger.warn(u"Failed to access uri endpoint %s. Status code %r" % (uri, request_status))
return None
else: else:
logger.debug(u"HTTP request made but no enpoint given.") logger.debug(u"HTTP request made but no enpoint given.")
return None return None
def _http_requests_pool(self, urls, workers=10, chunk=None):
"""Generator function to request urls in chunks"""
# From cpython
if chunk is None:
chunk, extra = divmod(len(urls), workers * 4)
if extra:
chunk += 1
if len(urls) == 0:
chunk = 0
if self.ssl_verify:
session = urllib3.PoolManager(cert_reqs='CERT_REQUIRED', ca_certs=certifi.where())
else:
urllib3.disable_warnings(InsecureRequestWarning)
session = urllib3.PoolManager()
part = partial(self._http_requests_urllib3, session=session)
if len(urls) == 1:
yield part(urls[0])
else:
pool = ThreadPool(workers)
try:
for work in pool.imap_unordered(part, urls, chunk):
yield work
except Exception as e:
logger.error(u"Failed to yield request: %s" % e)
finally:
pool.close()
pool.join()
def _http_requests_urllib3(self, url, session):
"""Request the data from the url"""
try:
r = session.request(self.request_type, url, headers=self.headers, timeout=self.timeout)
except IOError as e:
logger.warn(u"Failed to access uri endpoint %s with error %s" % (self.uri, e))
return None
except Exception as e:
logger.warn(u"Failed to access uri endpoint %s. Is your server maybe accepting SSL connections only? %s" % (self.uri, e))
return None
except:
logger.warn(u"Failed to access uri endpoint %s with Uncaught exception." % self.uri)
return None
response_status = r.status
response_content = r.data
response_headers = r.headers
if response_status in (200, 201):
return self._http_format_output(response_content, response_headers)
else:
logger.warn(u"Failed to access uri endpoint %s. Status code %r" % (self.uri, response_status))
return None
def _http_format_output(self, response_content, response_headers):
"""Formats the request response to the desired type"""
try:
if self.output_format == 'text':
output = response_content.decode('utf-8', 'ignore')
if self.output_format == 'dict':
output = helpers.convert_xml_to_dict(response_content.decode('utf-8', 'ignore'))
elif self.output_format == 'json':
output = helpers.convert_xml_to_json(response_content.decode('utf-8', 'ignore'))
elif self.output_format == 'xml':
output = helpers.parse_xml(response_content.decode('utf-8', 'ignore'))
else:
output = response_content
if self.callback:
return self.callback(output)
if self.return_type:
return output, response_headers['Content-Type']
return output
except Exception as e:
logger.warn(u"Failed format response from uri %s to %s error %s" % (self.uri, self.response_type, e))
return None

View file

@ -27,6 +27,66 @@ import pmsconnect
import session import session
def refresh_libraries():
logger.info(u"Tautulli Libraries :: Requesting libraries list refresh...")
server_id = plexpy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error(u"Tautulli Libraries :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
return
library_sections = pmsconnect.PmsConnect().get_library_details()
if library_sections:
monitor_db = database.MonitorDatabase()
library_keys = []
new_keys = []
for section in library_sections:
section_keys = {'server_id': server_id,
'section_id': section['section_id']}
section_values = {'server_id': server_id,
'section_id': section['section_id'],
'section_name': section['section_name'],
'section_type': section['section_type'],
'thumb': section['thumb'],
'art': section['art'],
'count': section['count'],
'parent_count': section.get('parent_count', None),
'child_count': section.get('child_count', None),
}
result = monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
library_keys.append(section['section_id'])
if result == 'insert':
new_keys.append(section['section_id'])
if plexpy.CONFIG.HOME_LIBRARY_CARDS == ['first_run_wizard']:
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys)
plexpy.CONFIG.write()
else:
new_keys = plexpy.CONFIG.HOME_LIBRARY_CARDS + new_keys
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', new_keys)
plexpy.CONFIG.write()
#if plexpy.CONFIG.UPDATE_SECTION_IDS == 1 or plexpy.CONFIG.UPDATE_SECTION_IDS == -1:
# # Start library section_id update on it's own thread
# threading.Thread(target=libraries.update_section_ids).start()
#if plexpy.CONFIG.UPDATE_LABELS == 1 or plexpy.CONFIG.UPDATE_LABELS == -1:
# # Start library labels update on it's own thread
# threading.Thread(target=libraries.update_labels).start()
logger.info(u"Tautulli Libraries :: Libraries list refreshed.")
return True
else:
logger.warn(u"Tautulli Libraries :: Unable to refresh libraries list.")
return False
def update_section_ids(): def update_section_ids():
plexpy.CONFIG.UPDATE_SECTION_IDS = -1 plexpy.CONFIG.UPDATE_SECTION_IDS = -1
@ -965,7 +1025,7 @@ class Libraries(object):
monitor_db = database.MonitorDatabase() monitor_db = database.MonitorDatabase()
# Refresh the PMS_URL to make sure the server_id is updated # Refresh the PMS_URL to make sure the server_id is updated
plextv.get_real_pms_url() plextv.get_server_resources()
server_id = plexpy.CONFIG.PMS_IDENTIFIER server_id = plexpy.CONFIG.PMS_IDENTIFIER

View file

@ -23,7 +23,6 @@ import activity_processor
import database import database
import helpers import helpers
import logger import logger
import plextv
import users import users
@ -284,7 +283,7 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
# Get the latest friends list so we can pull user id's # Get the latest friends list so we can pull user id's
try: try:
plextv.refresh_users() users.refresh_users()
except: except:
logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.") logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.")
return None return None

View file

@ -18,11 +18,9 @@
import base64 import base64
import json import json
from xml.dom import minidom
import plexpy import plexpy
import common import common
import database
import helpers import helpers
import http_handler import http_handler
import logger import logger
@ -31,129 +29,99 @@ import pmsconnect
import session import session
def refresh_users(): def get_server_resources(return_presence=False):
logger.info(u"Tautulli PlexTV :: Requesting users list refresh...") if not return_presence:
result = PlexTV().get_full_users_list() logger.info(u"Tautulli PlexTV :: Requesting resources for server...")
monitor_db = database.MonitorDatabase() server = {'pms_name': plexpy.CONFIG.PMS_NAME,
user_data = users.Users() 'pms_version': plexpy.CONFIG.PMS_VERSION,
'pms_platform': plexpy.CONFIG.PMS_PLATFORM,
'pms_ip': plexpy.CONFIG.PMS_IP,
'pms_port': plexpy.CONFIG.PMS_PORT,
'pms_ssl': plexpy.CONFIG.PMS_SSL,
'pms_is_remote': plexpy.CONFIG.PMS_IS_REMOTE,
'pms_is_cloud': plexpy.CONFIG.PMS_IS_CLOUD,
'pms_url': plexpy.CONFIG.PMS_URL,
'pms_url_manual': plexpy.CONFIG.PMS_URL_MANUAL
}
if result: if server['pms_url_manual'] and server['pms_ssl'] or server['pms_is_cloud']:
for item in result: scheme = 'https'
shared_libraries = ''
user_tokens = user_data.get_tokens(user_id=item['user_id'])
if user_tokens and user_tokens['server_token']:
pms_connect = pmsconnect.PmsConnect(token=user_tokens['server_token'])
library_details = pms_connect.get_server_children()
if library_details:
shared_libraries = ';'.join(d['section_id'] for d in library_details['libraries_list'])
else:
shared_libraries = ''
control_value_dict = {"user_id": item['user_id']}
new_value_dict = {"username": item['username'],
"thumb": item['thumb'],
"email": item['email'],
"is_home_user": item['is_home_user'],
"is_allow_sync": item['is_allow_sync'],
"is_restricted": item['is_restricted'],
"shared_libraries": shared_libraries,
"filter_all": item['filter_all'],
"filter_movies": item['filter_movies'],
"filter_tv": item['filter_tv'],
"filter_music": item['filter_music'],
"filter_photos": item['filter_photos']
}
# Check if we've set a custom avatar if so don't overwrite it.
if item['user_id']:
avatar_urls = monitor_db.select('SELECT thumb, custom_avatar_url '
'FROM users WHERE user_id = ?',
[item['user_id']])
if avatar_urls:
if not avatar_urls[0]['custom_avatar_url'] or \
avatar_urls[0]['custom_avatar_url'] == avatar_urls[0]['thumb']:
new_value_dict['custom_avatar_url'] = item['thumb']
else:
new_value_dict['custom_avatar_url'] = item['thumb']
monitor_db.upsert('users', new_value_dict, control_value_dict)
logger.info(u"Tautulli PlexTV :: Users list refreshed.")
return True
else: else:
logger.warn(u"Tautulli PlexTV :: Unable to refresh users list.") scheme = 'http'
return False
fallback_url = '{scheme}://{hostname}:{port}'.format(scheme=scheme,
def get_real_pms_url(): hostname=server['pms_ip'],
logger.info(u"Tautulli PlexTV :: Requesting URLs for server...") port=server['pms_port'])
# Reset any current PMS_URL value
plexpy.CONFIG.__setattr__('PMS_URL', '')
plexpy.CONFIG.write()
fallback_url = 'http://{}:{}'.format(plexpy.CONFIG.PMS_IP, plexpy.CONFIG.PMS_PORT)
plex_tv = PlexTV() plex_tv = PlexTV()
result = plex_tv.get_server_urls(include_https=plexpy.CONFIG.PMS_SSL) result = plex_tv.get_server_connections(pms_identifier=plexpy.CONFIG.PMS_IDENTIFIER,
plexpass = plex_tv.get_plexpass_status() pms_ip=server['pms_ip'],
pms_port=server['pms_port'],
include_https=server['pms_ssl'])
connections = []
if result: if result:
plexpy.CONFIG.__setattr__('PMS_VERSION', result['version']) connections = result.pop('connections', [])
plexpy.CONFIG.__setattr__('PMS_PLATFORM', result['platform']) server.update(result)
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', plexpass) presence = server.pop('server_presence', 0)
connections = result['connections'] else:
connections = []
presence = 0
if return_presence:
return presence
plexpass = plex_tv.get_plexpass_status()
server['pms_plexpass'] = int(plexpass)
# Only need to retrieve PMS_URL if using SSL # Only need to retrieve PMS_URL if using SSL
if not plexpy.CONFIG.PMS_URL_MANUAL and plexpy.CONFIG.PMS_SSL: if not server['pms_url_manual'] and server['pms_ssl']:
if connections: if connections:
if plexpy.CONFIG.PMS_IS_REMOTE: if server['pms_is_remote']:
# Get all remote connections # Get all remote connections
conns = [c for c in connections if c['local'] == '0' and 'plex.direct' in c['uri']] conns = [c for c in connections if
c['local'] == '0' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])]
else: else:
# Get all local connections # Get all local connections
conns = [c for c in connections if c['local'] == '1' and 'plex.direct' in c['uri']] conns = [c for c in connections if
c['local'] == '1' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])]
if conns: if conns:
# Get connection with matching address, otherwise return first connection # Get connection with matching address, otherwise return first connection
conn = next((c for c in conns if c['address'] == plexpy.CONFIG.PMS_IP conn = next((c for c in conns if c['address'] == server['pms_ip']
and c['port'] == str(plexpy.CONFIG.PMS_PORT)), conns[0]) and c['port'] == str(server['pms_port'])), conns[0])
plexpy.CONFIG.__setattr__('PMS_URL', conn['uri']) server['pms_url'] = conn['uri']
plexpy.CONFIG.write()
logger.info(u"Tautulli PlexTV :: Server URL retrieved.") logger.info(u"Tautulli PlexTV :: Server URL retrieved.")
# get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL # get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL
if not plexpy.CONFIG.PMS_URL: if not server['pms_url']:
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url) server['pms_url'] = fallback_url
plexpy.CONFIG.write()
logger.warn(u"Tautulli PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.") logger.warn(u"Tautulli PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.")
# Not using SSL, remote has no effect # Not using SSL, remote has no effect
else: else:
if plexpy.CONFIG.PMS_URL_MANUAL and plexpy.CONFIG.PMS_SSL: server['pms_url'] = fallback_url
fallback_url = fallback_url.replace('http://', 'https://')
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
plexpy.CONFIG.write()
logger.info(u"Tautulli PlexTV :: Using user-defined URL.") logger.info(u"Tautulli PlexTV :: Using user-defined URL.")
plexpy.CONFIG.process_kwargs(server)
plexpy.CONFIG.write()
class PlexTV(object): class PlexTV(object):
""" """
Plex.tv authentication Plex.tv authentication
""" """
def __init__(self, username='', password='', token=None): def __init__(self, username=None, password=None, token=None):
self.protocol = 'HTTPS'
self.username = username self.username = username
self.password = password self.password = password
self.token = token
self.urls = 'https://plex.tv'
self.timeout = plexpy.CONFIG.PMS_TIMEOUT
self.ssl_verify = plexpy.CONFIG.VERIFY_SSL_CERT self.ssl_verify = plexpy.CONFIG.VERIFY_SSL_CERT
if not token: if not self.token:
# Check if we should use the admin token, or the guest server token # Check if we should use the admin token, or the guest server token
if session.get_session_user_id(): if session.get_session_user_id():
user_data = users.Users() user_data = users.Users()
@ -161,12 +129,14 @@ class PlexTV(object):
self.token = user_tokens['server_token'] self.token = user_tokens['server_token']
else: else:
self.token = plexpy.CONFIG.PMS_TOKEN self.token = plexpy.CONFIG.PMS_TOKEN
else:
self.token = token
self.request_handler = http_handler.HTTPHandler(host='plex.tv', if not self.token:
port=443, logger.error(u"Tautulli PlexTV :: PlexTV called, but no token provided.")
return
self.request_handler = http_handler.HTTPHandler(urls=self.urls,
token=self.token, token=self.token,
timeout=self.timeout,
ssl_verify=self.ssl_verify) ssl_verify=self.ssl_verify)
def get_plex_auth(self, output_format='raw'): def get_plex_auth(self, output_format='raw'):
@ -183,7 +153,6 @@ class PlexTV(object):
} }
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='POST', request_type='POST',
headers=headers, headers=headers,
output_format=output_format, output_format=output_format,
@ -265,7 +234,6 @@ class PlexTV(object):
def get_plextv_friends(self, output_format=''): def get_plextv_friends(self, output_format=''):
uri = '/api/users' uri = '/api/users'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -274,7 +242,6 @@ class PlexTV(object):
def get_plextv_user_details(self, output_format=''): def get_plextv_user_details(self, output_format=''):
uri = '/users/account' uri = '/users/account'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -283,7 +250,6 @@ class PlexTV(object):
def get_plextv_devices_list(self, output_format=''): def get_plextv_devices_list(self, output_format=''):
uri = '/devices.xml' uri = '/devices.xml'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -292,7 +258,6 @@ class PlexTV(object):
def get_plextv_server_list(self, output_format=''): def get_plextv_server_list(self, output_format=''):
uri = '/pms/servers.xml' uri = '/pms/servers.xml'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -301,7 +266,6 @@ class PlexTV(object):
def get_plextv_sync_lists(self, machine_id='', output_format=''): def get_plextv_sync_lists(self, machine_id='', output_format=''):
uri = '/servers/%s/sync_lists' % machine_id uri = '/servers/%s/sync_lists' % machine_id
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -313,7 +277,6 @@ class PlexTV(object):
else: else:
uri = '/api/resources' uri = '/api/resources'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -325,7 +288,6 @@ class PlexTV(object):
else: else:
uri = '/api/downloads/1.json' uri = '/api/downloads/1.json'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -334,7 +296,6 @@ class PlexTV(object):
def delete_plextv_device(self, device_id='', output_format=''): def delete_plextv_device(self, device_id='', output_format=''):
uri = '/devices/%s.xml' % device_id uri = '/devices/%s.xml' % device_id
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='DELETE', request_type='DELETE',
output_format=output_format) output_format=output_format)
@ -343,7 +304,6 @@ class PlexTV(object):
def delete_plextv_device_sync_lists(self, client_id='', output_format=''): def delete_plextv_device_sync_lists(self, client_id='', output_format=''):
uri = '/devices/%s/sync_items' % client_id uri = '/devices/%s/sync_items' % client_id
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -352,197 +312,174 @@ class PlexTV(object):
def delete_plextv_sync(self, client_id='', sync_id='', output_format=''): def delete_plextv_sync(self, client_id='', sync_id='', output_format=''):
uri = '/devices/%s/sync_items/%s' % (client_id, sync_id) uri = '/devices/%s/sync_items/%s' % (client_id, sync_id)
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='DELETE', request_type='DELETE',
output_format=output_format) output_format=output_format)
return request return request
def get_full_users_list(self): def get_full_users_list(self):
friends_list = self.get_plextv_friends() friends_list = self.get_plextv_friends(output_format='xml')
own_account = self.get_plextv_user_details() own_account = self.get_plextv_user_details(output_format='xml')
users_list = [] users_list = []
try: try:
xml_parse = minidom.parseString(own_account) xml_head = own_account.getElementsByTagName('user')
except Exception as e: except Exception as e:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list own account: %s" % e) logger.warn(u"Tautulli PlexTV :: Unable to parse own account XML for get_full_users_list: %s." % e)
return [] return {}
except:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list own account.")
return []
xml_head = xml_parse.getElementsByTagName('user') for a in xml_head:
if not xml_head: own_details = {"user_id": helpers.get_xml_attr(a, 'id'),
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list.") "username": helpers.get_xml_attr(a, 'username'),
else: "thumb": helpers.get_xml_attr(a, 'thumb'),
for a in xml_head: "email": helpers.get_xml_attr(a, 'email'),
own_details = {"user_id": helpers.get_xml_attr(a, 'id'), "is_home_user": helpers.get_xml_attr(a, 'home'),
"username": helpers.get_xml_attr(a, 'username'), "is_allow_sync": None,
"thumb": helpers.get_xml_attr(a, 'thumb'), "is_restricted": helpers.get_xml_attr(a, 'restricted'),
"email": helpers.get_xml_attr(a, 'email'), "filter_all": helpers.get_xml_attr(a, 'filterAll'),
"is_home_user": helpers.get_xml_attr(a, 'home'), "filter_movies": helpers.get_xml_attr(a, 'filterMovies'),
"is_allow_sync": None, "filter_tv": helpers.get_xml_attr(a, 'filterTelevision'),
"is_restricted": helpers.get_xml_attr(a, 'restricted'), "filter_music": helpers.get_xml_attr(a, 'filterMusic'),
"filter_all": helpers.get_xml_attr(a, 'filterAll'), "filter_photos": helpers.get_xml_attr(a, 'filterPhotos')
"filter_movies": helpers.get_xml_attr(a, 'filterMovies'), }
"filter_tv": helpers.get_xml_attr(a, 'filterTelevision'),
"filter_music": helpers.get_xml_attr(a, 'filterMusic'),
"filter_photos": helpers.get_xml_attr(a, 'filterPhotos')
}
users_list.append(own_details) users_list.append(own_details)
try: try:
xml_parse = minidom.parseString(friends_list) xml_head = friends_list.getElementsByTagName('User')
except Exception as e: except Exception as e:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list friends list: %s" % e) logger.warn(u"Tautulli PlexTV :: Unable to parse friends list XML for get_full_users_list: %s." % e)
return [] return {}
except:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list friends list.")
return []
xml_head = xml_parse.getElementsByTagName('User') for a in xml_head:
if not xml_head: friend = {"user_id": helpers.get_xml_attr(a, 'id'),
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list.") "username": helpers.get_xml_attr(a, 'title'),
else: "thumb": helpers.get_xml_attr(a, 'thumb'),
for a in xml_head: "email": helpers.get_xml_attr(a, 'email'),
friend = {"user_id": helpers.get_xml_attr(a, 'id'), "is_home_user": helpers.get_xml_attr(a, 'home'),
"username": helpers.get_xml_attr(a, 'title'), "is_allow_sync": helpers.get_xml_attr(a, 'allowSync'),
"thumb": helpers.get_xml_attr(a, 'thumb'), "is_restricted": helpers.get_xml_attr(a, 'restricted'),
"email": helpers.get_xml_attr(a, 'email'), "filter_all": helpers.get_xml_attr(a, 'filterAll'),
"is_home_user": helpers.get_xml_attr(a, 'home'), "filter_movies": helpers.get_xml_attr(a, 'filterMovies'),
"is_allow_sync": helpers.get_xml_attr(a, 'allowSync'), "filter_tv": helpers.get_xml_attr(a, 'filterTelevision'),
"is_restricted": helpers.get_xml_attr(a, 'restricted'), "filter_music": helpers.get_xml_attr(a, 'filterMusic'),
"filter_all": helpers.get_xml_attr(a, 'filterAll'), "filter_photos": helpers.get_xml_attr(a, 'filterPhotos')
"filter_movies": helpers.get_xml_attr(a, 'filterMovies'), }
"filter_tv": helpers.get_xml_attr(a, 'filterTelevision'),
"filter_music": helpers.get_xml_attr(a, 'filterMusic'),
"filter_photos": helpers.get_xml_attr(a, 'filterPhotos')
}
users_list.append(friend) users_list.append(friend)
return users_list return users_list
def get_synced_items(self, machine_id=None, client_id_filter=None, user_id_filter=None, rating_key_filter=None): def get_synced_items(self, machine_id=None, client_id_filter=None, user_id_filter=None, rating_key_filter=None):
sync_list = self.get_plextv_sync_lists(machine_id) sync_list = self.get_plextv_sync_lists(machine_id, output_format='xml')
user_data = users.Users() user_data = users.Users()
synced_items = [] synced_items = []
try: try:
xml_parse = minidom.parseString(sync_list) xml_head = sync_list.getElementsByTagName('SyncList')
except Exception as e: except Exception as e:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s" % e) logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s." % e)
return [] return {}
except:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items.")
return []
xml_head = xml_parse.getElementsByTagName('SyncList') for a in xml_head:
client_id = helpers.get_xml_attr(a, 'clientIdentifier')
if not xml_head: # Filter by client_id
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items.") if client_id_filter and client_id_filter != client_id:
else: continue
for a in xml_head:
client_id = helpers.get_xml_attr(a, 'clientIdentifier')
# Filter by client_id sync_id = helpers.get_xml_attr(a, 'id')
if client_id_filter and client_id_filter != client_id: sync_device = a.getElementsByTagName('Device')
continue
sync_id = helpers.get_xml_attr(a, 'id') for device in sync_device:
sync_device = a.getElementsByTagName('Device') device_user_id = helpers.get_xml_attr(device, 'userID')
try:
device_username = user_data.get_details(user_id=device_user_id)['username']
device_friendly_name = user_data.get_details(user_id=device_user_id)['friendly_name']
except:
device_username = ''
device_friendly_name = ''
device_name = helpers.get_xml_attr(device, 'name')
device_product = helpers.get_xml_attr(device, 'product')
device_product_version = helpers.get_xml_attr(device, 'productVersion')
device_platform = helpers.get_xml_attr(device, 'platform')
device_platform_version = helpers.get_xml_attr(device, 'platformVersion')
device_type = helpers.get_xml_attr(device, 'device')
device_model = helpers.get_xml_attr(device, 'model')
device_last_seen = helpers.get_xml_attr(device, 'lastSeenAt')
for device in sync_device: # Filter by user_id
device_user_id = helpers.get_xml_attr(device, 'userID') if user_id_filter and user_id_filter != device_user_id:
try: continue
device_username = user_data.get_details(user_id=device_user_id)['username']
device_friendly_name = user_data.get_details(user_id=device_user_id)['friendly_name']
except:
device_username = ''
device_friendly_name = ''
device_name = helpers.get_xml_attr(device, 'name')
device_product = helpers.get_xml_attr(device, 'product')
device_product_version = helpers.get_xml_attr(device, 'productVersion')
device_platform = helpers.get_xml_attr(device, 'platform')
device_platform_version = helpers.get_xml_attr(device, 'platformVersion')
device_type = helpers.get_xml_attr(device, 'device')
device_model = helpers.get_xml_attr(device, 'model')
device_last_seen = helpers.get_xml_attr(device, 'lastSeenAt')
# Filter by user_id for synced in a.getElementsByTagName('SyncItems'):
if user_id_filter and user_id_filter != device_user_id: sync_item = synced.getElementsByTagName('SyncItem')
continue for item in sync_item:
for synced in a.getElementsByTagName('SyncItems'): for location in item.getElementsByTagName('Location'):
sync_item = synced.getElementsByTagName('SyncItem') clean_uri = helpers.get_xml_attr(location, 'uri').split('%2F')
for item in sync_item:
for location in item.getElementsByTagName('Location'): rating_key = next((clean_uri[(idx + 1) % len(clean_uri)]
clean_uri = helpers.get_xml_attr(location, 'uri').split('%2F') for idx, item in enumerate(clean_uri) if item == 'metadata'), None)
rating_key = next((clean_uri[(idx + 1) % len(clean_uri)] # Filter by rating_key
for idx, item in enumerate(clean_uri) if item == 'metadata'), None) if rating_key_filter and rating_key_filter != rating_key:
continue
# Filter by rating_key sync_id = helpers.get_xml_attr(item, 'id')
if rating_key_filter and rating_key_filter != rating_key: sync_version = helpers.get_xml_attr(item, 'version')
continue sync_root_title = helpers.get_xml_attr(item, 'rootTitle')
sync_title = helpers.get_xml_attr(item, 'title')
sync_metadata_type = helpers.get_xml_attr(item, 'metadataType')
sync_content_type = helpers.get_xml_attr(item, 'contentType')
sync_id = helpers.get_xml_attr(item, 'id') for status in item.getElementsByTagName('Status'):
sync_version = helpers.get_xml_attr(item, 'version') status_failure_code = helpers.get_xml_attr(status, 'failureCode')
sync_root_title = helpers.get_xml_attr(item, 'rootTitle') status_failure = helpers.get_xml_attr(status, 'failure')
sync_title = helpers.get_xml_attr(item, 'title') status_state = helpers.get_xml_attr(status, 'state')
sync_metadata_type = helpers.get_xml_attr(item, 'metadataType') status_item_count = helpers.get_xml_attr(status, 'itemsCount')
sync_content_type = helpers.get_xml_attr(item, 'contentType') status_item_complete_count = helpers.get_xml_attr(status, 'itemsCompleteCount')
status_item_downloaded_count = helpers.get_xml_attr(status, 'itemsDownloadedCount')
status_item_ready_count = helpers.get_xml_attr(status, 'itemsReadyCount')
status_item_successful_count = helpers.get_xml_attr(status, 'itemsSuccessfulCount')
status_total_size = helpers.get_xml_attr(status, 'totalSize')
status_item_download_percent_complete = helpers.get_percent(
status_item_downloaded_count, status_item_count)
for status in item.getElementsByTagName('Status'): for settings in item.getElementsByTagName('MediaSettings'):
status_failure_code = helpers.get_xml_attr(status, 'failureCode') settings_audio_boost = helpers.get_xml_attr(settings, 'audioBoost')
status_failure = helpers.get_xml_attr(status, 'failure') settings_music_bitrate = helpers.get_xml_attr(settings, 'musicBitrate')
status_state = helpers.get_xml_attr(status, 'state') settings_photo_quality = helpers.get_xml_attr(settings, 'photoQuality')
status_item_count = helpers.get_xml_attr(status, 'itemsCount') settings_photo_resolution = helpers.get_xml_attr(settings, 'photoResolution')
status_item_complete_count = helpers.get_xml_attr(status, 'itemsCompleteCount') settings_video_quality = helpers.get_xml_attr(settings, 'videoQuality')
status_item_downloaded_count = helpers.get_xml_attr(status, 'itemsDownloadedCount') settings_video_resolution = helpers.get_xml_attr(settings, 'videoResolution')
status_item_ready_count = helpers.get_xml_attr(status, 'itemsReadyCount')
status_item_successful_count = helpers.get_xml_attr(status, 'itemsSuccessfulCount')
status_total_size = helpers.get_xml_attr(status, 'totalSize')
status_item_download_percent_complete = helpers.get_percent(
status_item_downloaded_count, status_item_count)
for settings in item.getElementsByTagName('MediaSettings'): sync_details = {"device_name": helpers.sanitize(device_name),
settings_audio_boost = helpers.get_xml_attr(settings, 'audioBoost') "platform": helpers.sanitize(device_platform),
settings_music_bitrate = helpers.get_xml_attr(settings, 'musicBitrate') "username": helpers.sanitize(device_username),
settings_photo_quality = helpers.get_xml_attr(settings, 'photoQuality') "friendly_name": helpers.sanitize(device_friendly_name),
settings_photo_resolution = helpers.get_xml_attr(settings, 'photoResolution') "user_id": device_user_id,
settings_video_quality = helpers.get_xml_attr(settings, 'videoQuality') "root_title": helpers.sanitize(sync_root_title),
settings_video_resolution = helpers.get_xml_attr(settings, 'videoResolution') "title": helpers.sanitize(sync_title),
"metadata_type": sync_metadata_type,
"content_type": sync_content_type,
"rating_key": rating_key,
"state": status_state,
"item_count": status_item_count,
"item_complete_count": status_item_complete_count,
"item_downloaded_count": status_item_downloaded_count,
"item_downloaded_percent_complete": status_item_download_percent_complete,
"music_bitrate": settings_music_bitrate,
"photo_quality": settings_photo_quality,
"video_quality": settings_video_quality,
"total_size": status_total_size,
"failure": status_failure,
"client_id": client_id,
"sync_id": sync_id
}
sync_details = {"device_name": helpers.sanitize(device_name), synced_items.append(sync_details)
"platform": helpers.sanitize(device_platform),
"username": helpers.sanitize(device_username),
"friendly_name": helpers.sanitize(device_friendly_name),
"user_id": device_user_id,
"root_title": helpers.sanitize(sync_root_title),
"title": helpers.sanitize(sync_title),
"metadata_type": sync_metadata_type,
"content_type": sync_content_type,
"rating_key": rating_key,
"state": status_state,
"item_count": status_item_count,
"item_complete_count": status_item_complete_count,
"item_downloaded_count": status_item_downloaded_count,
"item_downloaded_percent_complete": status_item_download_percent_complete,
"music_bitrate": settings_music_bitrate,
"photo_quality": settings_photo_quality,
"video_quality": settings_video_quality,
"total_size": status_total_size,
"failure": status_failure,
"client_id": client_id,
"sync_id": sync_id
}
synced_items.append(sync_details)
return session.filter_session_info(synced_items, filter_key='user_id') return session.filter_session_info(synced_items, filter_key='user_id')
@ -550,27 +487,16 @@ class PlexTV(object):
logger.info(u"Tautulli PlexTV :: Deleting sync item '%s'." % sync_id) logger.info(u"Tautulli PlexTV :: Deleting sync item '%s'." % sync_id)
self.delete_plextv_sync(client_id=client_id, sync_id=sync_id) self.delete_plextv_sync(client_id=client_id, sync_id=sync_id)
def get_server_urls(self, include_https=True): def get_server_connections(self, pms_identifier='', pms_ip='', pms_port=32400, include_https=True):
if plexpy.CONFIG.PMS_IDENTIFIER: if not pms_identifier:
server_id = plexpy.CONFIG.PMS_IDENTIFIER logger.error(u"Tautulli PlexTV :: Unable to retrieve server connections: no pms_identifier provided.")
else:
logger.error(u"Tautulli PlexTV :: Unable to retrieve server identity.")
return {} return {}
plextv_resources = self.get_plextv_resources(include_https=include_https) plextv_resources = self.get_plextv_resources(include_https=include_https,
output_format='xml')
try: try:
xml_parse = minidom.parseString(plextv_resources) xml_head = plextv_resources.getElementsByTagName('Device')
except Exception as e:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s" % e)
return {}
except:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls.")
return {}
try:
xml_head = xml_parse.getElementsByTagName('Device')
except Exception as e: except Exception as e:
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s." % e) logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s." % e)
return {} return {}
@ -580,16 +506,20 @@ class PlexTV(object):
conn = [] conn = []
connections = device.getElementsByTagName('Connection') connections = device.getElementsByTagName('Connection')
server = {"platform": helpers.get_xml_attr(device, 'platform'), server = {'pms_identifier': helpers.get_xml_attr(device, 'clientIdentifier'),
"version": helpers.get_xml_attr(device, 'productVersion') 'pms_name': helpers.get_xml_attr(device, 'name'),
'pms_version': helpers.get_xml_attr(device, 'productVersion'),
'pms_platform': helpers.get_xml_attr(device, 'platform'),
'pms_presence': helpers.get_xml_attr(device, 'presence'),
'pms_is_cloud': 1 if helpers.get_xml_attr(device, 'platform') == 'Cloud' else 0
} }
for c in connections: for c in connections:
server_details = {"protocol": helpers.get_xml_attr(c, 'protocol'), server_details = {'protocol': helpers.get_xml_attr(c, 'protocol'),
"address": helpers.get_xml_attr(c, 'address'), 'address': helpers.get_xml_attr(c, 'address'),
"port": helpers.get_xml_attr(c, 'port'), 'port': helpers.get_xml_attr(c, 'port'),
"uri": helpers.get_xml_attr(c, 'uri'), 'uri': helpers.get_xml_attr(c, 'uri'),
"local": helpers.get_xml_attr(c, 'local') 'local': helpers.get_xml_attr(c, 'local')
} }
conn.append(server_details) conn.append(server_details)
@ -600,7 +530,7 @@ class PlexTV(object):
# Try to match the device # Try to match the device
for a in xml_head: for a in xml_head:
if helpers.get_xml_attr(a, 'clientIdentifier') == server_id: if helpers.get_xml_attr(a, 'clientIdentifier') == pms_identifier:
server = get_connections(a) server = get_connections(a)
break break
@ -612,15 +542,8 @@ class PlexTV(object):
connections = a.getElementsByTagName('Connection') connections = a.getElementsByTagName('Connection')
for connection in connections: for connection in connections:
if helpers.get_xml_attr(connection, 'address') == plexpy.CONFIG.PMS_IP and \ if helpers.get_xml_attr(connection, 'address') == pms_ip and \
int(helpers.get_xml_attr(connection, 'port')) == plexpy.CONFIG.PMS_PORT: helpers.get_xml_attr(connection, 'port') == str(pms_port):
plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier')
plexpy.CONFIG.write()
logger.info(u"Tautulli PlexTV :: PMS identifier changed from %s to %s."
% (server_id, plexpy.CONFIG.PMS_IDENTIFIER))
server = get_connections(a) server = get_connections(a)
break break
@ -649,7 +572,7 @@ class PlexTV(object):
return server_times return server_times
def discover(self, include_cloud=True): def discover(self, include_cloud=True, all_servers=False):
""" Query plex for all servers online. Returns the ones you own in a selectize format """ """ Query plex for all servers online. Returns the ones you own in a selectize format """
servers = self.get_plextv_resources(include_https=True, output_format='xml') servers = self.get_plextv_resources(include_https=True, output_format='xml')
clean_servers = [] clean_servers = []
@ -679,15 +602,16 @@ class PlexTV(object):
connections = d.getElementsByTagName('Connection') connections = d.getElementsByTagName('Connection')
for c in connections: for c in connections:
# If this is a remote server don't show any local IPs. if not all_servers:
if helpers.get_xml_attr(d, 'publicAddressMatches') == '0' and \ # If this is a remote server don't show any local IPs.
helpers.get_xml_attr(c, 'local') == '1': if helpers.get_xml_attr(d, 'publicAddressMatches') == '0' and \
continue helpers.get_xml_attr(c, 'local') == '1':
continue
# If this is a local server don't show any remote IPs. # If this is a local server don't show any remote IPs.
if helpers.get_xml_attr(d, 'publicAddressMatches') == '1' and \ if helpers.get_xml_attr(d, 'publicAddressMatches') == '1' and \
helpers.get_xml_attr(c, 'local') == '0': helpers.get_xml_attr(c, 'local') == '0':
continue continue
server = {'httpsRequired': helpers.get_xml_attr(d, 'httpsRequired'), server = {'httpsRequired': helpers.get_xml_attr(d, 'httpsRequired'),
'clientIdentifier': helpers.get_xml_attr(d, 'clientIdentifier'), 'clientIdentifier': helpers.get_xml_attr(d, 'clientIdentifier'),
@ -770,8 +694,6 @@ class PlexTV(object):
return True return True
else: else:
logger.debug(u"Tautulli PlexTV :: Plex Pass subscription not found.") logger.debug(u"Tautulli PlexTV :: Plex Pass subscription not found.")
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
plexpy.CONFIG.write()
return False return False
def get_devices_list(self): def get_devices_list(self):

View file

@ -22,7 +22,6 @@ import activity_processor
import database import database
import helpers import helpers
import logger import logger
import plextv
import users import users
@ -275,7 +274,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
# Get the latest friends list so we can pull user id's # Get the latest friends list so we can pull user id's
try: try:
plextv.refresh_users() users.refresh_users()
except: except:
logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.") logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.")
return None return None

View file

@ -13,16 +13,12 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>. # along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
import threading
import urllib import urllib
from urlparse import urlparse
import plexpy import plexpy
import common import common
import database
import helpers import helpers
import http_handler import http_handler
import libraries
import logger import logger
import plextv import plextv
import session import session
@ -49,83 +45,23 @@ def get_server_friendly_name():
return server_name return server_name
def refresh_libraries():
logger.info(u"Tautulli Pmsconnect :: Requesting libraries list refresh...")
server_id = plexpy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error(u"Tautulli Pmsconnect :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
return
library_sections = PmsConnect().get_library_details()
if library_sections:
monitor_db = database.MonitorDatabase()
library_keys = []
new_keys = []
for section in library_sections:
section_keys = {'server_id': server_id,
'section_id': section['section_id']}
section_values = {'server_id': server_id,
'section_id': section['section_id'],
'section_name': section['section_name'],
'section_type': section['section_type'],
'thumb': section['thumb'],
'art': section['art'],
'count': section['count'],
'parent_count': section.get('parent_count', None),
'child_count': section.get('child_count', None),
}
result = monitor_db.upsert('library_sections', key_dict=section_keys, value_dict=section_values)
library_keys.append(section['section_id'])
if result == 'insert':
new_keys.append(section['section_id'])
if plexpy.CONFIG.HOME_LIBRARY_CARDS == ['first_run_wizard']:
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', library_keys)
plexpy.CONFIG.write()
else:
new_keys = plexpy.CONFIG.HOME_LIBRARY_CARDS + new_keys
plexpy.CONFIG.__setattr__('HOME_LIBRARY_CARDS', new_keys)
plexpy.CONFIG.write()
#if plexpy.CONFIG.UPDATE_SECTION_IDS == 1 or plexpy.CONFIG.UPDATE_SECTION_IDS == -1:
# # Start library section_id update on it's own thread
# threading.Thread(target=libraries.update_section_ids).start()
#if plexpy.CONFIG.UPDATE_LABELS == 1 or plexpy.CONFIG.UPDATE_LABELS == -1:
# # Start library labels update on it's own thread
# threading.Thread(target=libraries.update_labels).start()
logger.info(u"Tautulli Pmsconnect :: Libraries list refreshed.")
return True
else:
logger.warn(u"Tautulli Pmsconnect :: Unable to refresh libraries list.")
return False
class PmsConnect(object): class PmsConnect(object):
""" """
Retrieve data from Plex Server Retrieve data from Plex Server
""" """
def __init__(self, token=None): def __init__(self, url=None, token=None):
if plexpy.CONFIG.PMS_URL: self.url = url
url_parsed = urlparse(plexpy.CONFIG.PMS_URL) self.token = token
hostname = url_parsed.hostname
port = url_parsed.port
self.protocol = url_parsed.scheme
else:
hostname = plexpy.CONFIG.PMS_IP
port = plexpy.CONFIG.PMS_PORT
self.protocol = 'http'
if not token: if not self.url and plexpy.CONFIG.PMS_URL:
self.url = plexpy.CONFIG.PMS_URL
elif not self.url:
self.url = 'http://{hostname}:{port}'.format(hostname=plexpy.CONFIG.PMS_IP,
port=plexpy.CONFIG.PMS_PORT)
self.timeout = plexpy.CONFIG.PMS_TIMEOUT
if not self.token:
# Check if we should use the admin token, or the guest server token # Check if we should use the admin token, or the guest server token
if session.get_session_user_id(): if session.get_session_user_id():
user_data = users.Users() user_data = users.Users()
@ -133,12 +69,10 @@ class PmsConnect(object):
self.token = user_tokens['server_token'] self.token = user_tokens['server_token']
else: else:
self.token = plexpy.CONFIG.PMS_TOKEN self.token = plexpy.CONFIG.PMS_TOKEN
else:
self.token = token
self.request_handler = http_handler.HTTPHandler(host=hostname, self.request_handler = http_handler.HTTPHandler(urls=self.url,
port=port, token=self.token,
token=self.token) timeout=self.timeout)
def get_sessions(self, output_format=''): def get_sessions(self, output_format=''):
""" """
@ -150,7 +84,6 @@ class PmsConnect(object):
""" """
uri = '/status/sessions' uri = '/status/sessions'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -166,7 +99,6 @@ class PmsConnect(object):
""" """
uri = '/status/sessions/terminate?sessionId=%s&reason=%s' % (session_id, reason) uri = '/status/sessions/terminate?sessionId=%s&reason=%s' % (session_id, reason)
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -183,7 +115,6 @@ class PmsConnect(object):
""" """
uri = '/library/metadata/' + rating_key uri = '/library/metadata/' + rating_key
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -200,7 +131,6 @@ class PmsConnect(object):
""" """
uri = '/library/metadata/' + rating_key + '/children' uri = '/library/metadata/' + rating_key + '/children'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -217,7 +147,6 @@ class PmsConnect(object):
""" """
uri = '/library/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s' % (start, count) uri = '/library/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s' % (start, count)
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -234,7 +163,6 @@ class PmsConnect(object):
""" """
uri = '/library/sections/%s/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s' % (section_id, start, count) uri = '/library/sections/%s/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s' % (section_id, start, count)
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -251,7 +179,6 @@ class PmsConnect(object):
""" """
uri = '/library/metadata/' + rating_key + '/children' uri = '/library/metadata/' + rating_key + '/children'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -285,7 +212,6 @@ class PmsConnect(object):
""" """
uri = '/library/metadata/' + rating_key + '/allLeaves' uri = '/library/metadata/' + rating_key + '/allLeaves'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -301,7 +227,6 @@ class PmsConnect(object):
""" """
uri = '/servers' uri = '/servers'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -317,7 +242,6 @@ class PmsConnect(object):
""" """
uri = '/:/prefs' uri = '/:/prefs'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -333,7 +257,6 @@ class PmsConnect(object):
""" """
uri = '/identity' uri = '/identity'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -349,7 +272,6 @@ class PmsConnect(object):
""" """
uri = '/library/sections' uri = '/library/sections'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -368,7 +290,6 @@ class PmsConnect(object):
uri = '/library/sections/' + section_id + '/' + list_type + '?X-Plex-Container-Start=0' + count + sort_type + label_key uri = '/library/sections/' + section_id + '/' + list_type + '?X-Plex-Container-Start=0' + count + sort_type + label_key
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -384,7 +305,6 @@ class PmsConnect(object):
""" """
uri = '/library/sections/' + section_id + '/label' uri = '/library/sections/' + section_id + '/label'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -401,7 +321,6 @@ class PmsConnect(object):
""" """
uri = '/sync/items/' + sync_id uri = '/sync/items/' + sync_id
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -417,7 +336,6 @@ class PmsConnect(object):
""" """
uri = '/sync/transcodeQueue' uri = '/sync/transcodeQueue'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -433,7 +351,6 @@ class PmsConnect(object):
""" """
uri = '/hubs/search?query=' + urllib.quote(query.encode('utf8')) + '&limit=' + limit + '&includeCollections=1' uri = '/hubs/search?query=' + urllib.quote(query.encode('utf8')) + '&limit=' + limit + '&includeCollections=1'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -449,7 +366,6 @@ class PmsConnect(object):
""" """
uri = '/myplex/account' uri = '/myplex/account'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -465,7 +381,6 @@ class PmsConnect(object):
""" """
uri = '/myplex/refreshReachability' uri = '/myplex/refreshReachability'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='PUT') request_type='PUT')
return request return request
@ -480,7 +395,6 @@ class PmsConnect(object):
""" """
uri = '/updater/check?download=0' uri = '/updater/check?download=0'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='PUT', request_type='PUT',
output_format=output_format) output_format=output_format)
@ -496,7 +410,6 @@ class PmsConnect(object):
""" """
uri = '/updater/status' uri = '/updater/status'
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -515,7 +428,6 @@ class PmsConnect(object):
""" """
uri = '/hubs/home/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s&type=%s' % (start, count, type) uri = '/hubs/home/recentlyAdded?X-Plex-Container-Start=%s&X-Plex-Container-Size=%s&type=%s' % (start, count, type)
request = self.request_handler.make_request(uri=uri, request = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
output_format=output_format) output_format=output_format)
@ -2334,7 +2246,6 @@ class PmsConnect(object):
uri = '/photo/:/transcode?%s' % urllib.urlencode(params) uri = '/photo/:/transcode?%s' % urllib.urlencode(params)
result = self.request_handler.make_request(uri=uri, result = self.request_handler.make_request(uri=uri,
proto=self.protocol,
request_type='GET', request_type='GET',
return_type=True) return_type=True)

View file

@ -23,9 +23,67 @@ import datatables
import helpers import helpers
import logger import logger
import plextv import plextv
import pmsconnect
import session import session
def refresh_users():
logger.info(u"Tautulli Users :: Requesting users list refresh...")
result = plextv.PlexTV().get_full_users_list()
monitor_db = database.MonitorDatabase()
user_data = Users()
if result:
for item in result:
shared_libraries = ''
user_tokens = user_data.get_tokens(user_id=item['user_id'])
if user_tokens and user_tokens['server_token']:
pms_connect = pmsconnect.PmsConnect(token=user_tokens['server_token'])
library_details = pms_connect.get_server_children()
if library_details:
shared_libraries = ';'.join(d['section_id'] for d in library_details['libraries_list'])
else:
shared_libraries = ''
control_value_dict = {"user_id": item['user_id']}
new_value_dict = {"username": item['username'],
"thumb": item['thumb'],
"email": item['email'],
"is_home_user": item['is_home_user'],
"is_allow_sync": item['is_allow_sync'],
"is_restricted": item['is_restricted'],
"shared_libraries": shared_libraries,
"filter_all": item['filter_all'],
"filter_movies": item['filter_movies'],
"filter_tv": item['filter_tv'],
"filter_music": item['filter_music'],
"filter_photos": item['filter_photos']
}
# Check if we've set a custom avatar if so don't overwrite it.
if item['user_id']:
avatar_urls = monitor_db.select('SELECT thumb, custom_avatar_url '
'FROM users WHERE user_id = ?',
[item['user_id']])
if avatar_urls:
if not avatar_urls[0]['custom_avatar_url'] or \
avatar_urls[0]['custom_avatar_url'] == avatar_urls[0]['thumb']:
new_value_dict['custom_avatar_url'] = item['thumb']
else:
new_value_dict['custom_avatar_url'] = item['thumb']
monitor_db.upsert('users', new_value_dict, control_value_dict)
logger.info(u"Tautulli Users :: Users list refreshed.")
return True
else:
logger.warn(u"Tautulli Users :: Unable to refresh users list.")
return False
class Users(object): class Users(object):
def __init__(self): def __init__(self):
@ -360,7 +418,7 @@ class Users(object):
logger.warn(u"Tautulli Users :: Unable to retrieve user %s from database. Requesting user list refresh." logger.warn(u"Tautulli Users :: Unable to retrieve user %s from database. Requesting user list refresh."
% user_id if user_id else user) % user_id if user_id else user)
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet # Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
plextv.refresh_users() refresh_users()
user_details = get_user_details(user_id=user_id, user=user) user_details = get_user_details(user_id=user_id, user=user)

View file

@ -42,6 +42,7 @@ def start_thread():
def on_disconnect(): def on_disconnect():
activity_processor.ActivityProcessor().set_temp_stopped() activity_processor.ActivityProcessor().set_temp_stopped()
plexpy.initialize_scheduler()
def reconnect(): def reconnect():
@ -148,9 +149,8 @@ def run():
logger.info(u"Tautulli WebSocket :: Unable to get an internal response from the server, Plex server is down.") logger.info(u"Tautulli WebSocket :: Unable to get an internal response from the server, Plex server is down.")
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'}) plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'})
plexpy.PLEX_SERVER_UP = False plexpy.PLEX_SERVER_UP = False
on_disconnect()
plexpy.initialize_scheduler() on_disconnect()
logger.debug(u"Tautulli WebSocket :: Leaving thread.") logger.debug(u"Tautulli WebSocket :: Leaving thread.")

View file

@ -27,9 +27,8 @@ from hashing_passwords import check_hash
import plexpy import plexpy
import logger import logger
import plextv
from plexpy.database import MonitorDatabase from plexpy.database import MonitorDatabase
from plexpy.users import Users from plexpy.users import Users, refresh_users
from plexpy.plextv import PlexTV from plexpy.plextv import PlexTV
@ -72,7 +71,7 @@ def user_login(username=None, password=None):
if result: if result:
# Refresh the users list to make sure we have all the correct permissions. # Refresh the users list to make sure we have all the correct permissions.
plextv.refresh_users() users.refresh_users()
# Successful login # Successful login
return True return True
else: else:

View file

@ -16,10 +16,8 @@
import hashlib import hashlib
import json import json
import os import os
import random
import shutil import shutil
import threading import threading
import uuid
import cherrypy import cherrypy
from cherrypy.lib.static import serve_file, serve_download from cherrypy.lib.static import serve_file, serve_download
@ -119,7 +117,7 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi("get_server_list") @addtoapi("get_server_list")
def discover(self, token=None, include_cloud=True, **kwargs): def discover(self, token=None, include_cloud=True, all_servers=False, **kwargs):
""" Get all your servers that are published to Plex.tv. """ Get all your servers that are published to Plex.tv.
``` ```
@ -150,12 +148,14 @@ class WebInterface(object):
plexpy.CONFIG.write() plexpy.CONFIG.write()
include_cloud = not (include_cloud == 'false') include_cloud = not (include_cloud == 'false')
all_servers = all_servers == 'true'
plex_tv = plextv.PlexTV() plex_tv = plextv.PlexTV()
servers = plex_tv.discover(include_cloud=include_cloud) servers_list = plex_tv.discover(include_cloud=include_cloud,
all_servers=all_servers)
if servers: if servers_list:
return servers return servers_list
##### Home ##### ##### Home #####
@ -170,6 +170,7 @@ class WebInterface(object):
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT, "home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
"home_stats_recently_added_count": plexpy.CONFIG.HOME_STATS_RECENTLY_ADDED_COUNT, "home_stats_recently_added_count": plexpy.CONFIG.HOME_STATS_RECENTLY_ADDED_COUNT,
"pms_name": plexpy.CONFIG.PMS_NAME, "pms_name": plexpy.CONFIG.PMS_NAME,
"pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD,
"update_show_changelog": plexpy.CONFIG.UPDATE_SHOW_CHANGELOG "update_show_changelog": plexpy.CONFIG.UPDATE_SHOW_CHANGELOG
} }
return serve_template(templatename="index.html", title="Home", config=config) return serve_template(templatename="index.html", title="Home", config=config)
@ -452,7 +453,7 @@ class WebInterface(object):
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def refresh_libraries_list(self, **kwargs): def refresh_libraries_list(self, **kwargs):
""" Refresh the libraries list on it's own thread. """ """ Refresh the libraries list on it's own thread. """
threading.Thread(target=pmsconnect.refresh_libraries).start() threading.Thread(target=libraries.refresh_libraries).start()
logger.info(u"Manual libraries list refresh requested.") logger.info(u"Manual libraries list refresh requested.")
return True return True
@ -1074,7 +1075,7 @@ class WebInterface(object):
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def refresh_users_list(self, **kwargs): def refresh_users_list(self, **kwargs):
""" Refresh the users list on it's own thread. """ """ Refresh the users list on it's own thread. """
threading.Thread(target=plextv.refresh_users).start() threading.Thread(target=users.refresh_users).start()
logger.info(u"Manual users list refresh requested.") logger.info(u"Manual users list refresh requested.")
return True return True
@ -2559,6 +2560,8 @@ class WebInterface(object):
"pms_port": plexpy.CONFIG.PMS_PORT, "pms_port": plexpy.CONFIG.PMS_PORT,
"pms_token": plexpy.CONFIG.PMS_TOKEN, "pms_token": plexpy.CONFIG.PMS_TOKEN,
"pms_ssl": checked(plexpy.CONFIG.PMS_SSL), "pms_ssl": checked(plexpy.CONFIG.PMS_SSL),
"pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE),
"pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD,
"pms_url_manual": checked(plexpy.CONFIG.PMS_URL_MANUAL), "pms_url_manual": checked(plexpy.CONFIG.PMS_URL_MANUAL),
"pms_uuid": plexpy.CONFIG.PMS_UUID, "pms_uuid": plexpy.CONFIG.PMS_UUID,
"pms_web_url": plexpy.CONFIG.PMS_WEB_URL, "pms_web_url": plexpy.CONFIG.PMS_WEB_URL,
@ -2576,7 +2579,6 @@ class WebInterface(object):
"refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL, "refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL,
"refresh_users_on_startup": checked(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP), "refresh_users_on_startup": checked(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP),
"logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL, "logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL,
"pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE),
"notify_consecutive": checked(plexpy.CONFIG.NOTIFY_CONSECUTIVE), "notify_consecutive": checked(plexpy.CONFIG.NOTIFY_CONSECUTIVE),
"notify_upload_posters": checked(plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS), "notify_upload_posters": checked(plexpy.CONFIG.NOTIFY_UPLOAD_POSTERS),
"notify_recently_added_upgrade": checked(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_UPGRADE), "notify_recently_added_upgrade": checked(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_UPGRADE),
@ -2733,8 +2735,7 @@ class WebInterface(object):
# Get new server URLs for SSL communications and get new server friendly name # Get new server URLs for SSL communications and get new server friendly name
if server_changed: if server_changed:
plextv.get_real_pms_url() plextv.get_server_resources()
pmsconnect.get_server_friendly_name()
web_socket.reconnect() web_socket.reconnect()
# If first run, start websocket # If first run, start websocket
@ -2751,11 +2752,11 @@ class WebInterface(object):
# Refresh users table if our server IP changes. # Refresh users table if our server IP changes.
if refresh_libraries: if refresh_libraries:
threading.Thread(target=pmsconnect.refresh_libraries).start() threading.Thread(target=libraries.refresh_libraries).start()
# Refresh users table if our server IP changes. # Refresh users table if our server IP changes.
if refresh_users: if refresh_users:
threading.Thread(target=plextv.refresh_users).start() threading.Thread(target=users.refresh_users).start()
return {'result': 'success', 'message': 'Settings saved.'} return {'result': 'success', 'message': 'Settings saved.'}
@ -3425,16 +3426,15 @@ class WebInterface(object):
# Fallback to checking /identity endpoint is server is unpublished # Fallback to checking /identity endpoint is server is unpublished
# Cannot set SSL settings on the PMS if unpublished so 'http' is okay # Cannot set SSL settings on the PMS if unpublished so 'http' is okay
if not identifier: if not identifier:
request_handler = http_handler.HTTPHandler(host=hostname, scheme = 'https' if ssl else 'http'
port=port, url = '{scheme}://{hostname}:{port}'.format(scheme=scheme, hostname=hostname, port=port)
token=None)
uri = '/identity' uri = '/identity'
request_handler = http_handler.HTTPHandler(urls=url,
ssl_verify=False)
request = request_handler.make_request(uri=uri, request = request_handler.make_request(uri=uri,
proto='http',
request_type='GET', request_type='GET',
output_format='xml', output_format='xml')
no_token=True,
timeout=10)
if request: if request:
xml_head = request.getElementsByTagName('MediaContainer')[0] xml_head = request.getElementsByTagName('MediaContainer')[0]
identifier = xml_head.getAttribute('machineIdentifier') identifier = xml_head.getAttribute('machineIdentifier')