removed plextv / pms, added TODO's for reimplementing Jellyfin
This commit is contained in:
@@ -50,10 +50,7 @@
|
||||
<h3 style="line-height: 50px;">Welcome!</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="welcome-message">
|
||||
Thanks for taking the time to try out Tautulli. Hope you find it useful.
|
||||
</p>
|
||||
<p class="welcome-message">
|
||||
Tautulli requires a permanent internet connection to ensure a reliable experience.
|
||||
Thanks for taking the time to try out JellyPy. Hope you find it useful.
|
||||
</p>
|
||||
<p class="welcome-message">
|
||||
This wizard will help you get set up, to continue press Next.
|
||||
@@ -65,11 +62,11 @@
|
||||
<h3>Authentication</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
Please setup an admin username and password for Tautulli.
|
||||
Please setup an admin username and password for JellyPy.
|
||||
</p>
|
||||
</div>
|
||||
<div class="wizard-input-section">
|
||||
<label for="http_username">HTTP Username</label>
|
||||
<label for="http_username">Username</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<input type="text" class="form-control auth-settings" id="http_username" name="http_username" value="" size="30">
|
||||
@@ -77,7 +74,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-input-section">
|
||||
<label for="http_password">HTTP Password</label>
|
||||
<label for="http_password">Password</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-8">
|
||||
<input type="password" class="form-control auth-settings" id="http_password" name="http_password" value="" size="30" autocomplete="new-password">
|
||||
@@ -91,26 +88,14 @@
|
||||
</div>
|
||||
|
||||
<div class="wizard-card" data-cardname="card3">
|
||||
<h3>Plex Account</h3>
|
||||
<h3>Jellyfin</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
Tautulli requires a Plex.tv account. Click the button below to sign in on Plex.tv. You may need to allow popups in your browser.
|
||||
</p>
|
||||
</div>
|
||||
<input type="hidden" class="form-control" name="pms_token" id="pms_token" value="" data-validate="validatePMStoken">
|
||||
<a class="btn btn-dark" id="sign-in-plex" href="#" role="button">Sign In with Plex</a>
|
||||
<span style="margin-left: 10px; display: none;" id="pms-token-status"></span>
|
||||
</div>
|
||||
|
||||
<div class="wizard-card" data-cardname="card4">
|
||||
<h3>Plex Media Server</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
Select your Plex Media Server from the dropdown menu or enter an IP address or hostname.
|
||||
Select your Jellyfin Server from the dropdown menu or enter an IP address or hostname.
|
||||
</p>
|
||||
</div>
|
||||
<div class="wizard-input-section">
|
||||
<label for="pms_ip_selectize">Plex IP Address or Hostname</label>
|
||||
<label for="pms_ip_selectize">Jellyfin IP Address or Hostname</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<select class="form-control pms-settings selectize-pms-ip" id="pms_ip_selectize">
|
||||
@@ -130,7 +115,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-input-section">
|
||||
<label for="pms_port">Plex Port</label>
|
||||
<label for="pms_port">Jellyfin Port</label>
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<input type="text" class="form-control pms-settings" name="pms_port" id="pms_port" placeholder="32400" value="${config['pms_port']}" required>
|
||||
@@ -161,7 +146,7 @@
|
||||
<span style="margin-left: 10px; display: none;" id="pms-verify-status"></span>
|
||||
</div>
|
||||
|
||||
<div class="wizard-card" data-cardname="card5">
|
||||
<div class="wizard-card" data-cardname="card4">
|
||||
<h3>Activity Logging</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
@@ -186,7 +171,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-card" data-cardname="card6">
|
||||
<div class="wizard-card" data-cardname="card5">
|
||||
<h3>Notifications</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
@@ -199,7 +184,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wizard-card" data-cardname="card7">
|
||||
<div class="wizard-card" data-cardname="card6">
|
||||
<h3>Database Import</h3>
|
||||
<div class="wizard-input-section">
|
||||
<p class="help-block">
|
||||
|
@@ -47,7 +47,6 @@ from jellypy import newsletters
|
||||
from jellypy import newsletter_handler
|
||||
from jellypy import notification_handler
|
||||
from jellypy import notifiers
|
||||
from jellypy import plextv
|
||||
from jellypy import users
|
||||
from jellypy import versioncheck
|
||||
from jellypy import web_socket
|
||||
@@ -426,8 +425,9 @@ def initialize_scheduler():
|
||||
hours=backup_hours, minutes=0, seconds=0, args=(True, True))
|
||||
|
||||
if WS_CONNECTED and CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
|
||||
schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
|
||||
hours=12 * (not bool(CONFIG.PMS_URL_MANUAL)), minutes=0, seconds=0)
|
||||
# TODO: Jellyfin
|
||||
# schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
|
||||
# hours=12 * (not bool(CONFIG.PMS_URL_MANUAL)), minutes=0, seconds=0)
|
||||
|
||||
schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates',
|
||||
hours=pms_update_check_hours * bool(CONFIG.MONITOR_PMS_UPDATES), minutes=0, seconds=0)
|
||||
@@ -448,8 +448,9 @@ def initialize_scheduler():
|
||||
|
||||
else:
|
||||
# Cancel all jobs
|
||||
schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
|
||||
hours=0, minutes=0, seconds=0)
|
||||
# TODO: Jellyfin
|
||||
# schedule_job(plextv.get_server_resources, 'Refresh Plex server URLs',
|
||||
# hours=0, minutes=0, seconds=0)
|
||||
|
||||
schedule_job(activity_pinger.check_server_updates, 'Check for Plex updates',
|
||||
hours=0, minutes=0, seconds=0)
|
||||
@@ -532,7 +533,9 @@ def start():
|
||||
def startup_refresh():
|
||||
# Get the real PMS urls for SSL and remote access
|
||||
if CONFIG.PMS_TOKEN and CONFIG.PMS_IP and CONFIG.PMS_PORT:
|
||||
plextv.get_server_resources()
|
||||
pass
|
||||
# TODO: Jellyfin
|
||||
# plextv.get_server_resources()
|
||||
|
||||
# Connect server after server resource is refreshed
|
||||
if CONFIG.FIRST_RUN_COMPLETE:
|
||||
|
@@ -27,7 +27,6 @@ from jellypy import datafactory
|
||||
from jellypy import helpers
|
||||
from jellypy import logger
|
||||
from jellypy import notification_handler
|
||||
from jellypy import pmsconnect
|
||||
|
||||
ACTIVITY_SCHED = None
|
||||
|
||||
@@ -60,27 +59,29 @@ class ActivityHandler(object):
|
||||
|
||||
def get_metadata(self, skip_cache=False):
|
||||
cache_key = None if skip_cache else self.get_session_key()
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
metadata = pms_connect.get_metadata_details(rating_key=self.get_rating_key(), cache_key=cache_key)
|
||||
|
||||
if metadata:
|
||||
return metadata
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# metadata = pms_connect.get_metadata_details(rating_key=self.get_rating_key(), cache_key=cache_key)
|
||||
#
|
||||
# if metadata:
|
||||
# return metadata
|
||||
|
||||
return None
|
||||
|
||||
def get_live_session(self, skip_cache=False):
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
session_list = pms_connect.get_current_activity(skip_cache=skip_cache)
|
||||
|
||||
if session_list:
|
||||
for session in session_list['sessions']:
|
||||
if int(session['session_key']) == self.get_session_key():
|
||||
# Live sessions don't have rating keys in sessions
|
||||
# Get it from the websocket data
|
||||
if not session['rating_key']:
|
||||
session['rating_key'] = self.get_rating_key()
|
||||
session['rating_key_websocket'] = self.get_rating_key()
|
||||
return session
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# session_list = pms_connect.get_current_activity(skip_cache=skip_cache)
|
||||
#
|
||||
# if session_list:
|
||||
# for session in session_list['sessions']:
|
||||
# if int(session['session_key']) == self.get_session_key():
|
||||
# # Live sessions don't have rating keys in sessions
|
||||
# # Get it from the websocket data
|
||||
# if not session['rating_key']:
|
||||
# session['rating_key'] = self.get_rating_key()
|
||||
# session['rating_key_websocket'] = self.get_rating_key()
|
||||
# return session
|
||||
|
||||
return None
|
||||
|
||||
@@ -390,11 +391,12 @@ class TimelineHandler(object):
|
||||
return None
|
||||
|
||||
def get_metadata(self):
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
metadata = pms_connect.get_metadata_details(self.get_rating_key())
|
||||
|
||||
if metadata:
|
||||
return metadata
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# metadata = pms_connect.get_metadata_details(self.get_rating_key())
|
||||
#
|
||||
# if metadata:
|
||||
# return metadata
|
||||
|
||||
return None
|
||||
|
||||
@@ -522,9 +524,11 @@ class ReachabilityHandler(object):
|
||||
return False
|
||||
|
||||
def remote_access_enabled(self):
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
pref = pms_connect.get_server_pref(pref='PublishServerOnPlexOnlineKey')
|
||||
return helpers.bool_true(pref)
|
||||
return False
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# pref = pms_connect.get_server_pref(pref='PublishServerOnPlexOnlineKey')
|
||||
# return helpers.bool_true(pref)
|
||||
|
||||
def on_down(self, server_response):
|
||||
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_extdown', 'remote_access_info': server_response})
|
||||
@@ -541,39 +545,40 @@ class ReachabilityHandler(object):
|
||||
if self.is_reachable() and jellypy.PLEX_REMOTE_ACCESS_UP:
|
||||
return
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
server_response = pms_connect.get_server_response()
|
||||
|
||||
if server_response:
|
||||
# Waiting for port mapping
|
||||
if server_response['mapping_state'] == 'waiting':
|
||||
logger.warn("Tautulli ReachabilityHandler :: Remote access waiting for port mapping.")
|
||||
|
||||
elif jellypy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']:
|
||||
logger.warn("Tautulli ReachabilityHandler :: Remote access failed: %s" % server_response['reason'])
|
||||
logger.info("Tautulli ReachabilityHandler :: Plex remote access is down.")
|
||||
|
||||
jellypy.PLEX_REMOTE_ACCESS_UP = False
|
||||
|
||||
if not ACTIVITY_SCHED.get_job('on_extdown'):
|
||||
logger.debug("Tautulli ReachabilityHandler :: Schedule remote access down callback in %d seconds.",
|
||||
jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
|
||||
schedule_callback('on_extdown', func=self.on_down, args=[server_response],
|
||||
seconds=jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
|
||||
|
||||
elif jellypy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']:
|
||||
logger.info("Tautulli ReachabilityHandler :: Plex remote access is back up.")
|
||||
|
||||
jellypy.PLEX_REMOTE_ACCESS_UP = True
|
||||
|
||||
if ACTIVITY_SCHED.get_job('on_extdown'):
|
||||
logger.debug("Tautulli ReachabilityHandler :: Cancelling scheduled remote access down callback.")
|
||||
schedule_callback('on_extdown', remove_job=True)
|
||||
else:
|
||||
self.on_up(server_response)
|
||||
|
||||
elif jellypy.PLEX_REMOTE_ACCESS_UP is None:
|
||||
jellypy.PLEX_REMOTE_ACCESS_UP = self.is_reachable()
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# server_response = pms_connect.get_server_response()
|
||||
#
|
||||
# if server_response:
|
||||
# # Waiting for port mapping
|
||||
# if server_response['mapping_state'] == 'waiting':
|
||||
# logger.warn("Tautulli ReachabilityHandler :: Remote access waiting for port mapping.")
|
||||
#
|
||||
# elif jellypy.PLEX_REMOTE_ACCESS_UP is not False and server_response['reason']:
|
||||
# logger.warn("Tautulli ReachabilityHandler :: Remote access failed: %s" % server_response['reason'])
|
||||
# logger.info("Tautulli ReachabilityHandler :: Plex remote access is down.")
|
||||
#
|
||||
# jellypy.PLEX_REMOTE_ACCESS_UP = False
|
||||
#
|
||||
# if not ACTIVITY_SCHED.get_job('on_extdown'):
|
||||
# logger.debug("Tautulli ReachabilityHandler :: Schedule remote access down callback in %d seconds.",
|
||||
# jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
|
||||
# schedule_callback('on_extdown', func=self.on_down, args=[server_response],
|
||||
# seconds=jellypy.CONFIG.NOTIFY_REMOTE_ACCESS_THRESHOLD)
|
||||
#
|
||||
# elif jellypy.PLEX_REMOTE_ACCESS_UP is False and not server_response['reason']:
|
||||
# logger.info("Tautulli ReachabilityHandler :: Plex remote access is back up.")
|
||||
#
|
||||
# jellypy.PLEX_REMOTE_ACCESS_UP = True
|
||||
#
|
||||
# if ACTIVITY_SCHED.get_job('on_extdown'):
|
||||
# logger.debug("Tautulli ReachabilityHandler :: Cancelling scheduled remote access down callback.")
|
||||
# schedule_callback('on_extdown', remove_job=True)
|
||||
# else:
|
||||
# self.on_up(server_response)
|
||||
#
|
||||
# elif jellypy.PLEX_REMOTE_ACCESS_UP is None:
|
||||
# jellypy.PLEX_REMOTE_ACCESS_UP = self.is_reachable()
|
||||
|
||||
|
||||
def del_keys(key):
|
||||
@@ -670,41 +675,42 @@ def clear_recently_added_queue(rating_key, title):
|
||||
|
||||
def on_created(rating_key, **kwargs):
|
||||
logger.debug("Tautulli TimelineHandler :: Library item %s added to Plex." % str(rating_key))
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
metadata = pms_connect.get_metadata_details(rating_key)
|
||||
|
||||
if metadata:
|
||||
notify = True
|
||||
# now = helpers.timestamp()
|
||||
#
|
||||
# if helpers.cast_to_int(metadata['added_at']) < now - 86400: # Updated more than 24 hours ago
|
||||
# logger.debug("Tautulli TimelineHandler :: Library item %s added more than 24 hours ago. Not notifying."
|
||||
# % str(rating_key))
|
||||
# notify = False
|
||||
|
||||
data_factory = datafactory.DataFactory()
|
||||
if 'child_keys' not in kwargs:
|
||||
if data_factory.get_recently_added_item(rating_key):
|
||||
logger.debug("Tautulli TimelineHandler :: Library item %s added already. Not notifying again."
|
||||
% str(rating_key))
|
||||
notify = False
|
||||
|
||||
if notify:
|
||||
data = {'timeline_data': metadata, 'notify_action': 'on_created'}
|
||||
data.update(kwargs)
|
||||
jellypy.NOTIFY_QUEUE.put(data)
|
||||
|
||||
all_keys = [rating_key]
|
||||
if 'child_keys' in kwargs:
|
||||
all_keys.extend(kwargs['child_keys'])
|
||||
|
||||
for key in all_keys:
|
||||
data_factory.set_recently_added_item(key)
|
||||
|
||||
logger.debug("Added %s items to the recently_added database table." % str(len(all_keys)))
|
||||
|
||||
else:
|
||||
logger.error("Tautulli TimelineHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# metadata = pms_connect.get_metadata_details(rating_key)
|
||||
#
|
||||
# if metadata:
|
||||
# notify = True
|
||||
# # now = helpers.timestamp()
|
||||
# #
|
||||
# # if helpers.cast_to_int(metadata['added_at']) < now - 86400: # Updated more than 24 hours ago
|
||||
# # logger.debug("Tautulli TimelineHandler :: Library item %s added more than 24 hours ago. Not notifying."
|
||||
# # % str(rating_key))
|
||||
# # notify = False
|
||||
#
|
||||
# data_factory = datafactory.DataFactory()
|
||||
# if 'child_keys' not in kwargs:
|
||||
# if data_factory.get_recently_added_item(rating_key):
|
||||
# logger.debug("Tautulli TimelineHandler :: Library item %s added already. Not notifying again."
|
||||
# % str(rating_key))
|
||||
# notify = False
|
||||
#
|
||||
# if notify:
|
||||
# data = {'timeline_data': metadata, 'notify_action': 'on_created'}
|
||||
# data.update(kwargs)
|
||||
# jellypy.NOTIFY_QUEUE.put(data)
|
||||
#
|
||||
# all_keys = [rating_key]
|
||||
# if 'child_keys' in kwargs:
|
||||
# all_keys.extend(kwargs['child_keys'])
|
||||
#
|
||||
# for key in all_keys:
|
||||
# data_factory.set_recently_added_item(key)
|
||||
#
|
||||
# logger.debug("Added %s items to the recently_added database table." % str(len(all_keys)))
|
||||
#
|
||||
# else:
|
||||
# logger.error("Tautulli TimelineHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
||||
|
||||
|
||||
def delete_metadata_cache(session_key):
|
||||
|
@@ -23,8 +23,6 @@ from jellypy import database
|
||||
from jellypy import helpers
|
||||
from jellypy import logger
|
||||
from jellypy import notification_handler
|
||||
from jellypy import plextv
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import web_socket
|
||||
|
||||
monitor_lock = threading.Lock()
|
||||
@@ -43,8 +41,10 @@ def check_active_sessions(ws_request=False):
|
||||
for stream in db_streams:
|
||||
activity_handler.delete_metadata_cache(stream['session_key'])
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
session_list = pms_connect.get_current_activity()
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# session_list = pms_connect.get_current_activity()
|
||||
session_list = None
|
||||
|
||||
logger.debug("Tautulli Monitor :: Checking for active streams.")
|
||||
|
||||
@@ -229,8 +229,10 @@ def connect_server(log=True, startup=False):
|
||||
if log:
|
||||
logger.info("Tautulli Monitor :: Checking for Plex Cloud server status...")
|
||||
|
||||
plex_tv = plextv.PlexTV()
|
||||
status = plex_tv.get_cloud_server_status()
|
||||
# TODO: Jellyfin
|
||||
# plex_tv = plextv.PlexTV()
|
||||
# status = plex_tv.get_cloud_server_status()
|
||||
status = None
|
||||
|
||||
if status is True:
|
||||
logger.info("Tautulli Monitor :: Plex Cloud server is active.")
|
||||
@@ -261,16 +263,17 @@ def check_server_updates():
|
||||
with monitor_lock:
|
||||
logger.info("Tautulli Monitor :: Checking for PMS updates...")
|
||||
|
||||
plex_tv = plextv.PlexTV()
|
||||
download_info = plex_tv.get_plex_downloads()
|
||||
|
||||
if download_info:
|
||||
logger.info("Tautulli Monitor :: Current PMS version: %s", jellypy.CONFIG.PMS_VERSION)
|
||||
|
||||
if download_info['update_available']:
|
||||
logger.info("Tautulli Monitor :: PMS update available version: %s", download_info['version'])
|
||||
|
||||
jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
|
||||
|
||||
else:
|
||||
logger.info("Tautulli Monitor :: No PMS update available.")
|
||||
# TODO: Jellyfin
|
||||
# plex_tv = plextv.PlexTV()
|
||||
# download_info = plex_tv.get_plex_downloads()
|
||||
#
|
||||
# if download_info:
|
||||
# logger.info("Tautulli Monitor :: Current PMS version: %s", jellypy.CONFIG.PMS_VERSION)
|
||||
#
|
||||
# if download_info['update_available']:
|
||||
# logger.info("Tautulli Monitor :: PMS update available version: %s", download_info['version'])
|
||||
#
|
||||
# jellypy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
|
||||
#
|
||||
# else:
|
||||
# logger.info("Tautulli Monitor :: No PMS update available.")
|
||||
|
@@ -22,7 +22,6 @@ from jellypy import database
|
||||
from jellypy import helpers
|
||||
from jellypy import libraries
|
||||
from jellypy import logger
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import users
|
||||
|
||||
|
||||
@@ -260,19 +259,20 @@ class ActivityProcessor(object):
|
||||
if not is_import:
|
||||
logger.debug(
|
||||
"Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
if session['live']:
|
||||
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']),
|
||||
cache_key=session['session_key'],
|
||||
return_cache=True)
|
||||
else:
|
||||
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
||||
if not metadata:
|
||||
return False
|
||||
else:
|
||||
media_info = {}
|
||||
if 'media_info' in metadata and len(metadata['media_info']) > 0:
|
||||
media_info = metadata['media_info'][0]
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# if session['live']:
|
||||
# metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']),
|
||||
# cache_key=session['session_key'],
|
||||
# return_cache=True)
|
||||
# else:
|
||||
# metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
||||
# if not metadata:
|
||||
# return False
|
||||
# else:
|
||||
# media_info = {}
|
||||
# if 'media_info' in metadata and len(metadata['media_info']) > 0:
|
||||
# media_info = metadata['media_info'][0]
|
||||
else:
|
||||
metadata = import_metadata
|
||||
## TODO: Fix media info from imports. Temporary media info from import session.
|
||||
|
@@ -40,7 +40,6 @@ from jellypy import notification_handler
|
||||
from jellypy import notifiers
|
||||
from jellypy import newsletter_handler
|
||||
from jellypy import newsletters
|
||||
from jellypy import plextv
|
||||
from jellypy import users
|
||||
from jellypy.password import check_hash
|
||||
|
||||
@@ -451,11 +450,13 @@ class API2(object):
|
||||
|
||||
mobile_app.set_temp_device_token(True)
|
||||
|
||||
plex_server = plextv.get_server_resources(return_info=True)
|
||||
# TODO: Jellyfin
|
||||
# plex_server = plextv.get_server_resources(return_info=True)
|
||||
tautulli = jellypy.get_tautulli_info()
|
||||
|
||||
data = {"server_id": jellypy.CONFIG.PMS_UUID}
|
||||
data.update(plex_server)
|
||||
# TODO: Jellyfin
|
||||
# data.update(plex_server)
|
||||
data.update(tautulli)
|
||||
|
||||
return data
|
||||
|
@@ -25,7 +25,6 @@ from jellypy import database
|
||||
from jellypy import datatables
|
||||
from jellypy import helpers
|
||||
from jellypy import logger
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import session
|
||||
|
||||
|
||||
@@ -1589,7 +1588,7 @@ class DataFactory(object):
|
||||
return key_list
|
||||
|
||||
def update_metadata(self, old_key_list='', new_key_list='', media_type=''):
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
# TODO: pms_connect = pmsconnect.PmsConnect()
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
# function to map rating keys pairs
|
||||
@@ -1608,37 +1607,38 @@ class DataFactory(object):
|
||||
if old_key_list and new_key_list:
|
||||
mapping = get_pairs(old_key_list, new_key_list)
|
||||
|
||||
if mapping:
|
||||
logger.info("Tautulli DataFactory :: Updating metadata in the database.")
|
||||
for old_key, new_key in mapping.items():
|
||||
metadata = pms_connect.get_metadata_details(new_key)
|
||||
|
||||
if metadata:
|
||||
if metadata['media_type'] == 'show' or metadata['media_type'] == 'artist':
|
||||
# check grandparent_rating_key (2 tables)
|
||||
monitor_db.action(
|
||||
'UPDATE session_history SET grandparent_rating_key = ? WHERE grandparent_rating_key = ?',
|
||||
[new_key, old_key])
|
||||
monitor_db.action(
|
||||
'UPDATE session_history_metadata SET grandparent_rating_key = ? WHERE grandparent_rating_key = ?',
|
||||
[new_key, old_key])
|
||||
elif metadata['media_type'] == 'season' or metadata['media_type'] == 'album':
|
||||
# check parent_rating_key (2 tables)
|
||||
monitor_db.action(
|
||||
'UPDATE session_history SET parent_rating_key = ? WHERE parent_rating_key = ?',
|
||||
[new_key, old_key])
|
||||
monitor_db.action(
|
||||
'UPDATE session_history_metadata SET parent_rating_key = ? WHERE parent_rating_key = ?',
|
||||
[new_key, old_key])
|
||||
else:
|
||||
# check rating_key (2 tables)
|
||||
monitor_db.action('UPDATE session_history SET rating_key = ? WHERE rating_key = ?',
|
||||
[new_key, old_key])
|
||||
monitor_db.action('UPDATE session_history_media_info SET rating_key = ? WHERE rating_key = ?',
|
||||
[new_key, old_key])
|
||||
|
||||
# update session_history_metadata table
|
||||
self.update_metadata_details(old_key, new_key, metadata)
|
||||
# TODO: Jellyfin
|
||||
# if mapping:
|
||||
# logger.info("Tautulli DataFactory :: Updating metadata in the database.")
|
||||
# for old_key, new_key in mapping.items():
|
||||
# metadata = pms_connect.get_metadata_details(new_key)
|
||||
#
|
||||
# if metadata:
|
||||
# if metadata['media_type'] == 'show' or metadata['media_type'] == 'artist':
|
||||
# # check grandparent_rating_key (2 tables)
|
||||
# monitor_db.action(
|
||||
# 'UPDATE session_history SET grandparent_rating_key = ? WHERE grandparent_rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
# monitor_db.action(
|
||||
# 'UPDATE session_history_metadata SET grandparent_rating_key = ? WHERE grandparent_rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
# elif metadata['media_type'] == 'season' or metadata['media_type'] == 'album':
|
||||
# # check parent_rating_key (2 tables)
|
||||
# monitor_db.action(
|
||||
# 'UPDATE session_history SET parent_rating_key = ? WHERE parent_rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
# monitor_db.action(
|
||||
# 'UPDATE session_history_metadata SET parent_rating_key = ? WHERE parent_rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
# else:
|
||||
# # check rating_key (2 tables)
|
||||
# monitor_db.action('UPDATE session_history SET rating_key = ? WHERE rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
# monitor_db.action('UPDATE session_history_media_info SET rating_key = ? WHERE rating_key = ?',
|
||||
# [new_key, old_key])
|
||||
#
|
||||
# # update session_history_metadata table
|
||||
# self.update_metadata_details(old_key, new_key, metadata)
|
||||
|
||||
return 'Updated metadata in database.'
|
||||
else:
|
||||
@@ -1886,23 +1886,24 @@ class DataFactory(object):
|
||||
def set_recently_added_item(self, rating_key=''):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
metadata = pms_connect.get_metadata_details(rating_key)
|
||||
|
||||
keys = {'rating_key': metadata['rating_key']}
|
||||
|
||||
values = {'added_at': metadata['added_at'],
|
||||
'section_id': metadata['section_id'],
|
||||
'parent_rating_key': metadata['parent_rating_key'],
|
||||
'grandparent_rating_key': metadata['grandparent_rating_key'],
|
||||
'media_type': metadata['media_type'],
|
||||
'media_info': json.dumps(metadata['media_info'])
|
||||
}
|
||||
|
||||
try:
|
||||
monitor_db.upsert(table_name='recently_added', key_dict=keys, value_dict=values)
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli DataFactory :: Unable to execute database query for set_recently_added_item: %s." % e)
|
||||
return False
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# metadata = pms_connect.get_metadata_details(rating_key)
|
||||
#
|
||||
# keys = {'rating_key': metadata['rating_key']}
|
||||
#
|
||||
# values = {'added_at': metadata['added_at'],
|
||||
# 'section_id': metadata['section_id'],
|
||||
# 'parent_rating_key': metadata['parent_rating_key'],
|
||||
# 'grandparent_rating_key': metadata['grandparent_rating_key'],
|
||||
# 'media_type': metadata['media_type'],
|
||||
# 'media_info': json.dumps(metadata['media_info'])
|
||||
# }
|
||||
#
|
||||
# try:
|
||||
# monitor_db.upsert(table_name='recently_added', key_dict=keys, value_dict=values)
|
||||
# except Exception as e:
|
||||
# logger.warn("Tautulli DataFactory :: Unable to execute database query for set_recently_added_item: %s." % e)
|
||||
# return False
|
||||
|
||||
return True
|
||||
|
@@ -25,8 +25,6 @@ from jellypy import database
|
||||
from jellypy import datatables
|
||||
from jellypy import helpers
|
||||
from jellypy import logger
|
||||
from jellypy import plextv
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import session
|
||||
from jellypy import users
|
||||
from jellypy.jellyfin import Jellyfin
|
||||
@@ -1159,7 +1157,7 @@ class Libraries(object):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
# Refresh the PMS_URL to make sure the server_id is updated
|
||||
plextv.get_server_resources()
|
||||
# TODO: plextv.get_server_resources()
|
||||
|
||||
server_id = jellypy.CONFIG.PMS_IDENTIFIER
|
||||
|
||||
|
@@ -32,7 +32,6 @@ from jellypy import helpers
|
||||
from jellypy import libraries
|
||||
from jellypy import logger
|
||||
from jellypy import newsletter_handler
|
||||
from jellypy import pmsconnect
|
||||
from jellypy.notifiers import send_notification, EMAIL
|
||||
|
||||
AGENT_IDS = {
|
||||
@@ -693,7 +692,8 @@ class RecentlyAdded(Newsletter):
|
||||
def _get_recently_added(self, media_type=None):
|
||||
from jellypy.notification_handler import format_group_index
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
|
||||
recently_added = []
|
||||
done = False
|
||||
|
@@ -39,7 +39,6 @@ from jellypy import datafactory
|
||||
from jellypy import logger
|
||||
from jellypy import helpers
|
||||
from jellypy import notifiers
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import request
|
||||
from jellypy.newsletter_handler import notify as notify_newsletter
|
||||
|
||||
@@ -164,18 +163,20 @@ def notify_conditions(notify_action=None, stream_data=None, timeline_data=None):
|
||||
# return False
|
||||
|
||||
if notify_action == 'on_concurrent':
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
result = pms_connect.get_current_activity()
|
||||
|
||||
user_sessions = []
|
||||
if result:
|
||||
user_sessions = [s for s in result['sessions'] if s['user_id'] == stream_data['user_id']]
|
||||
|
||||
if jellypy.CONFIG.NOTIFY_CONCURRENT_BY_IP:
|
||||
evaluated = len(
|
||||
Counter(s['ip_address'] for s in user_sessions)) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
|
||||
else:
|
||||
evaluated = len(user_sessions) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
|
||||
pass
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# result = pms_connect.get_current_activity()
|
||||
#
|
||||
# user_sessions = []
|
||||
# if result:
|
||||
# user_sessions = [s for s in result['sessions'] if s['user_id'] == stream_data['user_id']]
|
||||
#
|
||||
# if jellypy.CONFIG.NOTIFY_CONCURRENT_BY_IP:
|
||||
# evaluated = len(
|
||||
# Counter(s['ip_address'] for s in user_sessions)) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
|
||||
# else:
|
||||
# evaluated = len(user_sessions) >= jellypy.CONFIG.NOTIFY_CONCURRENT_THRESHOLD
|
||||
|
||||
elif notify_action == 'on_newdevice':
|
||||
data_factory = datafactory.DataFactory()
|
||||
@@ -536,10 +537,11 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||
notify_params.update(media_part_info)
|
||||
|
||||
child_metadata = grandchild_metadata = []
|
||||
for key in kwargs.pop('child_keys', []):
|
||||
child_metadata.append(pmsconnect.PmsConnect().get_metadata_details(rating_key=key))
|
||||
for key in kwargs.pop('grandchild_keys', []):
|
||||
grandchild_metadata.append(pmsconnect.PmsConnect().get_metadata_details(rating_key=key))
|
||||
# TODO: Jellyfin
|
||||
# for key in kwargs.pop('child_keys', []):
|
||||
# child_metadata.append(pmsconnect.PmsConnect().get_metadata_details(rating_key=key))
|
||||
# for key in kwargs.pop('grandchild_keys', []):
|
||||
# grandchild_metadata.append(pmsconnect.PmsConnect().get_metadata_details(rating_key=key))
|
||||
|
||||
# Session values
|
||||
session = session or {}
|
||||
@@ -1097,7 +1099,8 @@ def build_server_notify_params(notify_action=None, **kwargs):
|
||||
date_format = jellypy.CONFIG.DATE_FORMAT.replace('Do', '')
|
||||
time_format = jellypy.CONFIG.TIME_FORMAT.replace('Do', '')
|
||||
|
||||
update_channel = pmsconnect.PmsConnect().get_server_update_channel()
|
||||
# TODO: Jellyfin
|
||||
# update_channel = pmsconnect.PmsConnect().get_server_update_channel()
|
||||
|
||||
pms_download_info = defaultdict(str, kwargs.pop('pms_download_info', {}))
|
||||
plexpy_download_info = defaultdict(str, kwargs.pop('plexpy_download_info', {}))
|
||||
@@ -1146,7 +1149,8 @@ def build_server_notify_params(notify_action=None, **kwargs):
|
||||
'update_url': pms_download_info['download_url'],
|
||||
'update_release_date': arrow.get(pms_download_info['release_date']).format(date_format)
|
||||
if pms_download_info['release_date'] else '',
|
||||
'update_channel': 'Beta' if update_channel == 'beta' else 'Public',
|
||||
# TODO: Jellyfin
|
||||
# 'update_channel': 'Beta' if update_channel == 'beta' else 'Public',
|
||||
'update_platform': pms_download_info['platform'],
|
||||
'update_distro': pms_download_info['distro'],
|
||||
'update_distro_build': pms_download_info['build'],
|
||||
@@ -1410,32 +1414,34 @@ def get_img_info(img=None, rating_key=None, title='', width=1000, height=1500,
|
||||
img_info = database_img_info[0]
|
||||
|
||||
elif not database_img_info and img:
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
result = pms_connect.get_image(refresh=True, **image_info)
|
||||
|
||||
if result and result[0]:
|
||||
img_url = delete_hash = ''
|
||||
|
||||
if service == 'imgur':
|
||||
img_url, delete_hash = helpers.upload_to_imgur(img_data=result[0],
|
||||
img_title=title,
|
||||
rating_key=rating_key,
|
||||
fallback=fallback)
|
||||
elif service == 'cloudinary':
|
||||
img_url = helpers.upload_to_cloudinary(img_data=result[0],
|
||||
img_title=title,
|
||||
rating_key=rating_key,
|
||||
fallback=fallback)
|
||||
|
||||
if img_url:
|
||||
img_hash = set_hash_image_info(**image_info)
|
||||
data_factory.set_img_info(img_hash=img_hash,
|
||||
img_title=title,
|
||||
img_url=img_url,
|
||||
delete_hash=delete_hash,
|
||||
service=service)
|
||||
|
||||
img_info = {'img_title': title, 'img_url': img_url}
|
||||
pass
|
||||
# TODO: Jellyfin
|
||||
# pms_connect = pmsconnect.PmsConnect()
|
||||
# result = pms_connect.get_image(refresh=True, **image_info)
|
||||
#
|
||||
# if result and result[0]:
|
||||
# img_url = delete_hash = ''
|
||||
#
|
||||
# if service == 'imgur':
|
||||
# img_url, delete_hash = helpers.upload_to_imgur(img_data=result[0],
|
||||
# img_title=title,
|
||||
# rating_key=rating_key,
|
||||
# fallback=fallback)
|
||||
# elif service == 'cloudinary':
|
||||
# img_url = helpers.upload_to_cloudinary(img_data=result[0],
|
||||
# img_title=title,
|
||||
# rating_key=rating_key,
|
||||
# fallback=fallback)
|
||||
#
|
||||
# if img_url:
|
||||
# img_hash = set_hash_image_info(**image_info)
|
||||
# data_factory.set_img_info(img_hash=img_hash,
|
||||
# img_title=title,
|
||||
# img_url=img_url,
|
||||
# delete_hash=delete_hash,
|
||||
# service=service)
|
||||
#
|
||||
# img_info = {'img_title': title, 'img_url': img_url}
|
||||
|
||||
if img_info['img_url'] and service == 'cloudinary':
|
||||
# Transform image using Cloudinary
|
||||
|
@@ -61,7 +61,6 @@ from jellypy import database
|
||||
from jellypy import helpers
|
||||
from jellypy import logger
|
||||
from jellypy import mobile_app
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import request
|
||||
from jellypy import users
|
||||
|
||||
@@ -1517,29 +1516,30 @@ class GROUPME(Notifier):
|
||||
if self.config['incl_poster'] and kwargs.get('parameters'):
|
||||
pretty_metadata = PrettyMetadata(kwargs.get('parameters'))
|
||||
|
||||
# Retrieve the poster from Plex
|
||||
result = pmsconnect.PmsConnect().get_image(img=pretty_metadata.parameters.get('poster_thumb', ''))
|
||||
if result and result[0]:
|
||||
poster_content = result[0]
|
||||
else:
|
||||
poster_content = ''
|
||||
logger.error("Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME))
|
||||
|
||||
if poster_content:
|
||||
headers = {'X-Access-Token': self.config['access_token'],
|
||||
'Content-Type': 'image/png'}
|
||||
|
||||
r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content)
|
||||
|
||||
if r.status_code == 200:
|
||||
logger.info("Tautulli Notifiers :: {name} poster sent.".format(name=self.NAME))
|
||||
r_content = r.json()
|
||||
data['attachments'] = [{'type': 'image',
|
||||
'url': r_content['payload']['picture_url']}]
|
||||
else:
|
||||
logger.error("Tautulli Notifiers :: {name} poster failed: "
|
||||
"[{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||
logger.debug("Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||
# TODO: Jellyfin
|
||||
# # Retrieve the poster from Plex
|
||||
# result = pmsconnect.PmsConnect().get_image(img=pretty_metadata.parameters.get('poster_thumb', ''))
|
||||
# if result and result[0]:
|
||||
# poster_content = result[0]
|
||||
# else:
|
||||
# poster_content = ''
|
||||
# logger.error("Tautulli Notifiers :: Unable to retrieve image for {name}.".format(name=self.NAME))
|
||||
#
|
||||
# if poster_content:
|
||||
# headers = {'X-Access-Token': self.config['access_token'],
|
||||
# 'Content-Type': 'image/png'}
|
||||
#
|
||||
# r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content)
|
||||
#
|
||||
# if r.status_code == 200:
|
||||
# logger.info("Tautulli Notifiers :: {name} poster sent.".format(name=self.NAME))
|
||||
# r_content = r.json()
|
||||
# data['attachments'] = [{'type': 'image',
|
||||
# 'url': r_content['payload']['picture_url']}]
|
||||
# else:
|
||||
# logger.error("Tautulli Notifiers :: {name} poster failed: "
|
||||
# "[{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||
# logger.debug("Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||
|
||||
return self.make_request('https://api.groupme.com/v3/bots/post', json=data)
|
||||
|
||||
|
@@ -1,978 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This file is part of Tautulli.
|
||||
#
|
||||
# Tautulli 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.
|
||||
#
|
||||
# Tautulli 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 Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import json
|
||||
|
||||
import jellypy
|
||||
|
||||
from jellypy import common
|
||||
from jellypy import helpers
|
||||
from jellypy import http_handler
|
||||
from jellypy import logger
|
||||
from jellypy import users
|
||||
from jellypy import pmsconnect
|
||||
from jellypy import session
|
||||
|
||||
|
||||
def get_server_resources(return_presence=False, return_server=False, return_info=False, **kwargs):
|
||||
if not return_presence and not return_info:
|
||||
logger.info("Tautulli PlexTV :: Requesting resources for server...")
|
||||
|
||||
server = {'pms_name': jellypy.CONFIG.PMS_NAME,
|
||||
'pms_version': jellypy.CONFIG.PMS_VERSION,
|
||||
'pms_platform': jellypy.CONFIG.PMS_PLATFORM,
|
||||
'pms_ip': jellypy.CONFIG.PMS_IP,
|
||||
'pms_port': jellypy.CONFIG.PMS_PORT,
|
||||
'pms_ssl': jellypy.CONFIG.PMS_SSL,
|
||||
'pms_is_remote': jellypy.CONFIG.PMS_IS_REMOTE,
|
||||
'pms_is_cloud': jellypy.CONFIG.PMS_IS_CLOUD,
|
||||
'pms_url': jellypy.CONFIG.PMS_URL,
|
||||
'pms_url_manual': jellypy.CONFIG.PMS_URL_MANUAL,
|
||||
'pms_identifier': jellypy.CONFIG.PMS_IDENTIFIER,
|
||||
'pms_plexpass': jellypy.CONFIG.PMS_PLEXPASS
|
||||
}
|
||||
|
||||
if return_info:
|
||||
return server
|
||||
|
||||
if kwargs:
|
||||
server.update(kwargs)
|
||||
for k in ['pms_ssl', 'pms_is_remote', 'pms_is_cloud', 'pms_url_manual']:
|
||||
server[k] = int(server[k])
|
||||
|
||||
if server['pms_url_manual'] and server['pms_ssl'] or server['pms_is_cloud']:
|
||||
scheme = 'https'
|
||||
else:
|
||||
scheme = 'http'
|
||||
|
||||
fallback_url = '{scheme}://{hostname}:{port}'.format(scheme=scheme,
|
||||
hostname=server['pms_ip'],
|
||||
port=server['pms_port'])
|
||||
|
||||
plex_tv = PlexTV()
|
||||
result = plex_tv.get_server_connections(pms_identifier=server['pms_identifier'],
|
||||
pms_ip=server['pms_ip'],
|
||||
pms_port=server['pms_port'],
|
||||
include_https=server['pms_ssl'])
|
||||
|
||||
if result:
|
||||
connections = result.pop('connections', [])
|
||||
server.update(result)
|
||||
presence = server.pop('pms_presence', 0)
|
||||
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
|
||||
if not server['pms_url_manual'] and server['pms_ssl']:
|
||||
if connections:
|
||||
if server['pms_is_remote']:
|
||||
# Get all remote connections
|
||||
conns = [c for c in connections if
|
||||
c['local'] == '0' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])]
|
||||
else:
|
||||
# Get all local connections
|
||||
conns = [c for c in connections if
|
||||
c['local'] == '1' and ('plex.direct' in c['uri'] or 'plex.service' in c['uri'])]
|
||||
|
||||
if conns:
|
||||
# Get connection with matching address, otherwise return first connection
|
||||
conn = next((c for c in conns if c['address'] == server['pms_ip']
|
||||
and c['port'] == str(server['pms_port'])), conns[0])
|
||||
server['pms_url'] = conn['uri']
|
||||
logger.info("Tautulli PlexTV :: Server URL retrieved.")
|
||||
|
||||
# get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL
|
||||
if not server['pms_url']:
|
||||
server['pms_url'] = fallback_url
|
||||
logger.warn("Tautulli PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.")
|
||||
|
||||
# Not using SSL, remote has no effect
|
||||
else:
|
||||
server['pms_url'] = fallback_url
|
||||
logger.info("Tautulli PlexTV :: Using user-defined URL.")
|
||||
|
||||
if return_server:
|
||||
return server
|
||||
|
||||
logger.info("Tautulli PlexTV :: Selected server: %s (%s) (%s - Version %s)",
|
||||
server['pms_name'], server['pms_url'], server['pms_platform'], server['pms_version'])
|
||||
|
||||
jellypy.CONFIG.process_kwargs(server)
|
||||
jellypy.CONFIG.write()
|
||||
|
||||
|
||||
class PlexTV(object):
|
||||
"""
|
||||
Plex.tv authentication
|
||||
"""
|
||||
|
||||
def __init__(self, username=None, password=None, token=None, headers=None):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.token = token
|
||||
|
||||
self.urls = 'https://plex.tv'
|
||||
self.timeout = jellypy.CONFIG.PMS_TIMEOUT
|
||||
self.ssl_verify = jellypy.CONFIG.VERIFY_SSL_CERT
|
||||
|
||||
if self.username is None and self.password is None:
|
||||
if not self.token:
|
||||
# Check if we should use the admin token, or the guest server token
|
||||
if session.get_session_user_id():
|
||||
user_data = users.Users()
|
||||
user_tokens = user_data.get_tokens(user_id=session.get_session_user_id())
|
||||
self.token = user_tokens['server_token']
|
||||
else:
|
||||
self.token = jellypy.CONFIG.PMS_TOKEN
|
||||
|
||||
if not self.token:
|
||||
logger.error("Tautulli PlexTV :: PlexTV called, but no token provided.")
|
||||
return
|
||||
|
||||
self.request_handler = http_handler.HTTPHandler(urls=self.urls,
|
||||
token=self.token,
|
||||
timeout=self.timeout,
|
||||
ssl_verify=self.ssl_verify,
|
||||
headers=headers)
|
||||
|
||||
def get_plex_auth(self, output_format='raw'):
|
||||
uri = '/api/v2/users/signin'
|
||||
headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'Accept': 'application/xml'}
|
||||
data = {'login': self.username,
|
||||
'password': self.password,
|
||||
'rememberMe': True}
|
||||
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='POST',
|
||||
headers=headers,
|
||||
data=data,
|
||||
output_format=output_format,
|
||||
no_token=True,
|
||||
encode_multipart=False)
|
||||
|
||||
return request
|
||||
|
||||
def get_token(self):
|
||||
plextv_response = self.get_plex_auth(output_format='xml')
|
||||
|
||||
if plextv_response:
|
||||
try:
|
||||
xml_head = plextv_response.getElementsByTagName('user')
|
||||
if xml_head:
|
||||
user = {'auth_token': xml_head[0].getAttribute('authToken'),
|
||||
'user_id': xml_head[0].getAttribute('id')
|
||||
}
|
||||
else:
|
||||
logger.warn("Tautulli PlexTV :: Could not get Plex authentication token.")
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_token: %s." % e)
|
||||
return None
|
||||
|
||||
return user
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_plexpy_pms_token(self, force=False):
|
||||
if force:
|
||||
logger.debug("Tautulli PlexTV :: Forcing refresh of Plex.tv token.")
|
||||
devices_list = self.get_devices_list()
|
||||
device_id = next((d for d in devices_list if d['device_identifier'] == jellypy.CONFIG.PMS_UUID), {}).get(
|
||||
'device_id', None)
|
||||
|
||||
if device_id:
|
||||
logger.debug("Tautulli PlexTV :: Removing Tautulli from Plex.tv devices.")
|
||||
try:
|
||||
self.delete_plextv_device(device_id=device_id)
|
||||
except:
|
||||
logger.error("Tautulli PlexTV :: Failed to remove Tautulli from Plex.tv devices.")
|
||||
return None
|
||||
else:
|
||||
logger.warn("Tautulli PlexTV :: No existing Tautulli device found.")
|
||||
|
||||
logger.info("Tautulli PlexTV :: Fetching a new Plex.tv token for Tautulli.")
|
||||
user = self.get_token()
|
||||
if user:
|
||||
token = user['auth_token']
|
||||
jellypy.CONFIG.__setattr__('PMS_TOKEN', token)
|
||||
jellypy.CONFIG.write()
|
||||
logger.info("Tautulli PlexTV :: Updated Plex.tv token for Tautulli.")
|
||||
return token
|
||||
|
||||
def get_server_token(self):
|
||||
servers = self.get_plextv_resources(output_format='xml')
|
||||
server_token = ''
|
||||
|
||||
try:
|
||||
xml_head = servers.getElementsByTagName('Device')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_server_token: %s." % e)
|
||||
return None
|
||||
|
||||
for a in xml_head:
|
||||
if helpers.get_xml_attr(a, 'clientIdentifier') == jellypy.CONFIG.PMS_IDENTIFIER \
|
||||
and 'server' in helpers.get_xml_attr(a, 'provides'):
|
||||
server_token = helpers.get_xml_attr(a, 'accessToken')
|
||||
break
|
||||
|
||||
return server_token
|
||||
|
||||
def get_plextv_pin(self, pin='', output_format=''):
|
||||
if pin:
|
||||
uri = '/api/v2/pins/' + pin
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format,
|
||||
no_token=True)
|
||||
else:
|
||||
uri = '/api/v2/pins?strong=true'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='POST',
|
||||
output_format=output_format,
|
||||
no_token=True)
|
||||
return request
|
||||
|
||||
def get_pin(self, pin=''):
|
||||
plextv_response = self.get_plextv_pin(pin=pin,
|
||||
output_format='xml')
|
||||
|
||||
if plextv_response:
|
||||
try:
|
||||
xml_head = plextv_response.getElementsByTagName('pin')
|
||||
if xml_head:
|
||||
pin = {'id': xml_head[0].getAttribute('id'),
|
||||
'code': xml_head[0].getAttribute('code'),
|
||||
'token': xml_head[0].getAttribute('authToken')
|
||||
}
|
||||
return pin
|
||||
else:
|
||||
logger.warn("Tautulli PlexTV :: Could not get Plex authentication pin.")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_pin: %s." % e)
|
||||
return None
|
||||
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_plextv_user_data(self):
|
||||
plextv_response = self.get_plex_auth(output_format='dict')
|
||||
|
||||
if plextv_response:
|
||||
return plextv_response
|
||||
else:
|
||||
return []
|
||||
|
||||
def get_plextv_friends(self, output_format=''):
|
||||
uri = '/api/users'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_user_details(self, output_format=''):
|
||||
uri = '/users/account'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_devices_list(self, output_format=''):
|
||||
uri = '/devices.xml'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_server_list(self, output_format=''):
|
||||
uri = '/pms/servers.xml'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_shared_servers(self, machine_id='', output_format=''):
|
||||
uri = '/api/servers/%s/shared_servers' % machine_id
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_sync_lists(self, machine_id='', output_format=''):
|
||||
uri = '/servers/%s/sync_lists' % machine_id
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_resources(self, include_https=False, output_format=''):
|
||||
if include_https:
|
||||
uri = '/api/resources?includeHttps=1'
|
||||
else:
|
||||
uri = '/api/resources'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_downloads(self, plexpass=False, output_format=''):
|
||||
if plexpass:
|
||||
uri = '/api/downloads/5.json?channel=plexpass'
|
||||
else:
|
||||
uri = '/api/downloads/1.json'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def delete_plextv_device(self, device_id='', output_format=''):
|
||||
uri = '/devices/%s.xml' % device_id
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='DELETE',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def delete_plextv_device_sync_lists(self, client_id='', output_format=''):
|
||||
uri = '/devices/%s/sync_items' % client_id
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def delete_plextv_sync(self, client_id='', sync_id='', output_format=''):
|
||||
uri = '/devices/%s/sync_items/%s' % (client_id, sync_id)
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='DELETE',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def cloud_server_status(self, output_format=''):
|
||||
uri = '/api/v2/cloud_server'
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_plextv_geoip(self, ip_address='', output_format=''):
|
||||
uri = '/api/v2/geoip?ip_address=%s' % ip_address
|
||||
request = self.request_handler.make_request(uri=uri,
|
||||
request_type='GET',
|
||||
output_format=output_format)
|
||||
|
||||
return request
|
||||
|
||||
def get_full_users_list(self):
|
||||
own_account = self.get_plextv_user_details(output_format='xml')
|
||||
friends_list = self.get_plextv_friends(output_format='xml')
|
||||
shared_servers = self.get_plextv_shared_servers(machine_id=jellypy.CONFIG.PMS_IDENTIFIER,
|
||||
output_format='xml')
|
||||
|
||||
users_list = []
|
||||
|
||||
try:
|
||||
xml_head = own_account.getElementsByTagName('user')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse own account XML for get_full_users_list: %s." % e)
|
||||
return []
|
||||
|
||||
for a in xml_head:
|
||||
own_details = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||
"username": helpers.get_xml_attr(a, 'username'),
|
||||
"thumb": helpers.get_xml_attr(a, 'thumb'),
|
||||
"email": helpers.get_xml_attr(a, 'email'),
|
||||
"is_active": 1,
|
||||
"is_admin": 1,
|
||||
"is_home_user": helpers.get_xml_attr(a, 'home'),
|
||||
"is_allow_sync": 1,
|
||||
"is_restricted": helpers.get_xml_attr(a, 'restricted'),
|
||||
"filter_all": helpers.get_xml_attr(a, 'filterAll'),
|
||||
"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'),
|
||||
"user_token": helpers.get_xml_attr(a, 'authToken'),
|
||||
"server_token": helpers.get_xml_attr(a, 'authToken'),
|
||||
"shared_libraries": None,
|
||||
}
|
||||
|
||||
users_list.append(own_details)
|
||||
|
||||
try:
|
||||
xml_head = friends_list.getElementsByTagName('User')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse friends list XML for get_full_users_list: %s." % e)
|
||||
return []
|
||||
|
||||
for a in xml_head:
|
||||
friend = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||
"username": helpers.get_xml_attr(a, 'title'),
|
||||
"thumb": helpers.get_xml_attr(a, 'thumb'),
|
||||
"email": helpers.get_xml_attr(a, 'email'),
|
||||
"is_active": 1,
|
||||
"is_admin": 0,
|
||||
"is_home_user": helpers.get_xml_attr(a, 'home'),
|
||||
"is_allow_sync": helpers.get_xml_attr(a, 'allowSync'),
|
||||
"is_restricted": helpers.get_xml_attr(a, 'restricted'),
|
||||
"filter_all": helpers.get_xml_attr(a, 'filterAll'),
|
||||
"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)
|
||||
|
||||
try:
|
||||
xml_head = shared_servers.getElementsByTagName('SharedServer')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse shared server list XML for get_full_users_list: %s." % e)
|
||||
return []
|
||||
|
||||
user_map = {}
|
||||
for a in xml_head:
|
||||
user_id = helpers.get_xml_attr(a, 'userID')
|
||||
server_token = helpers.get_xml_attr(a, 'accessToken')
|
||||
|
||||
sections = a.getElementsByTagName('Section')
|
||||
shared_libraries = [helpers.get_xml_attr(s, 'key')
|
||||
for s in sections if helpers.get_xml_attr(s, 'shared') == '1']
|
||||
|
||||
user_map[user_id] = {'server_token': server_token,
|
||||
'shared_libraries': shared_libraries}
|
||||
|
||||
for u in users_list:
|
||||
d = user_map.get(u['user_id'], {})
|
||||
u.update(d)
|
||||
|
||||
return users_list
|
||||
|
||||
def get_synced_items(self, machine_id=None, client_id_filter=None, user_id_filter=None,
|
||||
rating_key_filter=None, sync_id_filter=None):
|
||||
|
||||
if not machine_id:
|
||||
machine_id = jellypy.CONFIG.PMS_IDENTIFIER
|
||||
|
||||
if isinstance(rating_key_filter, list):
|
||||
rating_key_filter = [str(k) for k in rating_key_filter]
|
||||
elif rating_key_filter:
|
||||
rating_key_filter = [str(rating_key_filter)]
|
||||
|
||||
if isinstance(user_id_filter, list):
|
||||
user_id_filter = [str(k) for k in user_id_filter]
|
||||
elif user_id_filter:
|
||||
user_id_filter = [str(user_id_filter)]
|
||||
|
||||
sync_list = self.get_plextv_sync_lists(machine_id, output_format='xml')
|
||||
user_data = users.Users()
|
||||
|
||||
synced_items = []
|
||||
|
||||
try:
|
||||
xml_head = sync_list.getElementsByTagName('SyncList')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s." % e)
|
||||
return {}
|
||||
|
||||
for a in xml_head:
|
||||
client_id = helpers.get_xml_attr(a, 'clientIdentifier')
|
||||
|
||||
# Filter by client_id
|
||||
if client_id_filter and str(client_id_filter) != client_id:
|
||||
continue
|
||||
|
||||
sync_list_id = helpers.get_xml_attr(a, 'id')
|
||||
sync_device = a.getElementsByTagName('Device')
|
||||
|
||||
for device in sync_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')
|
||||
|
||||
# Filter by user_id
|
||||
if user_id_filter and device_user_id not in user_id_filter:
|
||||
continue
|
||||
|
||||
for synced in a.getElementsByTagName('SyncItems'):
|
||||
sync_item = synced.getElementsByTagName('SyncItem')
|
||||
for item in sync_item:
|
||||
|
||||
for location in item.getElementsByTagName('Location'):
|
||||
clean_uri = helpers.get_xml_attr(location, 'uri').split('%2F')
|
||||
|
||||
rating_key = next((clean_uri[(idx + 1) % len(clean_uri)]
|
||||
for idx, item in enumerate(clean_uri) if item == 'metadata'), None)
|
||||
|
||||
# Filter by rating_key
|
||||
if rating_key_filter and rating_key not in rating_key_filter:
|
||||
continue
|
||||
|
||||
sync_id = helpers.get_xml_attr(item, 'id')
|
||||
|
||||
# Filter by sync_id
|
||||
if sync_id_filter and str(sync_id_filter) != sync_id:
|
||||
continue
|
||||
|
||||
sync_version = helpers.get_xml_attr(item, 'version')
|
||||
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')
|
||||
|
||||
for status in item.getElementsByTagName('Status'):
|
||||
status_failure_code = helpers.get_xml_attr(status, 'failureCode')
|
||||
status_failure = helpers.get_xml_attr(status, 'failure')
|
||||
status_state = helpers.get_xml_attr(status, 'state')
|
||||
status_item_count = helpers.get_xml_attr(status, 'itemsCount')
|
||||
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 settings in item.getElementsByTagName('MediaSettings'):
|
||||
settings_video_bitrate = helpers.get_xml_attr(settings, 'maxVideoBitrate')
|
||||
settings_video_quality = helpers.get_xml_attr(settings, 'videoQuality')
|
||||
settings_video_resolution = helpers.get_xml_attr(settings, 'videoResolution')
|
||||
settings_audio_boost = helpers.get_xml_attr(settings, 'audioBoost')
|
||||
settings_audio_bitrate = helpers.get_xml_attr(settings, 'musicBitrate')
|
||||
settings_photo_quality = helpers.get_xml_attr(settings, 'photoQuality')
|
||||
settings_photo_resolution = helpers.get_xml_attr(settings, 'photoResolution')
|
||||
|
||||
sync_details = {"device_name": device_name,
|
||||
"platform": device_platform,
|
||||
"user_id": device_user_id,
|
||||
"user": device_friendly_name,
|
||||
"username": device_username,
|
||||
"root_title": sync_root_title,
|
||||
"sync_title": 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,
|
||||
"video_bitrate": settings_video_bitrate,
|
||||
"audio_bitrate": settings_audio_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')
|
||||
|
||||
def delete_sync(self, client_id, sync_id):
|
||||
logger.info("Tautulli PlexTV :: Deleting sync item '%s'." % sync_id)
|
||||
self.delete_plextv_sync(client_id=client_id, sync_id=sync_id)
|
||||
|
||||
def get_server_connections(self, pms_identifier='', pms_ip='', pms_port=32400, include_https=True):
|
||||
|
||||
if not pms_identifier:
|
||||
logger.error("Tautulli PlexTV :: Unable to retrieve server connections: no pms_identifier provided.")
|
||||
return {}
|
||||
|
||||
plextv_resources = self.get_plextv_resources(include_https=include_https,
|
||||
output_format='xml')
|
||||
try:
|
||||
xml_head = plextv_resources.getElementsByTagName('Device')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s." % e)
|
||||
return {}
|
||||
|
||||
# Function to get all connections for a device
|
||||
def get_connections(device):
|
||||
conn = []
|
||||
connections = device.getElementsByTagName('Connection')
|
||||
|
||||
server = {'pms_identifier': helpers.get_xml_attr(device, 'clientIdentifier'),
|
||||
'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:
|
||||
server_details = {'protocol': helpers.get_xml_attr(c, 'protocol'),
|
||||
'address': helpers.get_xml_attr(c, 'address'),
|
||||
'port': helpers.get_xml_attr(c, 'port'),
|
||||
'uri': helpers.get_xml_attr(c, 'uri'),
|
||||
'local': helpers.get_xml_attr(c, 'local')
|
||||
}
|
||||
conn.append(server_details)
|
||||
|
||||
server['connections'] = conn
|
||||
return server
|
||||
|
||||
server = {}
|
||||
|
||||
# Try to match the device
|
||||
for a in xml_head:
|
||||
if helpers.get_xml_attr(a, 'clientIdentifier') == pms_identifier:
|
||||
server = get_connections(a)
|
||||
break
|
||||
|
||||
# Else no device match found
|
||||
if not server:
|
||||
# Try to match the PMS_IP and PMS_PORT
|
||||
for a in xml_head:
|
||||
if helpers.get_xml_attr(a, 'provides') == 'server':
|
||||
connections = a.getElementsByTagName('Connection')
|
||||
|
||||
for connection in connections:
|
||||
if helpers.get_xml_attr(connection, 'address') == pms_ip and \
|
||||
helpers.get_xml_attr(connection, 'port') == str(pms_port):
|
||||
server = get_connections(a)
|
||||
break
|
||||
|
||||
if server.get('connections'):
|
||||
break
|
||||
|
||||
return server
|
||||
|
||||
def get_server_times(self):
|
||||
servers = self.get_plextv_server_list(output_format='xml')
|
||||
server_times = {}
|
||||
|
||||
try:
|
||||
xml_head = servers.getElementsByTagName('Server')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_server_times: %s." % e)
|
||||
return {}
|
||||
|
||||
for a in xml_head:
|
||||
if helpers.get_xml_attr(a, 'machineIdentifier') == jellypy.CONFIG.PMS_IDENTIFIER:
|
||||
server_times = {"created_at": helpers.get_xml_attr(a, 'createdAt'),
|
||||
"updated_at": helpers.get_xml_attr(a, 'updatedAt'),
|
||||
"version": helpers.get_xml_attr(a, 'version')
|
||||
}
|
||||
break
|
||||
|
||||
return server_times
|
||||
|
||||
def discover(self, include_cloud=True, all_servers=False):
|
||||
""" Query plex for all servers online. Returns the ones you own in a selectize format """
|
||||
|
||||
# Try to discover localhost server
|
||||
local_machine_identifier = None
|
||||
request_handler = http_handler.HTTPHandler(urls='http://127.0.0.1:32400', timeout=1,
|
||||
ssl_verify=False, silent=True)
|
||||
request = request_handler.make_request(uri='/identity', request_type='GET', output_format='xml')
|
||||
if request:
|
||||
xml_head = request.getElementsByTagName('MediaContainer')[0]
|
||||
local_machine_identifier = xml_head.getAttribute('machineIdentifier')
|
||||
|
||||
local_server = {'httpsRequired': '0',
|
||||
'clientIdentifier': local_machine_identifier,
|
||||
'label': 'Local',
|
||||
'ip': '127.0.0.1',
|
||||
'port': '32400',
|
||||
'uri': 'http://127.0.0.1:32400',
|
||||
'local': '1',
|
||||
'value': '127.0.0.1:32400',
|
||||
'is_cloud': False
|
||||
}
|
||||
|
||||
servers = self.get_plextv_resources(include_https=True, output_format='xml')
|
||||
clean_servers = []
|
||||
|
||||
try:
|
||||
xml_head = servers.getElementsByTagName('MediaContainer')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Failed to get servers from plex: %s." % e)
|
||||
return []
|
||||
|
||||
for a in xml_head:
|
||||
if a.getAttribute('size'):
|
||||
if a.getAttribute('size') == '0':
|
||||
return []
|
||||
|
||||
if a.getElementsByTagName('Device'):
|
||||
devices = a.getElementsByTagName('Device')
|
||||
|
||||
for d in devices:
|
||||
if helpers.get_xml_attr(d, 'presence') == '1' and \
|
||||
helpers.get_xml_attr(d, 'owned') == '1' and \
|
||||
helpers.get_xml_attr(d, 'provides') == 'server':
|
||||
|
||||
is_cloud = (helpers.get_xml_attr(d, 'platform').lower() == 'cloud')
|
||||
if not include_cloud and is_cloud:
|
||||
continue
|
||||
|
||||
connections = d.getElementsByTagName('Connection')
|
||||
|
||||
for c in connections:
|
||||
if not all_servers:
|
||||
# If this is a remote server don't show any local IPs.
|
||||
if helpers.get_xml_attr(d, 'publicAddressMatches') == '0' and \
|
||||
helpers.get_xml_attr(c, 'local') == '1':
|
||||
continue
|
||||
|
||||
# If this is a local server don't show any remote IPs.
|
||||
if helpers.get_xml_attr(d, 'publicAddressMatches') == '1' and \
|
||||
helpers.get_xml_attr(c, 'local') == '0':
|
||||
continue
|
||||
|
||||
if helpers.get_xml_attr(d, 'clientIdentifier') == local_machine_identifier:
|
||||
local_server['httpsRequired'] = helpers.get_xml_attr(d, 'httpsRequired')
|
||||
local_server['label'] = helpers.get_xml_attr(d, 'name')
|
||||
clean_servers.append(local_server)
|
||||
local_machine_identifier = None
|
||||
|
||||
server = {'httpsRequired': '1' if is_cloud else helpers.get_xml_attr(d, 'httpsRequired'),
|
||||
'clientIdentifier': helpers.get_xml_attr(d, 'clientIdentifier'),
|
||||
'label': helpers.get_xml_attr(d, 'name'),
|
||||
'ip': helpers.get_xml_attr(c, 'address'),
|
||||
'port': helpers.get_xml_attr(c, 'port'),
|
||||
'uri': helpers.get_xml_attr(c, 'uri'),
|
||||
'local': helpers.get_xml_attr(c, 'local'),
|
||||
'value': helpers.get_xml_attr(c, 'address') + ':' + helpers.get_xml_attr(c,
|
||||
'port'),
|
||||
'is_cloud': is_cloud
|
||||
}
|
||||
clean_servers.append(server)
|
||||
|
||||
if local_machine_identifier:
|
||||
clean_servers.append(local_server)
|
||||
|
||||
clean_servers.sort(key=lambda s: (s['label'], -int(s['local']), s['ip']))
|
||||
|
||||
return clean_servers
|
||||
|
||||
def get_plex_downloads(self):
|
||||
logger.debug("Tautulli PlexTV :: Retrieving current server version.")
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
pms_connect.set_server_version()
|
||||
|
||||
update_channel = pms_connect.get_server_update_channel()
|
||||
|
||||
logger.debug("Tautulli PlexTV :: Plex update channel is %s." % update_channel)
|
||||
plex_downloads = self.get_plextv_downloads(plexpass=(update_channel == 'beta'))
|
||||
|
||||
try:
|
||||
available_downloads = json.loads(plex_downloads)
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to load JSON for get_plex_updates.")
|
||||
return {}
|
||||
|
||||
# Get the updates for the platform
|
||||
pms_platform = common.PMS_PLATFORM_NAME_OVERRIDES.get(jellypy.CONFIG.PMS_PLATFORM, jellypy.CONFIG.PMS_PLATFORM)
|
||||
platform_downloads = available_downloads.get('computer').get(pms_platform) or \
|
||||
available_downloads.get('nas').get(pms_platform)
|
||||
|
||||
if not platform_downloads:
|
||||
logger.error("Tautulli PlexTV :: Unable to retrieve Plex updates: Could not match server platform: %s."
|
||||
% pms_platform)
|
||||
return {}
|
||||
|
||||
v_old = helpers.cast_to_int(
|
||||
"".join(v.zfill(4) for v in jellypy.CONFIG.PMS_VERSION.split('-')[0].split('.')[:4]))
|
||||
v_new = helpers.cast_to_int(
|
||||
"".join(v.zfill(4) for v in platform_downloads.get('version', '').split('-')[0].split('.')[:4]))
|
||||
|
||||
if not v_old:
|
||||
logger.error("Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid current server version: %s."
|
||||
% jellypy.CONFIG.PMS_VERSION)
|
||||
return {}
|
||||
if not v_new:
|
||||
logger.error("Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid new server version: %s."
|
||||
% platform_downloads.get('version'))
|
||||
return {}
|
||||
|
||||
# Get proper download
|
||||
releases = platform_downloads.get('releases', [{}])
|
||||
release = next((r for r in releases if r['distro'] == jellypy.CONFIG.PMS_UPDATE_DISTRO and
|
||||
r['build'] == jellypy.CONFIG.PMS_UPDATE_DISTRO_BUILD), releases[0])
|
||||
|
||||
download_info = {'update_available': v_new > v_old,
|
||||
'platform': platform_downloads.get('name'),
|
||||
'release_date': platform_downloads.get('release_date'),
|
||||
'version': platform_downloads.get('version'),
|
||||
'requirements': platform_downloads.get('requirements'),
|
||||
'extra_info': platform_downloads.get('extra_info'),
|
||||
'changelog_added': platform_downloads.get('items_added'),
|
||||
'changelog_fixed': platform_downloads.get('items_fixed'),
|
||||
'label': release.get('label'),
|
||||
'distro': release.get('distro'),
|
||||
'distro_build': release.get('build'),
|
||||
'download_url': release.get('url'),
|
||||
}
|
||||
|
||||
return download_info
|
||||
|
||||
def get_plexpass_status(self):
|
||||
account_data = self.get_plextv_user_details(output_format='xml')
|
||||
|
||||
try:
|
||||
subscription = account_data.getElementsByTagName('subscription')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_plexpass_status: %s." % e)
|
||||
return False
|
||||
|
||||
if subscription and helpers.get_xml_attr(subscription[0], 'active') == '1':
|
||||
jellypy.CONFIG.__setattr__('PMS_PLEXPASS', 1)
|
||||
jellypy.CONFIG.write()
|
||||
return True
|
||||
else:
|
||||
logger.debug("Tautulli PlexTV :: Plex Pass subscription not found.")
|
||||
jellypy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
|
||||
jellypy.CONFIG.write()
|
||||
return False
|
||||
|
||||
def get_devices_list(self):
|
||||
devices = self.get_plextv_devices_list(output_format='xml')
|
||||
|
||||
try:
|
||||
xml_head = devices.getElementsByTagName('Device')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_devices_list: %s." % e)
|
||||
return []
|
||||
|
||||
devices_list = []
|
||||
for a in xml_head:
|
||||
device = {"device_name": helpers.get_xml_attr(a, 'name'),
|
||||
"product": helpers.get_xml_attr(a, 'product'),
|
||||
"product_version": helpers.get_xml_attr(a, 'productVersion'),
|
||||
"platform": helpers.get_xml_attr(a, 'platform'),
|
||||
"platform_version": helpers.get_xml_attr(a, 'platformVersion'),
|
||||
"device": helpers.get_xml_attr(a, 'device'),
|
||||
"model": helpers.get_xml_attr(a, 'model'),
|
||||
"vendor": helpers.get_xml_attr(a, 'vendor'),
|
||||
"provides": helpers.get_xml_attr(a, 'provides'),
|
||||
"device_identifier": helpers.get_xml_attr(a, 'clientIdentifier'),
|
||||
"device_id": helpers.get_xml_attr(a, 'id'),
|
||||
"token": helpers.get_xml_attr(a, 'token')
|
||||
}
|
||||
devices_list.append(device)
|
||||
|
||||
return devices_list
|
||||
|
||||
def get_cloud_server_status(self):
|
||||
cloud_status = self.cloud_server_status(output_format='xml')
|
||||
|
||||
try:
|
||||
status_info = cloud_status.getElementsByTagName('info')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_cloud_server_status: %s." % e)
|
||||
return False
|
||||
|
||||
for info in status_info:
|
||||
servers = info.getElementsByTagName('server')
|
||||
for s in servers:
|
||||
if helpers.get_xml_attr(s, 'address') == jellypy.CONFIG.PMS_IP:
|
||||
if helpers.get_xml_attr(info, 'running') == '1':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_plex_account_details(self):
|
||||
account_data = self.get_plextv_user_details(output_format='xml')
|
||||
|
||||
try:
|
||||
xml_head = account_data.getElementsByTagName('user')
|
||||
except Exception as e:
|
||||
logger.warn("Tautulli PlexTV :: Unable to parse XML for get_plex_account_details: %s." % e)
|
||||
return None
|
||||
|
||||
for a in xml_head:
|
||||
account_details = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||
"username": helpers.get_xml_attr(a, 'username'),
|
||||
"thumb": helpers.get_xml_attr(a, 'thumb'),
|
||||
"email": helpers.get_xml_attr(a, 'email'),
|
||||
"is_home_user": helpers.get_xml_attr(a, 'home'),
|
||||
"is_restricted": helpers.get_xml_attr(a, 'restricted'),
|
||||
"filter_all": helpers.get_xml_attr(a, 'filterAll'),
|
||||
"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'),
|
||||
"user_token": helpers.get_xml_attr(a, 'authToken')
|
||||
}
|
||||
return account_details
|
||||
|
||||
def get_geoip_lookup(self, ip_address=''):
|
||||
if not ip_address or not helpers.is_valid_ip(ip_address):
|
||||
return
|
||||
|
||||
geoip_data = self.get_plextv_geoip(ip_address=ip_address, output_format='xml')
|
||||
|
||||
try:
|
||||
xml_head = geoip_data.getElementsByTagName('location')
|
||||
except Exception as e:
|
||||
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_geoip_lookup: %s." % e)
|
||||
return None
|
||||
|
||||
for a in xml_head:
|
||||
coordinates = helpers.get_xml_attr(a, 'coordinates').split(',')
|
||||
latitude = longitude = None
|
||||
if len(coordinates) == 2:
|
||||
latitude, longitude = [helpers.cast_to_float(c) for c in coordinates]
|
||||
|
||||
geo_info = {"code": helpers.get_xml_attr(a, 'code') or None,
|
||||
"country": helpers.get_xml_attr(a, 'country') or None,
|
||||
"region": helpers.get_xml_attr(a, 'subdivisions') or None,
|
||||
"city": helpers.get_xml_attr(a, 'city') or None,
|
||||
"postal_code": helpers.get_xml_attr(a, 'postal_code') or None,
|
||||
"timezone": helpers.get_xml_attr(a, 'time_zone') or None,
|
||||
"latitude": latitude,
|
||||
"longitude": longitude,
|
||||
"continent": None, # keep for backwards compatibility with GeoLite2
|
||||
"accuracy": None # keep for backwards compatibility with GeoLite2
|
||||
}
|
||||
|
||||
return geo_info
|
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,6 @@ from jellypy import datatables
|
||||
from jellypy import helpers
|
||||
from jellypy import libraries
|
||||
from jellypy import logger
|
||||
from jellypy import plextv
|
||||
from jellypy import session
|
||||
|
||||
|
||||
|
@@ -33,7 +33,6 @@ from jellypy.database import MonitorDatabase
|
||||
from jellypy.helpers import timestamp
|
||||
from jellypy.password import check_hash
|
||||
from jellypy.users import Users, refresh_users
|
||||
from jellypy.plextv import PlexTV
|
||||
|
||||
# Monkey patch SameSite support into cookies.
|
||||
# https://stackoverflow.com/a/50813092
|
||||
@@ -51,21 +50,22 @@ def plex_user_login(username=None, password=None, token=None, headers=None):
|
||||
user_token = None
|
||||
user_id = None
|
||||
|
||||
# Try to login to Plex.tv to check if the user has a vaild account
|
||||
if username and password:
|
||||
plex_tv = PlexTV(username=username, password=password, headers=headers)
|
||||
plex_user = plex_tv.get_token()
|
||||
if plex_user:
|
||||
user_token = plex_user['auth_token']
|
||||
user_id = plex_user['user_id']
|
||||
elif token:
|
||||
plex_tv = PlexTV(token=token, headers=headers)
|
||||
plex_user = plex_tv.get_plex_account_details()
|
||||
if plex_user:
|
||||
user_token = token
|
||||
user_id = plex_user['user_id']
|
||||
else:
|
||||
return None
|
||||
# TODO: Jellyfin
|
||||
# # Try to login to Plex.tv to check if the user has a vaild account
|
||||
# if username and password:
|
||||
# plex_tv = PlexTV(username=username, password=password, headers=headers)
|
||||
# plex_user = plex_tv.get_token()
|
||||
# if plex_user:
|
||||
# user_token = plex_user['auth_token']
|
||||
# user_id = plex_user['user_id']
|
||||
# elif token:
|
||||
# plex_tv = PlexTV(token=token, headers=headers)
|
||||
# plex_user = plex_tv.get_plex_account_details()
|
||||
# if plex_user:
|
||||
# user_token = token
|
||||
# user_id = plex_user['user_id']
|
||||
# else:
|
||||
# return None
|
||||
|
||||
if user_token and user_id:
|
||||
# Try to retrieve the user from the database.
|
||||
@@ -86,10 +86,12 @@ def plex_user_login(username=None, password=None, token=None, headers=None):
|
||||
if not jellypy.CONFIG.ALLOW_GUEST_ACCESS:
|
||||
return None
|
||||
|
||||
# The user is in the database, and guest access is enabled, so try to retrieve a server token.
|
||||
# If a server token is returned, then the user is a valid friend of the server.
|
||||
plex_tv = PlexTV(token=user_token, headers=headers)
|
||||
server_token = plex_tv.get_server_token()
|
||||
# TODO: Jellyfin
|
||||
# # The user is in the database, and guest access is enabled, so try to retrieve a server token.
|
||||
# # If a server token is returned, then the user is a valid friend of the server.
|
||||
# plex_tv = PlexTV(token=user_token, headers=headers)
|
||||
# server_token = plex_tv.get_server_token()
|
||||
server_token = None
|
||||
if server_token:
|
||||
|
||||
# Register the new user / update the access tokens.
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user