% if a['type'] == 'track':
- Artist:
${a['artist']}
+ Artist:
${a['grandparentTitle']}
- Album:
${a['album']}
+ Album:
${a['parentTitle']}
% endif
% if a['state'] == 'playing':
diff --git a/data/interfaces/default/js/tables/sync_table.js b/data/interfaces/default/js/tables/sync_table.js
index d0c7ba1e..bf2ca84b 100644
--- a/data/interfaces/default/js/tables/sync_table.js
+++ b/data/interfaces/default/js/tables/sync_table.js
@@ -28,7 +28,8 @@ sync_table_options = {
} else {
$(td).html(cellData.toProperCase());
}
- }
+ },
+ "className": "no-wrap"
},
{
"targets": [1],
@@ -37,7 +38,8 @@ sync_table_options = {
if (cellData !== '') {
$(td).html('
' + cellData + '');
}
- }
+ },
+ "className": "no-wrap"
},
{
"targets": [2],
@@ -57,15 +59,18 @@ sync_table_options = {
"data": "metadata_type",
"render": function ( data, type, full ) {
return data.toProperCase();
- }
+ },
+ "className": "no-wrap"
},
{
"targets": [4],
- "data": "device_name"
+ "data": "device_name",
+ "className": "no-wrap"
},
{
"targets": [5],
- "data": "platform"
+ "data": "platform",
+ "className": "no-wrap"
},
{
"targets": [6],
@@ -77,19 +82,23 @@ sync_table_options = {
} else {
$(td).html('0MB');
}
- }
+ },
+ "className": "no-wrap"
},
{
"targets": [7],
- "data": "item_count"
+ "data": "item_count",
+ "className": "no-wrap"
},
{
"targets": [8],
- "data": "item_complete_count"
+ "data": "item_complete_count",
+ "className": "no-wrap"
},
{
"targets": [9],
- "data": "item_downloaded_count"
+ "data": "item_downloaded_count",
+ "className": "no-wrap"
},
{
"targets": [10],
@@ -100,7 +109,8 @@ sync_table_options = {
} else {
$(td).html('
0%');
}
- }
+ },
+ "className": "no-wrap"
}
],
"drawCallback": function (settings) {
diff --git a/data/interfaces/default/sync.html b/data/interfaces/default/sync.html
index 51b81249..da6d9da2 100644
--- a/data/interfaces/default/sync.html
+++ b/data/interfaces/default/sync.html
@@ -33,17 +33,17 @@ from plexpy import helpers
- State |
- Username |
- Title |
- Type |
- Device |
- Platform |
- Total Size |
- Total Items |
- Converted |
- Downloaded |
- Complete |
+ State |
+ Username |
+ Title |
+ Type |
+ Device |
+ Platform |
+ Total Size |
+ Total Items |
+ Converted |
+ Downloaded |
+ Complete |
diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html
index d640eef2..c9f005a2 100644
--- a/data/interfaces/default/user.html
+++ b/data/interfaces/default/user.html
@@ -222,17 +222,17 @@ from plexpy import helpers
- State |
- Username |
- Title |
- Type |
- Device |
- Platform |
- Total Size |
- Total Items |
- Converted |
- Downloaded |
- Complete |
+ State |
+ Username |
+ Title |
+ Type |
+ Device |
+ Platform |
+ Total Size |
+ Total Items |
+ Converted |
+ Downloaded |
+ Complete |
diff --git a/lib/pynma/pynma.py b/lib/pynma/pynma.py
index 037145c8..2bbe3f42 100644
--- a/lib/pynma/pynma.py
+++ b/lib/pynma/pynma.py
@@ -6,7 +6,7 @@ from urllib import urlencode
__version__ = "0.1"
-API_SERVER = 'nma.usk.bz'
+API_SERVER = 'www.notifymyandroid.com'
ADD_PATH = '/publicapi/notify'
USER_AGENT="PyNMA/v%s"%__version__
diff --git a/plexpy/__init__.py b/plexpy/__init__.py
index 58b3b2c2..5fccea03 100644
--- a/plexpy/__init__.py
+++ b/plexpy/__init__.py
@@ -29,7 +29,7 @@ import uuid
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.triggers.interval import IntervalTrigger
-from plexpy import versioncheck, logger
+from plexpy import versioncheck, logger, monitor
import plexpy.config
PROG_DIR = None
@@ -256,6 +256,9 @@ def initialize_scheduler():
minutes = 0
schedule_job(versioncheck.checkGithub, 'Check GitHub for updates', hours=0, minutes=minutes)
+ if CONFIG.PMS_IP:
+ schedule_job(monitor.check_active_sessions, 'Check for active sessions', hours=0, minutes=0, seconds=60)
+
# Start scheduler
if start_jobs and len(SCHED.get_jobs()):
try:
@@ -267,7 +270,7 @@ def initialize_scheduler():
#SCHED.print_jobs()
-def schedule_job(function, name, hours=0, minutes=0):
+def schedule_job(function, name, hours=0, minutes=0, seconds=0):
"""
Start scheduled job if starting or restarting plexpy.
Reschedule job if Interval Settings have changed.
@@ -277,16 +280,16 @@ def schedule_job(function, name, hours=0, minutes=0):
job = SCHED.get_job(name)
if job:
- if hours == 0 and minutes == 0:
+ if hours == 0 and minutes == 0 and seconds == 0:
SCHED.remove_job(name)
logger.info("Removed background task: %s", name)
elif job.trigger.interval != datetime.timedelta(hours=hours, minutes=minutes):
SCHED.reschedule_job(name, trigger=IntervalTrigger(
- hours=hours, minutes=minutes))
+ hours=hours, minutes=minutes, seconds=seconds))
logger.info("Re-scheduled background task: %s", name)
- elif hours > 0 or minutes > 0:
+ elif hours > 0 or minutes > 0 or seconds > 0:
SCHED.add_job(function, id=name, trigger=IntervalTrigger(
- hours=hours, minutes=minutes))
+ hours=hours, minutes=minutes, seconds=seconds))
logger.info("Scheduled background task: %s", name)
@@ -339,11 +342,23 @@ def dbcheck():
conn.commit()
c.close()
+ conn_db = sqlite3.connect(DB_FILE)
+ c_db = conn_db.cursor()
+ c_db.execute(
+ 'CREATE TABLE IF NOT EXISTS sessions (id INTEGER PRIMARY KEY AUTOINCREMENT, '
+ 'session_key INTEGER, rating_key INTEGER, media_type TEXT)'
+ )
+ conn_db.commit()
+ c_db.close()
def shutdown(restart=False, update=False):
cherrypy.engine.exit()
SCHED.shutdown(wait=False)
+ # Clear any sessions in the db - Not sure yet if we should do this. More testing required
+ # logger.debug(u'Clearing Plex sessions.')
+ # monitor.drop_session_db()
+
CONFIG.write()
if not restart and not update:
diff --git a/plexpy/config.py b/plexpy/config.py
index fb9854ad..ce8430d8 100644
--- a/plexpy/config.py
+++ b/plexpy/config.py
@@ -69,10 +69,7 @@ _CONFIG_DEFINITIONS = {
'INTERFACE': (str, 'General', 'default'),
'JOURNAL_MODE': (str, 'Advanced', 'wal'),
'LAUNCH_BROWSER': (int, 'General', 1),
- 'LMS_ENABLED': (int, 'LMS', 0),
- 'LMS_HOST': (str, 'LMS', ''),
'LOG_DIR': (str, 'General', ''),
- 'MPC_ENABLED': (bool_int, 'MPC', False),
'NMA_APIKEY': (str, 'NMA', ''),
'NMA_ENABLED': (int, 'NMA', 0),
'NMA_PRIORITY': (int, 'NMA', 0),
@@ -94,11 +91,6 @@ _CONFIG_DEFINITIONS = {
'PUSHOVER_ENABLED': (int, 'Pushover', 0),
'PUSHOVER_KEYS': (str, 'Pushover', ''),
'PUSHOVER_PRIORITY': (int, 'Pushover', 0),
- 'SUBSONIC_ENABLED': (int, 'Subsonic', 0),
- 'SUBSONIC_HOST': (str, 'Subsonic', ''),
- 'SUBSONIC_PASSWORD': (str, 'Subsonic', ''),
- 'SUBSONIC_USERNAME': (str, 'Subsonic', ''),
- 'SYNOINDEX_ENABLED': (int, 'Synoindex', 0),
'TWITTER_ENABLED': (int, 'Twitter', 0),
'TWITTER_PASSWORD': (str, 'Twitter', ''),
'TWITTER_PREFIX': (str, 'Twitter', 'Headphones'),
diff --git a/plexpy/monitor.py b/plexpy/monitor.py
new file mode 100644
index 00000000..348bcec9
--- /dev/null
+++ b/plexpy/monitor.py
@@ -0,0 +1,188 @@
+# 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 .
+
+from plexpy import logger, helpers, plexwatch, pmsconnect, notification_handler, config
+
+from xml.dom import minidom
+from httplib import HTTPSConnection
+from httplib import HTTPConnection
+
+import os
+import sqlite3
+import threading
+import plexpy
+
+monitor_lock = threading.Lock()
+
+def check_active_sessions():
+
+ with monitor_lock:
+ pms_connect = pmsconnect.PmsConnect()
+ session_list = pms_connect.get_current_activity()
+ monitor_db = MonitorDatabase()
+
+ if session_list['stream_count'] != '0':
+ media_container = session_list['sessions']
+ active_streams = []
+
+ for session in media_container:
+ session_key = session['sessionKey']
+ rating_key = session['ratingKey']
+ media_type = session['type']
+ friendly_name = session['friendly_name']
+ platform = session['player']
+ title = session['title']
+ parent_title = session['parentTitle']
+ grandparent_title = session['grandparentTitle']
+
+ write_session = monitor_db.write_session_key(session_key, rating_key, media_type)
+ if write_session == 'insert':
+ # User started playing a stream :: We notify here
+ if media_type == 'track' or media_type == 'episode':
+ item_title = grandparent_title + ' - ' + title
+ elif media_type == 'movie':
+ item_title = title
+ else:
+ item_title = title
+ logger.info('%s (%s) starting playing %s' % (friendly_name, platform, item_title))
+ pushmessage = '%s (%s) starting playing %s' % (friendly_name, platform, item_title)
+ notification_handler.push_nofitications(pushmessage, 'PlexPy Playback started', 'Playback Started')
+
+ keys = {'session_key': session_key,
+ 'rating_key': rating_key}
+ active_streams.append(keys)
+
+ # Check our temp table for what we must do with the new stream
+ db_streams = monitor_db.select('SELECT session_key, rating_key, media_type FROM sessions')
+ for result in db_streams:
+ if any(d['session_key'] == str(result[0]) for d in active_streams):
+ # The user's session is still active
+ pass
+ if any(d['rating_key'] == str(result[1]) for d in active_streams):
+ # The user is still playing the same media item
+ # Here we can check the play states
+ pass
+ else:
+ # The user has stopped playing a stream
+ monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?', [result[0], result[1]])
+ else:
+ # The user's session is no longer active
+ monitor_db.action('DELETE FROM sessions WHERE session_key = ?', [result[0]])
+ else:
+ # No sessions exist
+ # monitor_db.action('DELETE FROM sessions')
+ pass
+
+def drop_session_db():
+ monitor_db = MonitorDatabase()
+ monitor_db.action('DROP TABLE sessions')
+
+def db_filename(filename="plexpy.db"):
+
+ return os.path.join(plexpy.DATA_DIR, filename)
+
+def get_cache_size():
+ # This will protect against typecasting problems produced by empty string and None settings
+ if not plexpy.CONFIG.CACHE_SIZEMB:
+ # sqlite will work with this (very slowly)
+ return 0
+ return int(plexpy.CONFIG.CACHE_SIZEMB)
+
+
+class MonitorDatabase(object):
+
+ def __init__(self, filename='plexpy.db'):
+ self.filename = filename
+ self.connection = sqlite3.connect(db_filename(filename), timeout=20)
+ # Don't wait for the disk to finish writing
+ self.connection.execute("PRAGMA synchronous = OFF")
+ # Journal disabled since we never do rollbacks
+ self.connection.execute("PRAGMA journal_mode = %s" % plexpy.CONFIG.JOURNAL_MODE)
+ # 64mb of cache memory, probably need to make it user configurable
+ self.connection.execute("PRAGMA cache_size=-%s" % (get_cache_size() * 1024))
+ self.connection.row_factory = sqlite3.Row
+
+ def action(self, query, args=None):
+
+ if query is None:
+ return
+
+ sql_result = None
+
+ try:
+ with self.connection as c:
+ if args is None:
+ sql_result = c.execute(query)
+ else:
+ sql_result = c.execute(query, args)
+
+ except sqlite3.OperationalError, e:
+ if "unable to open database file" in e.message or "database is locked" in e.message:
+ logger.warn('Database Error: %s', e)
+ else:
+ logger.error('Database error: %s', e)
+ raise
+
+ except sqlite3.DatabaseError, e:
+ logger.error('Fatal Error executing %s :: %s', query, e)
+ raise
+
+ return sql_result
+
+ def write_session_key(self, session_key=None, rating_key=None, media_type=None):
+
+ values = {'rating_key': rating_key,
+ 'media_type': media_type}
+
+ keys = {'session_key': session_key,
+ 'rating_key': rating_key}
+
+ result = self.upsert('sessions', values, keys)
+ return result
+
+ def select(self, query, args=None):
+
+ sql_results = self.action(query, args).fetchall()
+
+ if sql_results is None or sql_results == [None]:
+ return []
+
+ return sql_results
+
+ def upsert(self, table_name, value_dict, key_dict):
+
+ trans_type = 'update'
+ changes_before = self.connection.total_changes
+
+ gen_params = lambda my_dict: [x + " = ?" for x in my_dict.keys()]
+
+ update_query = "UPDATE " + table_name + " SET " + ", ".join(gen_params(value_dict)) + \
+ " WHERE " + " AND ".join(gen_params(key_dict))
+
+ self.action(update_query, value_dict.values() + key_dict.values())
+
+ if self.connection.total_changes == changes_before:
+ trans_type = 'insert'
+ insert_query = (
+ "INSERT INTO " + table_name + " (" + ", ".join(value_dict.keys() + key_dict.keys()) + ")" +
+ " VALUES (" + ", ".join(["?"] * len(value_dict.keys() + key_dict.keys())) + ")"
+ )
+ try:
+ self.action(insert_query, value_dict.values() + key_dict.values())
+ except sqlite3.IntegrityError:
+ logger.info('Queries failed: %s and %s', update_query, insert_query)
+
+ # We want to know if it was an update or insert
+ return trans_type
diff --git a/plexpy/notification_handler.py b/plexpy/notification_handler.py
new file mode 100644
index 00000000..f1901699
--- /dev/null
+++ b/plexpy/notification_handler.py
@@ -0,0 +1,90 @@
+# 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 .
+
+from plexpy import logger, config, notifiers
+
+import plexpy
+
+
+def push_nofitications(push_message=None, subject=None, status_message=None):
+
+ if push_message:
+ if not subject:
+ subject = 'PlexPy'
+
+ if plexpy.CONFIG.GROWL_ENABLED:
+ logger.info(u"Growl request")
+ growl = notifiers.GROWL()
+ growl.notify(push_message, status_message)
+
+ if plexpy.CONFIG.PROWL_ENABLED:
+ logger.info(u"Prowl request")
+ prowl = notifiers.PROWL()
+ prowl.notify(push_message, status_message)
+
+ if plexpy.CONFIG.XBMC_ENABLED:
+ xbmc = notifiers.XBMC()
+ if plexpy.CONFIG.XBMC_NOTIFY:
+ xbmc.notify(subject, push_message)
+
+ if plexpy.CONFIG.PLEX_ENABLED:
+ plex = notifiers.Plex()
+ if plexpy.CONFIG.PLEX_NOTIFY:
+ plex.notify(subject, push_message)
+
+ if plexpy.CONFIG.NMA_ENABLED:
+ nma = notifiers.NMA()
+ nma.notify(subject, push_message)
+
+ if plexpy.CONFIG.PUSHALOT_ENABLED:
+ logger.info(u"Pushalot request")
+ pushalot = notifiers.PUSHALOT()
+ pushalot.notify(push_message, status_message)
+
+ if plexpy.CONFIG.PUSHOVER_ENABLED:
+ logger.info(u"Pushover request")
+ pushover = notifiers.PUSHOVER()
+ pushover.notify(push_message, status_message)
+
+ if plexpy.CONFIG.PUSHBULLET_ENABLED:
+ logger.info(u"PushBullet request")
+ pushbullet = notifiers.PUSHBULLET()
+ pushbullet.notify(push_message, status_message)
+
+ if plexpy.CONFIG.TWITTER_ENABLED:
+ logger.info(u"Sending Twitter notification")
+ twitter = notifiers.TwitterNotifier()
+ twitter.notify_download(push_message)
+
+ if plexpy.CONFIG.OSX_NOTIFY_ENABLED:
+ # TODO: Get thumb in notification
+ # from plexpy import cache
+ # c = cache.Cache()
+ # album_art = c.get_artwork_from_cache(None, release['AlbumID'])
+ logger.info(u"Sending OS X notification")
+ osx_notify = notifiers.OSX_NOTIFY()
+ osx_notify.notify(subject, push_message)
+
+ if plexpy.CONFIG.BOXCAR_ENABLED:
+ logger.info(u"Sending Boxcar2 notification")
+ boxcar = notifiers.BOXCAR()
+ boxcar.notify(subject, push_message)
+
+ if plexpy.CONFIG.EMAIL_ENABLED:
+ logger.info(u"Sending Email notification")
+ email = notifiers.Email()
+ email.notify(subject=subject, message=push_message)
+ else:
+ logger.warning('Notification requested but no message received.')
\ No newline at end of file
diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py
index 2edfaf8f..f375fc20 100644
--- a/plexpy/notifiers.py
+++ b/plexpy/notifiers.py
@@ -178,20 +178,6 @@ class PROWL(object):
self.notify('ZOMG Lazors Pewpewpew!', 'Test Message')
-
-class MPC(object):
- """
- MPC library update
- """
-
- def __init__(self):
-
- pass
-
- def notify(self):
- subprocess.call(["mpc", "update"])
-
-
class XBMC(object):
"""
XBMC notifications
@@ -225,25 +211,12 @@ class XBMC(object):
if response:
return response[0]['result']
- def update(self):
- # From what I read you can't update the music library on a per directory or per path basis
- # so need to update the whole thing
+ def notify(self, subject=None, message=None):
hosts = [x.strip() for x in self.hosts.split(',')]
- for host in hosts:
- logger.info('Sending library update command to XBMC @ ' + host)
- request = self._sendjson(host, 'AudioLibrary.Scan')
-
- if not request:
- logger.warn('Error sending update request to XBMC')
-
- def notify(self, artist, album, albumartpath):
-
- hosts = [x.strip() for x in self.hosts.split(',')]
-
- header = "PlexPy"
- message = "%s - %s added to your library" % (artist, album)
+ header = subject
+ message = message
time = "3000" # in ms
for host in hosts:
@@ -252,12 +225,12 @@ class XBMC(object):
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
if version < 12: #Eden
- notification = header + "," + message + "," + time + "," + albumartpath
+ notification = header + "," + message + "," + time
notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'}
request = self._sendhttp(host, notifycommand)
else: #Frodo
- params = {'title': header, 'message': message, 'displaytime': int(time), 'image': albumartpath}
+ params = {'title': header, 'message': message, 'displaytime': int(time)}
request = self._sendjson(host, 'GUI.ShowNotification', params)
if not request:
@@ -267,48 +240,6 @@ class XBMC(object):
logger.error('Error sending notification request to XBMC')
-class LMS(object):
- """
- Class for updating a Logitech Media Server
- """
-
- def __init__(self):
- self.hosts = plexpy.CONFIG.LMS_HOST
-
- def _sendjson(self, host):
- data = {'id': 1, 'method': 'slim.request', 'params': ["", ["rescan"]]}
- data = json.JSONEncoder().encode(data)
-
- content = {'Content-Type': 'application/json'}
-
- req = urllib2.Request(host + '/jsonrpc.js', data, content)
-
- try:
- handle = urllib2.urlopen(req)
- except Exception as e:
- logger.warn('Error opening LMS url: %s' % e)
- return
-
- response = json.JSONDecoder().decode(handle.read())
-
- try:
- return response['result']
- except:
- logger.warn('LMS returned error: %s' % response['error'])
- return response['error']
-
- def update(self):
-
- hosts = [x.strip() for x in self.hosts.split(',')]
-
- for host in hosts:
- logger.info('Sending library rescan command to LMS @ ' + host)
- request = self._sendjson(host)
-
- if request:
- logger.warn('Error sending rescan request to LMS')
-
-
class Plex(object):
def __init__(self):
@@ -344,48 +275,18 @@ class Plex(object):
return response
- def update(self):
-
- # From what I read you can't update the music library on a per directory or per path basis
- # so need to update the whole thing
-
- hosts = [x.strip() for x in self.server_hosts.split(',')]
-
- for host in hosts:
- logger.info('Sending library update command to Plex Media Server@ ' + host)
- url = "%s/library/sections" % host
- try:
- xml_sections = minidom.parse(urllib.urlopen(url))
- except IOError, e:
- logger.warn("Error while trying to contact Plex Media Server: %s" % e)
- return False
-
- sections = xml_sections.getElementsByTagName('Directory')
- if not sections:
- logger.info(u"Plex Media Server not running on: " + host)
- return False
-
- for s in sections:
- if s.getAttribute('type') == "artist":
- url = "%s/library/sections/%s/refresh" % (host, s.getAttribute('key'))
- try:
- urllib.urlopen(url)
- except Exception as e:
- logger.warn("Error updating library section for Plex Media Server: %s" % e)
- return False
-
- def notify(self, artist, album, albumartpath):
+ def notify(self, subject=None, message=None):
hosts = [x.strip() for x in self.client_hosts.split(',')]
- header = "PlexPy"
- message = "%s - %s added to your library" % (artist, album)
+ header = subject
+ message = message
time = "3000" # in ms
for host in hosts:
logger.info('Sending notification command to Plex Media Server @ ' + host)
try:
- notification = header + "," + message + "," + time + "," + albumartpath
+ notification = header + "," + message + "," + time
notifycommand = {'command': 'ExecBuiltIn', 'parameter': 'Notification(' + notification + ')'}
request = self._sendhttp(host, notifycommand)
@@ -397,7 +298,7 @@ class Plex(object):
class NMA(object):
- def notify(self, artist=None, album=None, snatched=None):
+ def notify(self, subject=None, message=None):
title = 'PlexPy'
api = plexpy.CONFIG.NMA_APIKEY
nma_priority = plexpy.CONFIG.NMA_PRIORITY
@@ -406,12 +307,7 @@ class NMA(object):
logger.debug(u"NMA API: " + api)
logger.debug(u"NMA Priority: " + str(nma_priority))
- if snatched:
- event = snatched + " snatched!"
- message = "PlexPy has snatched: " + snatched
- else:
- event = artist + ' - ' + album + ' complete!'
- message = "PlexPy has downloaded and postprocessed: " + artist + ' [' + album + ']'
+ event = subject
logger.debug(u"NMA event: " + event)
logger.debug(u"NMA message: " + message)
@@ -460,9 +356,9 @@ class PUSHBULLET(object):
body=json.dumps(data))
response = http_handler.getresponse()
request_status = response.status
- logger.debug(u"PushBullet response status: %r" % request_status)
- logger.debug(u"PushBullet response headers: %r" % response.getheaders())
- logger.debug(u"PushBullet response body: %r" % response.read())
+ # logger.debug(u"PushBullet response status: %r" % request_status)
+ # logger.debug(u"PushBullet response headers: %r" % response.getheaders())
+ # logger.debug(u"PushBullet response body: %r" % response.read())
if request_status == 200:
logger.info(u"PushBullet notifications sent.")
@@ -474,10 +370,6 @@ class PUSHBULLET(object):
logger.info(u"PushBullet notification failed serverside.")
return False
- def updateLibrary(self):
- #For uniformity reasons not removed
- return
-
def test(self, apikey, deviceid):
self.enabled = True
@@ -527,43 +419,6 @@ class PUSHALOT(object):
return False
-class Synoindex(object):
- def __init__(self, util_loc='/usr/syno/bin/synoindex'):
- self.util_loc = util_loc
-
- def util_exists(self):
- return os.path.exists(self.util_loc)
-
- def notify(self, path):
- path = os.path.abspath(path)
-
- if not self.util_exists():
- logger.warn("Error sending notification: synoindex utility not found at %s" % self.util_loc)
- return
-
- if os.path.isfile(path):
- cmd_arg = '-a'
- elif os.path.isdir(path):
- cmd_arg = '-A'
- else:
- logger.warn("Error sending notification: Path passed to synoindex was not a file or folder.")
- return
-
- cmd = [self.util_loc, cmd_arg, path]
- logger.info("Calling synoindex command: %s" % str(cmd))
- try:
- p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=plexpy.PROG_DIR)
- out, error = p.communicate()
- #synoindex never returns any codes other than '0', highly irritating
- except OSError, e:
- logger.warn("Error sending notification: %s" % str(e))
-
- def notify_multiple(self, path_list):
- if isinstance(path_list, list):
- for path in path_list:
- self.notify(path)
-
-
class PUSHOVER(object):
def __init__(self):
@@ -814,25 +669,6 @@ class BOXCAR(object):
return False
-class SubSonicNotifier(object):
-
- def __init__(self):
- self.host = plexpy.CONFIG.SUBSONIC_HOST
- self.username = plexpy.CONFIG.SUBSONIC_USERNAME
- self.password = plexpy.CONFIG.SUBSONIC_PASSWORD
-
- def notify(self, albumpaths):
- # Correct URL
- if not self.host.lower().startswith("http"):
- self.host = "http://" + self.host
-
- if not self.host.lower().endswith("/"):
- self.host = self.host + "/"
-
- # Invoke request
- request.request_response(self.host + "musicFolderSettings.view?scanNow",
- auth=(self.username, self.password))
-
class Email(object):
def notify(self, subject, message):
diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py
index f994ffd3..31b7fae4 100644
--- a/plexpy/pmsconnect.py
+++ b/plexpy/pmsconnect.py
@@ -581,6 +581,7 @@ class PmsConnect(object):
progress = self.get_xml_attr(session, 'viewOffset')
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
+ 'art': self.get_xml_attr(session, 'art'),
'parentThumb': self.get_xml_attr(session, 'parentThumb'),
'thumb': self.get_xml_attr(session, 'thumb'),
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
@@ -588,13 +589,17 @@ class PmsConnect(object):
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'),
+ 'grandparentTitle': self.get_xml_attr(session, 'grandparentTitle'),
+ 'parentTitle': self.get_xml_attr(session, 'parentTitle'),
+ 'title': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
'audioChannels': audio_channels,
'audioCodec': audio_codec,
+ 'videoDecision': '',
+ 'videoCodec': '',
+ 'height': '',
+ 'width': '',
'duration': duration,
'progress': progress,
'progressPercent': str(helpers.get_percent(progress, duration)),
@@ -647,6 +652,7 @@ class PmsConnect(object):
if self.get_xml_attr(session, 'type') == 'episode':
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
'art': self.get_xml_attr(session, 'art'),
+ 'parentThumb': self.get_xml_attr(session, 'parentThumb'),
'thumb': thumb,
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
'friendly_name': plex_watch.get_user_friendly_name(
@@ -654,6 +660,7 @@ class PmsConnect(object):
'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'),
+ 'parentTitle': self.get_xml_attr(session, 'parentTitle'),
'title': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
@@ -673,11 +680,14 @@ class PmsConnect(object):
session_output = {'sessionKey': self.get_xml_attr(session, 'sessionKey'),
'art': self.get_xml_attr(session, 'art'),
'thumb': thumb,
+ 'parentThumb': self.get_xml_attr(session, 'parentThumb'),
'user': self.get_xml_attr(session.getElementsByTagName('User')[0], 'title'),
'friendly_name': plex_watch.get_user_friendly_name(
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'),
+ 'parentTitle': self.get_xml_attr(session, 'parentTitle'),
'title': self.get_xml_attr(session, 'title'),
'ratingKey': self.get_xml_attr(session, 'ratingKey'),
'audioDecision': audio_decision,
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index bc39c42c..a6c39904 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -274,8 +274,6 @@ class WebInterface(object):
"xbmc_host": plexpy.CONFIG.XBMC_HOST,
"xbmc_username": plexpy.CONFIG.XBMC_USERNAME,
"xbmc_password": plexpy.CONFIG.XBMC_PASSWORD,
- "lms_enabled": checked(plexpy.CONFIG.LMS_ENABLED),
- "lms_host": plexpy.CONFIG.LMS_HOST,
"plex_enabled": checked(plexpy.CONFIG.PLEX_ENABLED),
"plex_client_host": plexpy.CONFIG.PLEX_CLIENT_HOST,
"plex_username": plexpy.CONFIG.PLEX_USERNAME,
@@ -285,7 +283,6 @@ class WebInterface(object):
"nma_priority": int(plexpy.CONFIG.NMA_PRIORITY),
"pushalot_enabled": checked(plexpy.CONFIG.PUSHALOT_ENABLED),
"pushalot_apikey": plexpy.CONFIG.PUSHALOT_APIKEY,
- "synoindex_enabled": checked(plexpy.CONFIG.SYNOINDEX_ENABLED),
"pushover_enabled": checked(plexpy.CONFIG.PUSHOVER_ENABLED),
"pushover_keys": plexpy.CONFIG.PUSHOVER_KEYS,
"pushover_apitoken": plexpy.CONFIG.PUSHOVER_APITOKEN,
@@ -293,17 +290,12 @@ class WebInterface(object):
"pushbullet_enabled": checked(plexpy.CONFIG.PUSHBULLET_ENABLED),
"pushbullet_apikey": plexpy.CONFIG.PUSHBULLET_APIKEY,
"pushbullet_deviceid": plexpy.CONFIG.PUSHBULLET_DEVICEID,
- "subsonic_enabled": checked(plexpy.CONFIG.SUBSONIC_ENABLED),
- "subsonic_host": plexpy.CONFIG.SUBSONIC_HOST,
- "subsonic_username": plexpy.CONFIG.SUBSONIC_USERNAME,
- "subsonic_password": plexpy.CONFIG.SUBSONIC_PASSWORD,
"twitter_enabled": checked(plexpy.CONFIG.TWITTER_ENABLED),
"osx_notify_enabled": checked(plexpy.CONFIG.OSX_NOTIFY_ENABLED),
"osx_notify_app": plexpy.CONFIG.OSX_NOTIFY_APP,
"boxcar_enabled": checked(plexpy.CONFIG.BOXCAR_ENABLED),
"boxcar_token": plexpy.CONFIG.BOXCAR_TOKEN,
"cache_sizemb": plexpy.CONFIG.CACHE_SIZEMB,
- "mpc_enabled": checked(plexpy.CONFIG.MPC_ENABLED),
"email_enabled": checked(plexpy.CONFIG.EMAIL_ENABLED),
"email_from": plexpy.CONFIG.EMAIL_FROM,
"email_to": plexpy.CONFIG.EMAIL_TO,
@@ -333,11 +325,11 @@ class WebInterface(object):
checked_configs = [
"launch_browser", "enable_https", "api_enabled", "freeze_db", "growl_enabled",
- "prowl_enabled", "xbmc_enabled", "lms_enabled",
+ "prowl_enabled", "xbmc_enabled",
"plex_enabled", "nma_enabled", "pushalot_enabled",
- "synoindex_enabled", "pushover_enabled", "pushbullet_enabled",
- "subsonic_enabled", "twitter_enabled", "osx_notify_enabled",
- "boxcar_enabled", "mpc_enabled", "email_enabled", "email_tls",
+ "pushover_enabled", "pushbullet_enabled",
+ "twitter_enabled", "osx_notify_enabled",
+ "boxcar_enabled", "email_enabled", "email_tls",
"grouping_global_history", "grouping_user_history", "grouping_charts", "pms_use_bif"
]
for checked_config in checked_configs:
@@ -873,6 +865,18 @@ class WebInterface(object):
else:
logger.warn('Unable to retrieve data.')
+ @cherrypy.expose
+ def get_activity(self, **kwargs):
+
+ pms_connect = pmsconnect.PmsConnect()
+ result = pms_connect.get_current_activity()
+
+ if result:
+ cherrypy.response.headers['Content-type'] = 'application/json'
+ return json.dumps(result)
+ else:
+ logger.warn('Unable to retrieve data.')
+
@cherrypy.expose
def get_full_users_list(self, **kwargs):