diff --git a/data/interfaces/default/current_activity.html b/data/interfaces/default/current_activity.html
index 73fd99d8..1b09eb4b 100644
--- a/data/interfaces/default/current_activity.html
+++ b/data/interfaces/default/current_activity.html
@@ -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
% endfor
diff --git a/plexpy/log_reader.py b/plexpy/log_reader.py
index cd386ee8..a9f2ee33 100644
--- a/plexpy/log_reader.py
+++ b/plexpy/log_reader.py
@@ -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):
diff --git a/plexpy/monitor.py b/plexpy/monitor.py
index 2d402702..d5f7aac4 100644
--- a/plexpy/monitor.py
+++ b/plexpy/monitor.py
@@ -13,7 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see .
-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
diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py
index 91ae25a6..c62fb558 100644
--- a/plexpy/pmsconnect.py
+++ b/plexpy/pmsconnect.py
@@ -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'),
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index 1c9288fb..6e095ba3 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -952,4 +952,4 @@ class WebInterface(object):
cherrypy.response.headers['Content-type'] = 'application/json'
return result
else:
- logger.warn('Unable to retrieve data.')
\ No newline at end of file
+ logger.warn('Unable to retrieve data.')