Added restart and shutdown links in settings.

No longer exposing passwords in html forms.
Removed some old headphones js.
Minor styling adjustments.
Current activity on home screen now works.
Some history table fixes and additions.
Info screen for video items now works.
This commit is contained in:
Tim 2015-06-16 17:35:52 +02:00
commit 04b290173c
16 changed files with 1163 additions and 257 deletions

View file

@ -25,6 +25,7 @@ _CONFIG_DEFINITIONS = {
'PMS_IP': (str, 'PMS', '127.0.0.1'),
'PMS_PORT': (int, 'PMS', 32400),
'PMS_PASSWORD': (str, 'PMS', ''),
'PMS_TOKEN': (str, 'PMS', ''),
'PMS_USERNAME': (str, 'PMS', ''),
'TIME_FORMAT': (str, 'General', 'HH:mm'),
'API_ENABLED': (int, 'General', 0),

View file

@ -26,6 +26,7 @@ import re
import os
import json
import xmltodict
import math
def multikeysort(items, columns):
@ -111,6 +112,12 @@ def convert_milliseconds(ms):
return minutes
def convert_milliseconds_to_minutes(ms):
seconds = float(ms) / 1000
minutes = round(seconds / 60, 0)
return math.trunc(minutes)
def convert_seconds(s):
@ -336,4 +343,16 @@ def convert_xml_to_json(xml):
def convert_xml_to_dict(xml):
o = xmltodict.parse(xml)
return o
return o
def get_percent(value1, value2):
value1 = cast_to_float(value1)
value2 = cast_to_float(value2)
if value1 != 0 and value2 != 0:
percent = (value1 / value2) * 100
else:
percent = 0
return math.trunc(percent)

112
plexpy/plextv.py Normal file
View file

@ -0,0 +1,112 @@
# 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/>.
from plexpy import logger, helpers, common, request
from xml.dom import minidom
from httplib import HTTPSConnection
from urlparse import parse_qsl
from urllib import urlencode
from pynma import pynma
import base64
import cherrypy
import urllib
import urllib2
import plexpy
import os.path
import subprocess
import json
class PlexTV(object):
"""
Plex.tv authentication
"""
def __init__(self, username='', password=''):
self.username = username
self.password = password
def get_plex_auth(self):
http_handler = HTTPSConnection("plex.tv")
base64string = base64.encodestring('%s:%s' % (self.username, self.password)).replace('\n', '')
http_handler.request("POST",
'/users/sign_in.xml',
headers={'Content-Type': 'application/xml; charset=utf-8',
'Content-Length': '0',
'X-Plex-Device-Name': 'PlexPy',
'X-Plex-Product': 'PlexPy',
'X-Plex-Version': 'v0.1 dev',
'X-Plex-Client-Identifier': 'f0864d3531d75b19fa9204eaea456515e2502017',
'Authorization': 'Basic %s' % base64string + ":"
})
response = http_handler.getresponse()
request_status = response.status
request_body = response.read()
logger.debug(u"Plex.tv response status: %r" % request_status)
logger.debug(u"Plex.tv response headers: %r" % response.getheaders())
logger.debug(u"Plex.tv content type: %r" % response.getheader('content-type'))
logger.debug(u"Plex.tv response body: %r" % request_body)
if request_status == 201:
logger.info(u"Plex.tv connection successful.")
return request_body
elif request_status >= 400 and request_status < 500:
logger.info(u"Plex.tv request failed: %s" % response.reason)
return False
else:
logger.info(u"Plex.tv notification failed serverside.")
return False
def get_token(self):
plextv_response = self.get_plex_auth()
if plextv_response:
try:
xml_parse = minidom.parseString(helpers.latinToAscii(plextv_response))
except IOError, e:
logger.warn("Error parsing XML for Plex.tv token: %s" % e)
return False
xml_head = xml_parse.getElementsByTagName('user')
if not xml_head:
logger.warn("Error parsing XML for Plex.tv token: %s" % e)
return False
auth_token = xml_head[0].getAttribute('authenticationToken')
return auth_token
else:
return False
def get_plextv_user_data(self):
plextv_response = self.get_plex_auth()
if plextv_response:
try:
user_data = helpers.convert_xml_to_dict(plextv_response)
except IOError, e:
logger.warn("Error parsing XML for Plex.tv user data: %s" % e)
return False
return user_data
else:
return False

466
plexpy/pmsconnect.py Normal file
View file

@ -0,0 +1,466 @@
# 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/>.
from plexpy import logger, helpers, common, request
from xml.dom import minidom
from httplib import HTTPSConnection
from httplib import HTTPConnection
from urlparse import parse_qsl
from urllib import urlencode
from pynma import pynma
import base64
import cherrypy
import urllib
import urllib2
import plexpy
import os.path
import subprocess
import json
class PmsConnect(object):
"""
Retrieve data from Plex Server
"""
def __init__(self):
self.host = plexpy.CONFIG.PMS_IP
self.port = str(plexpy.CONFIG.PMS_PORT)
self.token = plexpy.CONFIG.PMS_TOKEN
"""
Return base url of Plex Server.
Output: string
"""
def get_base_url(self):
if self.host != '' and self.port != '':
base_url = 'http://' + self.host + ':' + self.port
return base_url
else:
return False
"""
Return current sessions.
Optional parameters: output_format { dict, json }
Output: array
"""
def get_sessions(self, output_format=''):
url_command = '/status/sessions'
http_handler = HTTPConnection(self.host, self.port, timeout=10)
http_handler.request("GET", url_command + '?X-Plex-Token=' + self.token)
response = http_handler.getresponse()
request_status = response.status
request_content = response.read()
if output_format == 'dict':
output = helpers.convert_xml_to_dict(request_content)
elif output_format == 'json':
output = helpers.convert_xml_to_json(request_content)
else:
output = request_content
return output
"""
Return metadata for request item.
Parameters required: rating_key { Plex ratingKey }
Optional parameters: output_format { dict, json }
Output: array
"""
def get_metadata(self, rating_key='', output_format=''):
url_command = '/library/metadata/' + rating_key
http_handler = HTTPConnection(self.host, self.port, timeout=10)
http_handler.request("GET", url_command + '?X-Plex-Token=' + self.token)
response = http_handler.getresponse()
request_status = response.status
request_content = response.read()
if output_format == 'dict':
output = helpers.convert_xml_to_dict(request_content)
elif output_format == 'json':
output = helpers.convert_xml_to_json(request_content)
else:
output = request_content
return output
"""
Return processed and validated metadata list for requested item.
Parameters required: rating_key { Plex ratingKey }
Output: array
"""
def get_metadata_details(self, rating_key=''):
metadata = self.get_metadata(rating_key)
metadata_list = []
try:
xml_parse = minidom.parseString(metadata)
except Exception, e:
logger.warn("Error parsing XML for Plex metadata: %s" % e)
return None
except:
logger.warn("Error parsing XML for Plex metadata.")
return None
xml_head = xml_parse.getElementsByTagName('MediaContainer')
if not xml_head:
logger.warn("Error parsing XML for Plex metadata.")
return None
for a in xml_head:
if a.getAttribute('size'):
if a.getAttribute('size') != '1':
metadata_list = {'metadata': None}
return metadata_list
if a.getElementsByTagName('Directory'):
metadata_main = a.getElementsByTagName('Directory')[0]
metadata_type = self.get_xml_attr(metadata_main, 'type')
logger.debug(u"Metadata type: %s" % metadata_type)
elif a.getElementsByTagName('Video'):
metadata_main = a.getElementsByTagName('Video')[0]
metadata_type = self.get_xml_attr(metadata_main, 'type')
logger.debug(u"Metadata type: %s" % metadata_type)
else:
logger.debug(u"Metadata failed")
genres = []
actors = []
writers = []
directors = []
if metadata_main.getElementsByTagName('Genre'):
for genre in metadata_main.getElementsByTagName('Genre'):
genres.append(self.get_xml_attr(genre, 'tag'))
logger.debug(u"Metadata genre: %s" % self.get_xml_attr(genre, 'tag'))
if metadata_main.getElementsByTagName('Role'):
for actor in metadata_main.getElementsByTagName('Role'):
actors.append(self.get_xml_attr(actor, 'tag'))
logger.debug(u"Metadata actor: %s" % self.get_xml_attr(actor, 'tag'))
if metadata_main.getElementsByTagName('Writer'):
for writer in metadata_main.getElementsByTagName('Writer'):
writers.append(self.get_xml_attr(writer, 'tag'))
logger.debug(u"Metadata genre: %s" % self.get_xml_attr(writer, 'tag'))
if metadata_main.getElementsByTagName('Director'):
for director in metadata_main.getElementsByTagName('Director'):
directors.append(self.get_xml_attr(director, 'tag'))
logger.debug(u"Metadata actor: %s" % self.get_xml_attr(director, 'tag'))
if metadata_type == 'show':
metadata = {'type': metadata_type,
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
'studio': self.get_xml_attr(metadata_main, 'studio'),
'title': self.get_xml_attr(metadata_main, 'title'),
'contentRating': self.get_xml_attr(metadata_main, 'contentRating'),
'summary': self.get_xml_attr(metadata_main, 'summary'),
'rating': self.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.convert_milliseconds_to_minutes(self.get_xml_attr(metadata_main, 'duration')),
'year': self.get_xml_attr(metadata_main, 'year'),
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
'art': self.get_xml_attr(metadata_main, 'art'),
'originallyAvailableAt': self.get_xml_attr(metadata_main, 'originallyAvailableAt'),
'writers': writers,
'directors': directors,
'genres': genres,
'actors': actors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'episode':
metadata = {'type': metadata_type,
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
'grandparentTitle': self.get_xml_attr(metadata_main, 'grandparentTitle'),
'parentIndex': self.get_xml_attr(metadata_main, 'parentIndex'),
'index': self.get_xml_attr(metadata_main, 'index'),
'title': self.get_xml_attr(metadata_main, 'title'),
'contentRating': self.get_xml_attr(metadata_main, 'contentRating'),
'summary': self.get_xml_attr(metadata_main, 'summary'),
'duration': helpers.convert_milliseconds_to_minutes(self.get_xml_attr(metadata_main, 'duration')),
'year': self.get_xml_attr(metadata_main, 'year'),
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
'parentThumb': self.get_xml_attr(metadata_main, 'parentThumb'),
'art': self.get_xml_attr(metadata_main, 'art'),
'originallyAvailableAt': self.get_xml_attr(metadata_main, 'originallyAvailableAt'),
'writers': writers,
'directors': directors,
'genres': genres,
'actors': actors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'movie':
metadata = {'type': metadata_type,
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
'studio': self.get_xml_attr(metadata_main, 'studio'),
'title': self.get_xml_attr(metadata_main, 'title'),
'contentRating': self.get_xml_attr(metadata_main, 'contentRating'),
'summary': self.get_xml_attr(metadata_main, 'summary'),
'rating': self.get_xml_attr(metadata_main, 'rating'),
'duration': helpers.convert_milliseconds_to_minutes(self.get_xml_attr(metadata_main, 'duration')),
'year': self.get_xml_attr(metadata_main, 'year'),
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
'art': self.get_xml_attr(metadata_main, 'art'),
'originallyAvailableAt': self.get_xml_attr(metadata_main, 'originallyAvailableAt'),
'genres': genres,
'actors': actors,
'writers': writers,
'directors': directors
}
metadata_list = {'metadata': metadata}
elif metadata_type == 'season':
metadata = {'type': metadata_type,
'ratingKey': self.get_xml_attr(metadata_main, 'ratingKey'),
'parentTitle': self.get_xml_attr(metadata_main, 'parentTitle'),
'index': self.get_xml_attr(metadata_main, 'index'),
'title': self.get_xml_attr(metadata_main, 'title'),
'thumb': self.get_xml_attr(metadata_main, 'thumb'),
'art': self.get_xml_attr(metadata_main, 'art'),
}
metadata_list = {'metadata': metadata}
else:
return None
return metadata_list
"""
Validate xml keys to make sure they exist and return their attribute value, return blank value is none found
"""
def get_xml_attr(self, xml_key, attribute, return_bool=False, default_return=''):
if xml_key.getAttribute(attribute):
if return_bool:
return True
else:
return xml_key.getAttribute(attribute)
else:
if return_bool:
return False
else:
return default_return
"""
Return processed and validated session list.
Output: array
"""
def get_current_activity(self):
session_data = self.get_sessions()
session_list = []
try:
xml_parse = minidom.parseString(session_data)
except Exception, e:
logger.warn("Error parsing XML for Plex session data: %s" % e)
return None
except:
logger.warn("Error parsing XML for Plex session data.")
return None
xml_head = xml_parse.getElementsByTagName('MediaContainer')
if not xml_head:
logger.warn("Error parsing XML for Plex session data.")
return None
for a in xml_head:
if a.getAttribute('size'):
if a.getAttribute('size') == '0':
logger.debug(u"No active sessions.")
session_list = {'stream_count': '0',
'sessions': []
}
return session_list
if a.getElementsByTagName('Track'):
session_data = a.getElementsByTagName('Track')
session_type = 'track'
logger.debug(u"Track session active.")
for session in session_data:
session_output = self.get_session_each(session_type, session)
session_list.append(session_output)
if a.getElementsByTagName('Video'):
session_data = a.getElementsByTagName('Video')
session_type = 'video'
logger.debug(u"Video session active.")
for session in session_data:
session_output = self.get_session_each(session_type, session)
session_list.append(session_output)
output = {'stream_count': self.get_xml_attr(xml_head[0], 'size'),
'sessions': session_list
}
return output
"""
Return selected data from current sessions.
This function processes and validates session data
Parameters required: stream_type { track or video }
session { the session dictionary }
Output: dict
"""
def get_session_each(self, stream_type='', session=None):
session_output = None
if stream_type == 'track':
if session.getElementsByTagName('TranscodeSession'):
transcode_session = session.getElementsByTagName('TranscodeSession')[0]
audio_decision = self.get_xml_attr(transcode_session, 'audioDecision')
audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
duration = self.get_xml_attr(transcode_session, 'duration')
progress = self.get_xml_attr(transcode_session, 'viewOffset')
else:
media_info = session.getElementsByTagName('Media')[0]
audio_decision = 'direct play'
audio_channels = self.get_xml_attr(media_info, 'audioChannels')
audio_codec = self.get_xml_attr(media_info, 'audioCodec')
duration = self.get_xml_attr(media_info, 'duration')
progress = self.get_xml_attr(session, 'viewOffset')
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
'parentThumb': self.get_xml_attr(session, 'parentThumb'),
'thumb': self.get_xml_attr(session, 'thumb'),
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
'artist': self.get_xml_attr(session, 'grandparentTitle'),
'album': self.get_xml_attr(session, 'parentTitle'),
'track': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
'audioChannels': audio_channels,
'audioCodec': audio_codec,
'duration': duration,
'progress': progress,
'progressPercent': str(helpers.get_percent(progress, duration)),
'type': 'track'
}
elif stream_type == 'video':
if session.getElementsByTagName('TranscodeSession'):
transcode_session = session.getElementsByTagName('TranscodeSession')[0]
audio_decision = self.get_xml_attr(transcode_session, 'audioDecision')
audio_channels = self.get_xml_attr(transcode_session, 'audioChannels')
audio_codec = self.get_xml_attr(transcode_session, 'audioCodec')
video_decision = self.get_xml_attr(transcode_session, 'videoDecision')
video_codec = self.get_xml_attr(transcode_session, 'videoCodec')
width = self.get_xml_attr(transcode_session, 'width')
height = self.get_xml_attr(transcode_session, 'height')
duration = self.get_xml_attr(session, 'duration')
progress = self.get_xml_attr(session, 'viewOffset')
else:
media_info = session.getElementsByTagName('Media')[0]
audio_decision = 'direct play'
audio_channels = self.get_xml_attr(media_info, 'audioChannels')
audio_codec = self.get_xml_attr(media_info, 'audioCodec')
video_decision = 'direct play'
video_codec = self.get_xml_attr(media_info, 'videoCodec')
width = self.get_xml_attr(media_info, 'width')
height = self.get_xml_attr(media_info, 'height')
duration = self.get_xml_attr(media_info, 'duration')
progress = self.get_xml_attr(session, 'viewOffset')
if self.get_xml_attr(session, 'type') == 'episode':
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
'art': self.get_xml_attr(session, 'art'),
'thumb': self.get_xml_attr(session, 'thumb'),
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
'grandparentTitle': self.get_xml_attr(session, 'grandparentTitle'),
'title': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
'audioChannels': audio_channels,
'audioCodec': audio_codec,
'videoDecision': video_decision,
'videoCodec': video_codec,
'height': height,
'width': width,
'duration': duration,
'progress': progress,
'progressPercent': str(helpers.get_percent(progress, duration)),
'type': self.get_xml_attr(session, 'type')
}
elif self.get_xml_attr(session, 'type') == 'movie':
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
'art': self.get_xml_attr(session, 'art'),
'thumb': self.get_xml_attr(session, 'thumb'),
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
'player': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'platform'),
'state': self.get_xml_attr(session.getElementsByTagName('Player')[0], 'state'),
'title': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
'audioChannels': audio_channels,
'audioCodec': audio_codec,
'videoDecision': video_decision,
'videoCodec': video_codec,
'height': height,
'width': width,
'duration': duration,
'progress': progress,
'progressPercent': str(helpers.get_percent(progress, duration)),
'type': self.get_xml_attr(session, 'type')
}
else:
logger.warn(u"No known stream types found in session list.")
return session_output
"""
Return image data as array.
Array contains the image content type and image binary
Parameters required: img { Plex image location }
Optional parameters: width { the image width }
height { the image height }
Output: array
"""
def get_image(self, img, width='0', height='0'):
if img != '':
try:
http_handler = HTTPConnection(self.host, self.port, timeout=10)
if width != '0' and height != '0':
image_path = '/photo/:/transcode?url=http://127.0.0.1:' + self.port + img + '&width=' + width + '&height=' + height
else:
image_path = '/photo/:/transcode?url=http://127.0.0.1:' + self.port + img
http_handler.request("GET", image_path + '&X-Plex-Token=' + self.token)
response = http_handler.getresponse()
request_status = response.status
request_content = response.read()
request_content_type = response.getheader('content-type')
logger.debug(u"Content type: %r" % request_content_type)
except IOError, e:
logger.warn(u"Failed to retrieve image. %s" % e)
return None
if request_status == 200:
return [request_content_type, request_content]
else:
logger.warn(u"Failed to retrieve image. Status code %r" % request_status)
return None
return None

