mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 15:56:07 -07:00
Add very early attempt at retrieving IP address per stream.
This commit is contained in:
parent
9d5dabca14
commit
7a5cad1a31
5 changed files with 125 additions and 34 deletions
|
@ -22,10 +22,13 @@ thumb Returns the location of the item's thumbnail. Use with p
|
|||
art Returns the location of the item's artwork
|
||||
progress_percent Returns the current progress of the item. 0 to 100.
|
||||
user Returns the name of the user owning the session.
|
||||
user_id Returns the Plex user id if available.
|
||||
machine_id Returns the machine id of the players being used.
|
||||
friendly_name Returns the friendlly name of the user owning the session.
|
||||
state Returns the state of the current session. Either 'playing', 'paused' or 'buffering'.
|
||||
title Returns the name of the episode, movie or music track.
|
||||
player Returns the name of the platform used to play the stream.
|
||||
platform Returns the type of platform used to play the stream.
|
||||
audio_decision Returns the audio transcode decision. Either 'transcode', 'copy' or 'direct play'.
|
||||
audio_codec Returns the name of the audio codec.
|
||||
audio_channels Returns the number of audio channels.
|
||||
|
@ -134,7 +137,7 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$("#platform-${a['session_key']}").html("<img src='" + getPlatformImagePath('${a['player']}') + "'>");
|
||||
$("#platform-${a['session_key']}").html("<img src='" + getPlatformImagePath('${a['platform']}') + "'>");
|
||||
|
||||
</script>
|
||||
% endfor
|
||||
|
|
|
@ -18,7 +18,7 @@ import re
|
|||
import os
|
||||
import plexpy
|
||||
|
||||
def get_log_tail(window=20):
|
||||
def get_log_tail(window=20, parsed=True):
|
||||
|
||||
if plexpy.CONFIG.PMS_LOGS_FOLDER:
|
||||
log_file = os.path.join(plexpy.CONFIG.PMS_LOGS_FOLDER, 'Plex Media Server.log')
|
||||
|
@ -33,24 +33,27 @@ def get_log_tail(window=20):
|
|||
|
||||
log_lines = tail(logfile, window)
|
||||
|
||||
line_error = False
|
||||
clean_lines = []
|
||||
for i in log_lines:
|
||||
try:
|
||||
log_time = i.split(' [')[0]
|
||||
log_level = i.split('] ', 1)[1].split(' - ',1)[0]
|
||||
log_msg = i.split('] ', 1)[1].split(' - ',1)[1]
|
||||
full_line = [log_time, log_level, log_msg]
|
||||
clean_lines.append(full_line)
|
||||
except:
|
||||
line_error = True
|
||||
full_line = ['', '', 'Unable to parse log line.']
|
||||
clean_lines.append(full_line)
|
||||
if parsed:
|
||||
line_error = False
|
||||
clean_lines = []
|
||||
for i in log_lines:
|
||||
try:
|
||||
log_time = i.split(' [')[0]
|
||||
log_level = i.split('] ', 1)[1].split(' - ',1)[0]
|
||||
log_msg = i.split('] ', 1)[1].split(' - ',1)[1]
|
||||
full_line = [log_time, log_level, log_msg]
|
||||
clean_lines.append(full_line)
|
||||
except:
|
||||
line_error = True
|
||||
full_line = ['', '', 'Unable to parse log line.']
|
||||
clean_lines.append(full_line)
|
||||
|
||||
if line_error:
|
||||
logger.error('PlexPy was unable to parse some lines of the Plex Media Server log.')
|
||||
if line_error:
|
||||
logger.error('PlexPy was unable to parse some lines of the Plex Media Server log.')
|
||||
|
||||
return clean_lines
|
||||
return clean_lines
|
||||
|
||||
return log_lines
|
||||
|
||||
# http://stackoverflow.com/a/13790289/2405162
|
||||
def tail(f, lines=1, _buffer=4098):
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from plexpy import logger, helpers, plexwatch, pmsconnect, notification_handler, config
|
||||
from plexpy import logger, helpers, plexwatch, pmsconnect, notification_handler, config, log_reader
|
||||
|
||||
from xml.dom import minidom
|
||||
from httplib import HTTPSConnection
|
||||
|
@ -23,6 +23,8 @@ import os
|
|||
import sqlite3
|
||||
import threading
|
||||
import plexpy
|
||||
import re
|
||||
import time
|
||||
|
||||
monitor_lock = threading.Lock()
|
||||
|
||||
|
@ -32,6 +34,7 @@ def check_active_sessions():
|
|||
pms_connect = pmsconnect.PmsConnect()
|
||||
session_list = pms_connect.get_current_activity()
|
||||
monitor_db = MonitorDatabase()
|
||||
# logger.debug(u"Checking for active streams.")
|
||||
|
||||
if session_list['stream_count'] != '0':
|
||||
media_container = session_list['sessions']
|
||||
|
@ -46,6 +49,7 @@ def check_active_sessions():
|
|||
title = session['title']
|
||||
parent_title = session['parent_title']
|
||||
grandparent_title = session['grandparent_title']
|
||||
machine_id = session['machine_id']
|
||||
|
||||
write_session = monitor_db.write_session_key(session_key, rating_key, media_type)
|
||||
if write_session == 'insert':
|
||||
|
@ -60,6 +64,12 @@ def check_active_sessions():
|
|||
pushmessage = '%s (%s) starting playing %s' % (friendly_name, platform, item_title)
|
||||
notification_handler.push_nofitications(pushmessage, 'PlexPy Playback started', 'Playback Started')
|
||||
|
||||
# Try and grab IP address from logs
|
||||
if plexpy.CONFIG.PMS_LOGS_FOLDER:
|
||||
monitor_processing = MonitorProcessing()
|
||||
ip_address = monitor_processing.find_session_ip(rating_key=rating_key,
|
||||
machine_id=machine_id)
|
||||
|
||||
keys = {'session_key': session_key,
|
||||
'rating_key': rating_key}
|
||||
active_streams.append(keys)
|
||||
|
@ -186,3 +196,54 @@ class MonitorDatabase(object):
|
|||
|
||||
# We want to know if it was an update or insert
|
||||
return trans_type
|
||||
|
||||
|
||||
class MonitorProcessing(object):
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def find_session_ip(self, rating_key=None, machine_id=None):
|
||||
|
||||
logger.debug(u"Requesting log lines...")
|
||||
log_lines = log_reader.get_log_tail(window=5000, parsed=False)
|
||||
|
||||
rating_key_line = 'metadata%2F' + rating_key
|
||||
machine_id_line = 'session=' + machine_id
|
||||
|
||||
for line in reversed(log_lines):
|
||||
# We're good if we find a line with both machine id and rating key
|
||||
# This is usually when there is a transcode session
|
||||
if machine_id_line in line and rating_key_line in line:
|
||||
# Currently only checking for ipv4 addresses
|
||||
ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)
|
||||
if ipv4:
|
||||
# The logged IP will always be the first match and we don't want localhost entries
|
||||
if ipv4[0] != '127.0.0.1':
|
||||
logger.debug(u"Matched IP address (%s) for stream ratingKey %s and machineIdentifier %s."
|
||||
% (ipv4[0], rating_key, machine_id))
|
||||
return ipv4[0]
|
||||
|
||||
logger.debug(u"Unable to find IP address on first pass. Attempting fallback check in 5 seconds...")
|
||||
|
||||
# Wait for the log to catch up and read in new lines
|
||||
time.sleep(5)
|
||||
|
||||
logger.debug(u"Requesting log lines...")
|
||||
log_lines = log_reader.get_log_tail(window=5000, parsed=False)
|
||||
|
||||
for line in reversed(log_lines):
|
||||
if 'GET /:/timeline' in line and rating_key_line in line:
|
||||
# Currently only checking for ipv4 addresses
|
||||
# This method can return the wrong IP address if more than one user
|
||||
# starts watching the same media item around the same time.
|
||||
ipv4 = re.findall(r'[0-9]+(?:\.[0-9]+){3}', line)
|
||||
if ipv4:
|
||||
# The logged IP will always be the first match and we don't want localhost entries
|
||||
if ipv4[0] != '127.0.0.1':
|
||||
logger.debug(u"Matched IP address (%s) for stream ratingKey %s." % (ipv4[0], rating_key))
|
||||
return ipv4[0]
|
||||
|
||||
logger.debug(u"Unable to find IP address on fallback search. Not logging IP address.")
|
||||
|
||||
return None
|
||||
|
|
|
@ -24,7 +24,7 @@ class PmsConnect(object):
|
|||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.protocol = 'HTTPS'
|
||||
self.protocol = 'HTTP'
|
||||
self.request_handler = http_handler.HTTPHandler(host=plexpy.CONFIG.PMS_IP,
|
||||
port=plexpy.CONFIG.PMS_PORT,
|
||||
token=plexpy.CONFIG.PMS_TOKEN)
|
||||
|
@ -196,7 +196,7 @@ class PmsConnect(object):
|
|||
for a in xml_head:
|
||||
if a.getAttribute('size'):
|
||||
if a.getAttribute('size') == '0':
|
||||
output = {'recently_added': None}
|
||||
output = {'recently_added': []}
|
||||
return output
|
||||
|
||||
if a.getElementsByTagName('Directory'):
|
||||
|
@ -459,14 +459,24 @@ class PmsConnect(object):
|
|||
duration = helpers.get_xml_attr(media_info, 'duration')
|
||||
progress = helpers.get_xml_attr(session, 'viewOffset')
|
||||
|
||||
user_details = plex_watch.get_user_details(
|
||||
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
|
||||
|
||||
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Track'):
|
||||
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')[:-6]
|
||||
else:
|
||||
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')
|
||||
|
||||
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
|
||||
'art': helpers.get_xml_attr(session, 'art'),
|
||||
'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
|
||||
'thumb': helpers.get_xml_attr(session, 'thumb'),
|
||||
'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
|
||||
'friendly_name': plex_watch.get_user_friendly_name(
|
||||
helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'user_id': user_details['user_id'],
|
||||
'friendly_name': user_details['friendly_name'],
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'machine_id': machine_id,
|
||||
'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
|
||||
'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
|
||||
'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
|
||||
|
@ -528,15 +538,25 @@ class PmsConnect(object):
|
|||
thumb = helpers.get_xml_attr(session, 'thumb')
|
||||
use_indexes = 0
|
||||
|
||||
user_details = plex_watch.get_user_details(
|
||||
user=helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'))
|
||||
|
||||
if helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier').endswith('_Video'):
|
||||
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')[:-6]
|
||||
else:
|
||||
machine_id = helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'machineIdentifier')
|
||||
|
||||
if helpers.get_xml_attr(session, 'type') == 'episode':
|
||||
session_output = {'session_key': helpers.get_xml_attr(session, 'sessionKey'),
|
||||
'art': helpers.get_xml_attr(session, 'art'),
|
||||
'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
|
||||
'thumb': thumb,
|
||||
'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
|
||||
'friendly_name': plex_watch.get_user_friendly_name(
|
||||
helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'user_id': user_details['user_id'],
|
||||
'friendly_name': user_details['friendly_name'],
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'machine_id': machine_id,
|
||||
'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
|
||||
'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
|
||||
'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
|
||||
|
@ -561,9 +581,11 @@ class PmsConnect(object):
|
|||
'thumb': thumb,
|
||||
'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
|
||||
'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
|
||||
'friendly_name': plex_watch.get_user_friendly_name(
|
||||
helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'user_id': user_details['user_id'],
|
||||
'friendly_name': user_details['friendly_name'],
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'machine_id': machine_id,
|
||||
'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
|
||||
'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
|
||||
'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
|
||||
|
@ -588,9 +610,11 @@ class PmsConnect(object):
|
|||
'thumb': thumb,
|
||||
'parent_thumb': helpers.get_xml_attr(session, 'parentThumb'),
|
||||
'user': helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
|
||||
'friendly_name': plex_watch.get_user_friendly_name(
|
||||
helpers.get_xml_attr(session.getElementsByTagName('User')[0], 'title')),
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'user_id': user_details['user_id'],
|
||||
'friendly_name': user_details['friendly_name'],
|
||||
'player': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'title'),
|
||||
'platform': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
|
||||
'machine_id': machine_id,
|
||||
'state': helpers.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
|
||||
'grandparent_title': helpers.get_xml_attr(session, 'grandparentTitle'),
|
||||
'parent_title': helpers.get_xml_attr(session, 'parentTitle'),
|
||||
|
|
|
@ -952,4 +952,4 @@ class WebInterface(object):
|
|||
cherrypy.response.headers['Content-type'] = 'application/json'
|
||||
return result
|
||||
else:
|
||||
logger.warn('Unable to retrieve data.')
|
||||
logger.warn('Unable to retrieve data.')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue