mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 07:46:07 -07:00
Very early work on implementing websocket monitoring method.
This commit is contained in:
parent
9c955771c0
commit
fa71beb03f
24 changed files with 7814 additions and 3 deletions
|
@ -279,7 +279,11 @@ def initialize_scheduler():
|
|||
|
||||
if CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
|
||||
schedule_job(plextv.get_real_pms_url, 'Refresh Plex Server URLs', hours=12, minutes=0, seconds=0)
|
||||
schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=seconds)
|
||||
|
||||
# If we're not using websockets then fall back to polling
|
||||
if not CONFIG.MONITORING_USE_WEBSOCKET:
|
||||
schedule_job(monitor.check_active_sessions, 'Check for active sessions',
|
||||
hours=0, minutes=0, seconds=seconds)
|
||||
|
||||
# Refresh the users list
|
||||
if CONFIG.REFRESH_USERS_INTERVAL:
|
||||
|
|
|
@ -111,6 +111,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'MUSIC_NOTIFY_ON_PAUSE': (int, 'Monitoring', 0),
|
||||
'MUSIC_LOGGING_ENABLE': (int, 'Monitoring', 0),
|
||||
'MONITORING_INTERVAL': (int, 'Monitoring', 60),
|
||||
'MONITORING_USE_WEBSOCKET': (int, 'Monitoring', 0),
|
||||
'NMA_APIKEY': (str, 'NMA', ''),
|
||||
'NMA_ENABLED': (int, 'NMA', 0),
|
||||
'NMA_PRIORITY': (int, 'NMA', 0),
|
||||
|
|
|
@ -160,6 +160,21 @@ def check_active_sessions():
|
|||
logger.debug(u"PlexPy Monitor :: Unable to read session list.")
|
||||
|
||||
|
||||
def get_last_state_by_session(session_key=None):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
||||
if str(session_key).isdigit():
|
||||
logger.debug(u"PlexPy Monitor :: Checking state for sessionKey %s..." % str(session_key))
|
||||
query = 'SELECT state FROM sessions WHERE session_key = ? LIMIT 1'
|
||||
result = monitor_db.select(query, args=[session_key])
|
||||
|
||||
if result:
|
||||
return result[0]
|
||||
|
||||
logger.debug(u"PlexPy Monitor :: No session with key %s is active." % str(session_key))
|
||||
return False
|
||||
|
||||
|
||||
class MonitorProcessing(object):
|
||||
|
||||
def __init__(self):
|
||||
|
|
124
plexpy/web_socket.py
Normal file
124
plexpy/web_socket.py
Normal file
|
@ -0,0 +1,124 @@
|
|||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy 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.
|
||||
#
|
||||
# PlexPy 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 PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Mostly borrowed from https://github.com/trakt/Plex-Trakt-Scrobbler
|
||||
|
||||
from plexpy import logger
|
||||
|
||||
import threading
|
||||
import plexpy
|
||||
import json
|
||||
import time
|
||||
import websocket
|
||||
|
||||
name = 'websocket'
|
||||
opcode_data = (websocket.ABNF.OPCODE_TEXT, websocket.ABNF.OPCODE_BINARY)
|
||||
|
||||
|
||||
def start_thread():
|
||||
threading.Thread(target=run).start()
|
||||
|
||||
|
||||
def run():
|
||||
from websocket import create_connection
|
||||
|
||||
uri = 'ws://%s:%s/:/websockets/notifications' % (
|
||||
plexpy.CONFIG.PMS_IP,
|
||||
plexpy.CONFIG.PMS_PORT
|
||||
)
|
||||
|
||||
# Set authentication token (if one is available)
|
||||
if plexpy.CONFIG.PMS_TOKEN:
|
||||
uri += '?X-Plex-Token=' + plexpy.CONFIG.PMS_TOKEN
|
||||
|
||||
ws = create_connection(uri)
|
||||
|
||||
reconnects = 0
|
||||
logger.debug(u'PlexPy WebSocket :: Ready')
|
||||
|
||||
while True:
|
||||
try:
|
||||
process(*receive(ws))
|
||||
|
||||
# successfully received data, reset reconnects counter
|
||||
reconnects = 0
|
||||
except websocket.WebSocketConnectionClosedException:
|
||||
if reconnects <= 5:
|
||||
reconnects += 1
|
||||
|
||||
# Increasing sleep interval between reconnections
|
||||
if reconnects > 1:
|
||||
time.sleep(2 * (reconnects - 1))
|
||||
|
||||
logger.info(u'PlexPy WebSocket :: Connection has closed, reconnecting...')
|
||||
ws = create_connection(uri)
|
||||
else:
|
||||
logger.error(u'PlexPy WebSocket :: Connection unavailable, activity monitoring not available')
|
||||
break
|
||||
|
||||
logger.debug(u'Leaving thread.')
|
||||
|
||||
|
||||
def receive(ws):
|
||||
frame = ws.recv_frame()
|
||||
|
||||
if not frame:
|
||||
raise websocket.WebSocketException("Not a valid frame %s" % frame)
|
||||
elif frame.opcode in opcode_data:
|
||||
return frame.opcode, frame.data
|
||||
elif frame.opcode == websocket.ABNF.OPCODE_CLOSE:
|
||||
ws.send_close()
|
||||
return frame.opcode, None
|
||||
elif frame.opcode == websocket.ABNF.OPCODE_PING:
|
||||
ws.pong("Hi!")
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
def process(opcode, data):
|
||||
from plexpy import monitor
|
||||
|
||||
if opcode not in opcode_data:
|
||||
return False
|
||||
|
||||
try:
|
||||
info = json.loads(data)
|
||||
except Exception as ex:
|
||||
logger.warn(u'PlexPy WebSocket :: Error decoding message from websocket: %s' % ex)
|
||||
logger.debug(data)
|
||||
return False
|
||||
|
||||
type = info.get('type')
|
||||
|
||||
if not type:
|
||||
return False
|
||||
|
||||
if type == 'playing':
|
||||
logger.debug('%s.playing %s' % (name, info))
|
||||
try:
|
||||
time_line = info.get('_children')
|
||||
except:
|
||||
logger.debug(u"PlexPy WebSocket :: Session found but unable to get timeline data.")
|
||||
return False
|
||||
|
||||
last_session_state = monitor.get_last_state_by_session(time_line[0]['sessionKey'])
|
||||
session_state = time_line[0]['state']
|
||||
|
||||
if last_session_state != session_state:
|
||||
monitor.check_active_sessions()
|
||||
else:
|
||||
logger.debug(u"PlexPy WebSocket :: Session %s state has not changed." % time_line[0]['sessionKey'])
|
||||
|
||||
return True
|
|
@ -430,6 +430,7 @@ class WebInterface(object):
|
|||
"movie_notify_on_pause": checked(plexpy.CONFIG.MOVIE_NOTIFY_ON_PAUSE),
|
||||
"music_notify_on_pause": checked(plexpy.CONFIG.MUSIC_NOTIFY_ON_PAUSE),
|
||||
"monitoring_interval": plexpy.CONFIG.MONITORING_INTERVAL,
|
||||
"monitoring_use_websocket": checked(plexpy.CONFIG.MONITORING_USE_WEBSOCKET),
|
||||
"refresh_users_interval": plexpy.CONFIG.REFRESH_USERS_INTERVAL,
|
||||
"refresh_users_on_startup": checked(plexpy.CONFIG.REFRESH_USERS_ON_STARTUP),
|
||||
"ip_logging_enable": checked(plexpy.CONFIG.IP_LOGGING_ENABLE),
|
||||
|
@ -468,7 +469,7 @@ class WebInterface(object):
|
|||
checked_configs = [
|
||||
"launch_browser", "enable_https", "api_enabled", "freeze_db", "check_github",
|
||||
"grouping_global_history", "grouping_user_history", "grouping_charts", "pms_use_bif", "pms_ssl",
|
||||
"tv_notify_enable", "movie_notify_enable", "music_notify_enable",
|
||||
"tv_notify_enable", "movie_notify_enable", "music_notify_enable", "monitoring_use_websocket",
|
||||
"tv_notify_on_start", "movie_notify_on_start", "music_notify_on_start",
|
||||
"tv_notify_on_stop", "movie_notify_on_stop", "music_notify_on_stop",
|
||||
"tv_notify_on_pause", "movie_notify_on_pause", "music_notify_on_pause", "refresh_users_on_startup",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue