diff --git a/CHANGELOG.md b/CHANGELOG.md index 418c496c..8be780f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## v2.0.28 (2018-04-02) + +* Monitoring: + * Fix: Homepage activity header text. + + +## v2.0.27 (2018-04-02) + +* Monitoring: + * Change: Move activity refresh interval setting to the settings page. + + +## v2.0.26-beta (2018-03-30) + +* Monitoring: + * New: Setting to change the refresh interval on the homepage. + * Fix: Identify extras correctly on the activity cards. +* Notifications: + * Change: Send Telegram image and text separately if the caption is longer than 200 characters. +* UI: + * Fix: Error when clicking on synced playlist links. + + ## v2.0.25 (2018-03-22) * Monitoring: diff --git a/data/interfaces/default/current_activity_instance.html b/data/interfaces/default/current_activity_instance.html index 092dfba8..27e63a1c 100644 --- a/data/interfaces/default/current_activity_instance.html +++ b/data/interfaces/default/current_activity_instance.html @@ -64,7 +64,7 @@ DOCUMENTATION :: END from collections import defaultdict from urllib import quote from plexpy import helpers - from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES + from plexpy.common import VIDEO_RESOLUTION_OVERRIDES, AUDIO_CODEC_OVERRIDES, EXTRA_TYPES import plexpy %> <% @@ -107,7 +107,11 @@ DOCUMENTATION :: END
% elif data['media_type'] in ('photo', 'clip'): - + % if data['extra_type']: + + % else: + + % endif % else: % endif @@ -300,14 +304,13 @@ DOCUMENTATION :: ENDSet the interval (in seconds) to refresh the current activity on the homepage. Minimum 2.
+
@@ -2031,6 +2041,9 @@ $(document).ready(function() {
$('#pms_url_manual').prop('checked', false);
$('#pms_url').val('Please verify your server above to retrieve the URL');
PMSCloudCheck();
+ },
+ onDropdownOpen: function() {
+ this.clear();
}
});
var select_pms = $select_pms[0].selectize;
@@ -2104,11 +2117,11 @@ $(document).ready(function() {
data: {
hostname: pms_ip,
port: pms_port,
- identifier: pms_identifier,
ssl: pms_ssl,
remote: pms_is_remote,
manual: pms_url_manual,
- get_url: serverChanged
+ get_url: true,
+ test_websocket: true
},
cache: true,
async: true,
@@ -2121,15 +2134,23 @@ $(document).ready(function() {
var result = xhr;
var identifier = result.identifier;
var url = result.url;
+ var ws = result.ws;
if (identifier) {
$("#pms_identifier").val(identifier);
+
if (url) {
$("#pms_url").val(url);
}
- $("#pms_verify").html('').fadeIn('fast');
- $("#pms_ip_group").removeClass("has-error");
- serverChanged = false;
+ if (ws === false) {
+ $("#pms_verify").html('').fadeIn('fast');
+ $("#pms_ip_group").addClass("has-error");
+ showMsg(' Server found but unable to connect websocket.
Check the logs for errors.', false, true, 5000, true)
+ } else {
+ $("#pms_verify").html('').fadeIn('fast');
+ $("#pms_ip_group").removeClass("has-error");
+ serverChanged = false;
+ }
if (_callback) {
_callback();
@@ -2157,13 +2178,6 @@ $(document).ready(function() {
$("#pms_web_url").val(pms_web_url || 'https://app.plex.tv/desktop');
}
- $('#test_pms_url_button').on('click', function(){
- var pms_url = $.trim($("#pms_url").val());
- if (pms_url.startsWith('http')) {
- window.open(pms_url + '/web', '_blank');
- }
- });
-
$('#test_pms_web_button').on('click', function(){
var pms_web_url = $.trim($("#pms_web_url").val());
window.open(pms_web_url, '_blank');
diff --git a/data/interfaces/default/sync.html b/data/interfaces/default/sync.html
index 3197b01b..e1d71656 100644
--- a/data/interfaces/default/sync.html
+++ b/data/interfaces/default/sync.html
@@ -100,7 +100,7 @@
// Load user ids and names (for the selector)
$.ajax({
url: 'get_user_names',
- type: 'get',
+ type: 'GET',
dataType: 'json',
success: function (data) {
var select = $('#sync-user');
@@ -116,7 +116,8 @@
function loadSyncTable(selected_user_id) {
sync_table_options.ajax = {
- url: 'get_sync?user_id=' + selected_user_id
+ url: 'get_sync?user_id=' + selected_user_id,
+ type: 'POST'
};
sync_table = $('#sync_table').DataTable(sync_table_options);
var colvis = new $.fn.dataTable.ColVis(sync_table, {
diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html
index 1d76ed6f..251fec10 100644
--- a/data/interfaces/default/user.html
+++ b/data/interfaces/default/user.html
@@ -413,7 +413,7 @@ DOCUMENTATION :: END
// Build watch history table
history_table_options.ajax = {
url: 'get_history',
- type: 'post',
+ type: 'POST',
data: function ( d ) {
return {
json_data: JSON.stringify( d ),
@@ -442,7 +442,8 @@ DOCUMENTATION :: END
function loadSyncTable() {
// Build user sync table
sync_table_options.ajax = {
- url: 'get_sync?user_id=' + user_id
+ url: 'get_sync?user_id=' + user_id,
+ type: 'POST'
};
sync_table = $('#sync_table-UID-${data["user_id"]}').DataTable(sync_table_options);
sync_table.column(2).visible(false);
@@ -457,7 +458,7 @@ DOCUMENTATION :: END
// Build user IP table
user_ip_table_options.ajax = {
url: 'get_user_ips',
- type: 'post',
+ type: 'POST',
data: function ( d ) {
return {
json_data: JSON.stringify( d ),
@@ -474,6 +475,7 @@ DOCUMENTATION :: END
// Build user login table
login_log_table_options.ajax = {
url: 'get_user_logins',
+ type: 'POST',
data: function(d) {
return {
json_data: JSON.stringify(d),
diff --git a/data/interfaces/default/users.html b/data/interfaces/default/users.html
index 6c0d5690..926dafe2 100644
--- a/data/interfaces/default/users.html
+++ b/data/interfaces/default/users.html
@@ -94,7 +94,7 @@
json_data: JSON.stringify(d)
};
}
- }
+ };
users_list_table = $('#users_list_table').DataTable(users_list_table_options);
var colvis = new $.fn.dataTable.ColVis(users_list_table, { buttonText: ' Select columns', buttonClass: 'btn btn-dark', exclude: [0, 1] });
diff --git a/data/interfaces/default/welcome.html b/data/interfaces/default/welcome.html
index 2a7cff1c..d61900a9 100644
--- a/data/interfaces/default/welcome.html
+++ b/data/interfaces/default/welcome.html
@@ -374,6 +374,9 @@ $(document).ready(function() {
$('#pms_is_remote_checkbox').prop('disabled', false);
$('#pms_ssl_checkbox').prop('disabled', false);
}
+ },
+ onDropdownOpen: function() {
+ this.clear();
}
});
var select_pms = $select_pms[0].selectize;
diff --git a/plexpy/common.py b/plexpy/common.py
index c69350d6..591b33fa 100644
--- a/plexpy/common.py
+++ b/plexpy/common.py
@@ -175,6 +175,16 @@ HW_ENCODERS = [
'nvenc'
]
+EXTRA_TYPES = {
+ '1': 'Trailer',
+ '2': 'Deleted Scene',
+ '3': 'Interview',
+ '5': 'Behind the Scenes',
+ '6': 'Scene',
+ '10': 'Featurette',
+ '11': 'Short'
+}
+
SCHEDULER_LIST = [
'Check GitHub for updates',
'Check for server response',
diff --git a/plexpy/config.py b/plexpy/config.py
index d3a6df68..57c92a22 100644
--- a/plexpy/config.py
+++ b/plexpy/config.py
@@ -209,6 +209,7 @@ _CONFIG_DEFINITIONS = {
'HOME_STATS_CARDS': (list, 'General', ['top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', \
'popular_music', 'last_watched', 'top_users', 'top_platforms', 'most_concurrent']),
'HOME_STATS_RECENTLY_ADDED_COUNT': (int, 'General', 50),
+ 'HOME_REFRESH_INTERVAL': (int, 'General', 10),
'HTTPS_CREATE_CERT': (int, 'General', 1),
'HTTPS_CERT': (str, 'General', ''),
'HTTPS_CERT_CHAIN': (str, 'General', ''),
diff --git a/plexpy/notifiers.py b/plexpy/notifiers.py
index 6d1ca7a4..51e94010 100644
--- a/plexpy/notifiers.py
+++ b/plexpy/notifiers.py
@@ -3321,10 +3321,17 @@ class TELEGRAM(Notifier):
if poster_content:
poster_filename = 'poster_{}.png'.format(pretty_metadata.parameters['rating_key'])
files = {'photo': (poster_filename, poster_content, 'image/png')}
- data['caption'] = text
- return self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']),
- data=data, files=files)
+ if len(text) > 200:
+ data['disable_notification'] = True
+ else:
+ data['caption'] = text
+
+ r = self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']),
+ data=data, files=files)
+
+ if not data.pop('disable_notification', None):
+ return r
data['text'] = text
diff --git a/plexpy/pmsconnect.py b/plexpy/pmsconnect.py
index 421527e7..5ea7d8dd 100644
--- a/plexpy/pmsconnect.py
+++ b/plexpy/pmsconnect.py
@@ -1133,7 +1133,9 @@ class PmsConnect(object):
'genres': genres,
'labels': labels,
'collections': collections,
- 'full_title': helpers.get_xml_attr(metadata_main, 'title')
+ 'full_title': helpers.get_xml_attr(metadata_main, 'title'),
+ 'extra_type': helpers.get_xml_attr(metadata_main, 'extraType'),
+ 'sub_type': helpers.get_xml_attr(metadata_main, 'subtype')
}
else:
@@ -1724,7 +1726,9 @@ class PmsConnect(object):
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
'channel_icon': helpers.get_xml_attr(session, 'sourceIcon'),
'channel_title': helpers.get_xml_attr(session, 'sourceTitle'),
- 'live': int(helpers.get_xml_attr(session, 'live') == '1')
+ 'live': int(helpers.get_xml_attr(session, 'live') == '1'),
+ 'extra_type': helpers.get_xml_attr(session, 'extraType'),
+ 'sub_type': helpers.get_xml_attr(session, 'subtype')
}
else:
channel_stream = 0
diff --git a/plexpy/version.py b/plexpy/version.py
index 97c5050d..353a93e8 100644
--- a/plexpy/version.py
+++ b/plexpy/version.py
@@ -1,2 +1,2 @@
PLEXPY_BRANCH = "master"
-PLEXPY_RELEASE_VERSION = "v2.0.25"
+PLEXPY_RELEASE_VERSION = "v2.0.28"
diff --git a/plexpy/webserve.py b/plexpy/webserve.py
index b9aaaf4e..ed6e2b36 100644
--- a/plexpy/webserve.py
+++ b/plexpy/webserve.py
@@ -27,6 +27,8 @@ from hashing_passwords import make_hash
from mako.lookup import TemplateLookup
from mako import exceptions
+import websocket
+
import plexpy
import activity_pinger
import common
@@ -173,6 +175,7 @@ class WebInterface(object):
"home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE,
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
"home_stats_recently_added_count": plexpy.CONFIG.HOME_STATS_RECENTLY_ADDED_COUNT,
+ "home_refresh_interval": plexpy.CONFIG.HOME_REFRESH_INTERVAL,
"pms_name": plexpy.CONFIG.PMS_NAME,
"pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD,
"update_show_changelog": plexpy.CONFIG.UPDATE_SHOW_CHANGELOG
@@ -2730,6 +2733,7 @@ class WebInterface(object):
"home_sections": json.dumps(plexpy.CONFIG.HOME_SECTIONS),
"home_stats_cards": json.dumps(plexpy.CONFIG.HOME_STATS_CARDS),
"home_library_cards": json.dumps(plexpy.CONFIG.HOME_LIBRARY_CARDS),
+ "home_refresh_interval": plexpy.CONFIG.HOME_REFRESH_INTERVAL,
"buffer_threshold": plexpy.CONFIG.BUFFER_THRESHOLD,
"buffer_wait": plexpy.CONFIG.BUFFER_WAIT,
"group_history_tables": checked(plexpy.CONFIG.GROUP_HISTORY_TABLES),
@@ -3556,7 +3560,7 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
@addtoapi()
def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, manual=0,
- get_url=False, **kwargs):
+ get_url=False, test_websocket=False, **kwargs):
""" Get the PMS server identifier.
```
@@ -3612,6 +3616,23 @@ class WebInterface(object):
pms_url_manual=manual,
pms_identifier=identifier)
result['url'] = server['pms_url']
+ result['ws'] = None
+
+ if test_websocket == 'true':
+ # Quick test websocket connection
+ ws_url = result['url'].replace('http', 'ws', 1) + '/:/websockets/notifications'
+ header = ['X-Plex-Token: %s' % plexpy.CONFIG.PMS_TOKEN]
+
+ logger.debug("Testing websocket connection...")
+ try:
+ test_ws = websocket.create_connection(ws_url, header=header)
+ test_ws.close()
+ logger.debug("Websocket connection test successful.")
+ result['ws'] = True
+ except (websocket.WebSocketException, IOError, Exception) as e:
+ logger.error("Websocket connection test failed: %s" % e)
+ result['ws'] = False
+
return result
else:
logger.warn('Unable to retrieve the PMS identifier.')
@@ -3790,6 +3811,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def info(self, rating_key=None, source=None, query=None, **kwargs):
+ if rating_key and not str(rating_key).isdigit():
+ raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
+
metadata = None
config = {