View file

@ -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, db, helpers, notifiers
from plexpy import logger, db, helpers, notifiers, plextv, pmsconnect
from plexpy.helpers import checked, radio, today, cleanName
from xml.dom import minidom
@ -161,11 +161,22 @@ class WebInterface(object):
interface_list = [name for name in os.listdir(interface_dir) if
os.path.isdir(os.path.join(interface_dir, name))]
# Initialise blank passwords so we do not expose them in the html forms
# but users are still able to clear them
if plexpy.CONFIG.HTTP_PASSWORD != '':
http_password = ' '
else:
http_password = ''
if plexpy.CONFIG.PMS_PASSWORD != '':
pms_password = ' '
else:
pms_password = ''
config = {
"http_host": plexpy.CONFIG.HTTP_HOST,
"http_username": plexpy.CONFIG.HTTP_USERNAME,
"http_port": plexpy.CONFIG.HTTP_PORT,
"http_password": plexpy.CONFIG.HTTP_PASSWORD,
"http_password": http_password,
"launch_browser": checked(plexpy.CONFIG.LAUNCH_BROWSER),
"enable_https": checked(plexpy.CONFIG.ENABLE_HTTPS),
"https_cert": plexpy.CONFIG.HTTPS_CERT,
@ -228,7 +239,7 @@ class WebInterface(object):
"pms_ip": plexpy.CONFIG.PMS_IP,
"pms_port": plexpy.CONFIG.PMS_PORT,
"pms_username": plexpy.CONFIG.PMS_USERNAME,
"pms_password": plexpy.CONFIG.PMS_PASSWORD,
"pms_password": pms_password,
"plexwatch_database": plexpy.CONFIG.PLEXWATCH_DATABASE,
"date_format": plexpy.CONFIG.DATE_FORMAT,
"time_format": plexpy.CONFIG.TIME_FORMAT,
@ -257,6 +268,30 @@ class WebInterface(object):
# checked items should be zero or one. if they were not sent then the item was not checked
kwargs[checked_config] = 0
# Write Plex token to the config
if (not plexpy.CONFIG.PMS_TOKEN or plexpy.CONFIG.PMS_TOKEN == '' \
or kwargs['pms_username'] != plexpy.CONFIG.PMS_USERNAME) \
and (kwargs['pms_username'] != '' or kwargs['pms_password'] != ''):
plex_tv = plextv.PlexTV(kwargs['pms_username'], kwargs['pms_password'])
token = plex_tv.get_token()
if token:
kwargs['pms_token'] = token
logger.info('Plex.tv token sucessfully written to config.')
else:
logger.warn('Unable to write Plex.tv token to config.')
# Clear Plex token if username or password set to blank
if kwargs['pms_username'] == '' or kwargs['pms_password'] == '':
kwargs['pms_token'] = ''
# If passwords exists in config, do not overwrite when blank value received
if kwargs['http_password'] == ' ' and plexpy.CONFIG.HTTP_PASSWORD != '':
kwargs['http_password'] = plexpy.CONFIG.HTTP_PASSWORD
if kwargs['pms_password'] == ' ' and plexpy.CONFIG.PMS_PASSWORD != '':
kwargs['pms_password'] = plexpy.CONFIG.PMS_PASSWORD
for plain_config, use_config in [(x[4:], x) for x in kwargs if x.startswith('use_')]:
# the use prefix is fairly nice in the html, but does not match the actual config
kwargs[plain_config] = kwargs[use_config]
@ -325,7 +360,7 @@ class WebInterface(object):
sortcolumn = 'duration'
if search_value == "":
query = 'SELECT id, time, user, platform, ip_address, title, time, paused_counter, stopped, xml, \
query = 'SELECT id, time, user, platform, ip_address, title, time, paused_counter, stopped, ratingKey, xml, \
round((julianday(datetime(stopped, "unixepoch", "localtime")) - \
julianday(datetime(time, "unixepoch", "localtime"))) * 86400) - \
(case when paused_counter is null then 0 else paused_counter end) as duration \
@ -333,7 +368,7 @@ class WebInterface(object):
filtered = myDB.select(query)
totalcount = len(filtered)
else:
query = 'SELECT id, time, user, platform, ip_address, title, time, paused_counter, stopped, xml, \
query = 'SELECT id, time, user, platform, ip_address, title, time, paused_counter, stopped, ratingKey, xml, \
round((julianday(datetime(stopped, "unixepoch", "localtime")) - \
julianday(datetime(time, "unixepoch", "localtime"))) * 86400) - \
(case when paused_counter is null then 0 else paused_counter end) as duration \
@ -354,6 +389,7 @@ class WebInterface(object):
"started": item["time"],
"paused": item["paused_counter"],
"stopped": item["stopped"],
"rating_key": item["ratingKey"],
"duration": item["duration"],
"percent_complete": 0,
}
@ -486,3 +522,111 @@ class WebInterface(object):
logger.warn(msg)
return msg
@cherrypy.expose
def get_pms_token(self):
token = plextv.PlexTV()
result = token.get_token()
if result:
return result
else:
logger.warn('Unable to retrieve Plex.tv token.')
return False
@cherrypy.expose
def get_pms_sessions_json(self, **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_sessions('json')
if result:
cherrypy.response.headers['Content-type'] = 'application/json'
return result
else:
logger.warn('Unable to retrieve data.')
return False
@cherrypy.expose
def get_current_activity(self, **kwargs):
try:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_current_activity()
except:
return serve_template(templatename="current_activity.html", activity=None)
if result:
return serve_template(templatename="current_activity.html", activity=result)
else:
return serve_template(templatename="current_activity.html", activity=None)
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def get_current_activity_header(self, **kwargs):
try:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_current_activity()
except IOError, e:
return serve_template(templatename="current_activity_header.html", activity=None)
if result:
return serve_template(templatename="current_activity_header.html", activity=result['stream_count'])
else:
return serve_template(templatename="current_activity_header.html", activity=None)
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def pms_image_proxy(self, img='', width='0', height='0', **kwargs):
if img != '':
try:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_image(img, width, height)
logger.info('Image proxy queried. Content type is %s' % result[0])
cherrypy.response.headers['Content-type'] = result[0]
return result[1]
except:
logger.warn('Image proxy queried but errors occured.')
return 'No image'
else:
logger.warn('Image proxy queried but no parameters received.')
return 'No image'
@cherrypy.expose
def info(self, rating_key='', **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_metadata_details(rating_key)
if result:
return serve_template(templatename="info.html", metadata=result['metadata'], title="Info")
else:
return serve_template(templatename="info.html", metadata='', title="Info")
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def get_metadata_json(self, rating_key='', **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_metadata(rating_key, 'json')
if result:
cherrypy.response.headers['Content-type'] = 'application/json'
return result
else:
logger.warn('Unable to retrieve data.')
@cherrypy.expose
def get_metadata_xml(self, rating_key='', **kwargs):
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_metadata(rating_key)
if result:
cherrypy.response.headers['Content-type'] = 'application/xml'
return result
else:
logger.warn('Unable to retrieve data.')