Compare commits

...

35 Commits

Author SHA1 Message Date
JonnyWong16
5fd8cfeb80 v2.1.35-beta 2019-09-24 18:09:05 -07:00
JonnyWong16
b295566a4e Clear metadata cache before retrieving new sessions 2019-09-19 21:01:37 -07:00
JonnyWong16
e0943a2d55 Clear metadata cache on startup check for active sessions 2019-09-19 20:55:19 -07:00
JonnyWong16
3015740c3e Merge pull request #1354 from samwiseg0/fix/blank_audio
Fix blank audio on activity card when changing audio streams during direct play
2019-09-19 19:40:14 -07:00
JonnyWong16
ec9ff2f803 Merge pull request #1353 from samwiseg0/fix/video_scan_type
Add video scan type and standardize video resolution. Fixes Tautulli/Tautulli-Issues#194
2019-09-19 19:39:40 -07:00
JonnyWong16
ec8aae9122 Fix Tautulli logging out after saving settings and restarting 2019-09-19 19:37:31 -07:00
samwiseg0
52e608cc43 Fix blank audio on activity card when changing audio streams 2019-09-19 22:29:44 -04:00
samwiseg0
8213f270e5 Move full resolution outside if statement 2019-09-19 22:26:43 -04:00
JonnyWong16
7085042b0d Merge pull request #1352 from samwiseg0/fix/watch_stats
Add year to SQL query for movie watch stats
2019-09-19 19:04:06 -07:00
JonnyWong16
6a411d2458 Merge pull request #1351 from samwiseg0/fix/release_date
Fix release date to be a string vs integer
2019-09-19 19:03:57 -07:00
JonnyWong16
38e2fbabb8 Merge pull request #1350 from samwiseg0/fix/lin_hw_decode
Fix hardware decode not reflected in GUI
2019-09-19 19:03:48 -07:00
samwiseg0
85709f754a Update API docs to reflect changes 2019-09-19 21:22:37 -04:00
samwiseg0
623a1e8a91 Update webui to utilize video full resolution 2019-09-19 21:22:02 -04:00
samwiseg0
de69945ebe Define notification parameters 2019-09-19 20:57:08 -04:00
samwiseg0
7095fa6ac6 Remove overrides 2019-09-19 20:53:18 -04:00
samwiseg0
a59e8298fd Use video_full_resolution for optimized versions in the activity card 2019-09-19 20:50:17 -04:00
samwiseg0
2737d52279 Set the full resolution of the source video and stream video 2019-09-19 20:47:39 -04:00
samwiseg0
0ac1ad4386 Create video_scan_type and stream_video_scan_type 2019-09-19 20:46:38 -04:00
samwiseg0
2db328ac31 Standardize videoResolution to be lowercase 2019-09-19 20:45:53 -04:00
samwiseg0
b6de4ad054 Add year to SQL query watch stats. Fixes Tautulli/Tautulli-Issues#195 2019-09-16 23:44:48 -04:00
samwiseg0
cfea7164b7 Fix release date to be a str vs int 2019-09-16 22:50:31 -04:00
samwiseg0
7e7e5a6be4 Add nvdec for linux decode support. Fixes Tautulli/Tautulli-Issues#193 2019-09-16 21:30:09 -04:00
samwiseg0
df57f4c009 Remove duplicate nvenc 2019-09-16 21:24:57 -04:00
JonnyWong16
c2185c4ce5 Fix notificaiton parameter prefix and suffix not being substituted correctly 2019-09-07 16:37:38 -07:00
JonnyWong16
08714436c3 v2.1.34 2019-09-03 21:46:48 -07:00
JonnyWong16
f65f5d07c0 Add product to get_history API command 2019-09-03 19:52:54 -07:00
JonnyWong16
a9b10c4560 Add Product column to history tables 2019-09-03 19:52:33 -07:00
JonnyWong16
589fbd3158 Add TVMaze and TMDB IDs to notification parameters after lookup 2019-08-27 19:54:54 -07:00
JonnyWong16
0ffc8c5d19 Update JWT secret instead of UUID 2019-08-24 22:00:31 -07:00
JonnyWong16
7498617b74 Flag update JWT UUID after restarting 2019-08-24 21:13:39 -07:00
JonnyWong16
f21d505ab8 Force logout all clients when changing the admin password 2019-08-24 20:49:56 -07:00
JonnyWong16
7b16af0585 Fix verifying PMS with unpublished hostnames (Fixes Tautulli/Tautulli-Issues#190) 2019-08-16 21:27:34 -07:00
JonnyWong16
a83108282a Fix add title to searchable media info fields 2019-08-14 22:50:23 -07:00
JonnyWong16
1c4d01d6ec Fix libraries/users table respect grouping setting 2019-08-09 19:15:53 -07:00
JonnyWong16
22e6d4067d Missing space for episode titles on tables 2019-08-09 19:01:27 -07:00
25 changed files with 203 additions and 81 deletions

11
API.md
View File

@@ -507,7 +507,9 @@ Returns:
"stream_video_language": "",
"stream_video_language_code": "",
"stream_video_ref_frames": "4",
"stream_video_full_resolution": "1080p",
"stream_video_resolution": "1080",
"stream_video_scan_type": "progressive",
"stream_video_width": "1920",
"studio": "HBO",
"subtitle_codec": "",
@@ -560,12 +562,14 @@ Returns:
"video_decision": "direct play",
"video_frame_rate": "23.976",
"video_framerate": "24p",
"video_full_resolution": "1080p",
"video_height": "1078",
"video_language": "",
"video_language_code": "",
"video_profile": "high",
"video_ref_frames": "4",
"video_resolution": "1080",
"video_scan_type": "progressive",
"video_width": "1920",
"view_offset": "1000",
"width": "1920",
@@ -700,8 +704,9 @@ Returns:
"parent_title": "",
"paused_counter": 0,
"percent_complete": 84,
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"platform": "Windows",
"product": "Plex for Windows",
"player": "Castle-PC",
"rating_key": 4348,
"reference_id": 1123,
"session_key": null,
@@ -833,6 +838,7 @@ Required parameters:
None
Optional parameters:
grouping (int): 0 or 1
order_column (str): "library_thumb", "section_name", "section_type", "count", "parent_count",
"child_count", "last_accessed", "last_played", "plays", "duration"
order_dir (str): "desc" or "asc"
@@ -2341,6 +2347,7 @@ Required parameters:
None
Optional parameters:
grouping (int): 0 or 1
order_column (str): "user_thumb", "friendly_name", "last_seen", "ip_address", "platform",
"player", "last_played", "plays", "duration"
order_dir (str): "desc" or "asc"

View File

@@ -1,5 +1,40 @@
# Changelog
## v2.1.35-beta (2019-09-24)
* Monitoring:
* Fix: Audio shown as blank on activity cards when changing audio tracks during direct play.
* Fix: Display correct interlaced or progressive video scan type on activity cards.
* New: Added flag for Nvidia hardware decoding on activity cards.
* Notifications:
* Fix: Notification parameter prefix and suffix were not substituted correctly.
* Fix: Release Date notification parameter was incorrectly casted to an integer instead of a string.
* New: Added video scan type and full resolution notification parameters.
* UI:
* Fix: Movies with the same title but different year being grouped on the homepage stats cards.
* API:
* New: Added video scan type and full resolution values to get_activity command.
* Other:
* Fix: Tautulli logging out every time after saving settings and restarting.
## v2.1.34 (2019-09-03)
* History:
* New: Added Product column to history tables.
* Notifications:
* Fix: IMDB/TMDb/TVDB/TVmaze ID notification parameters showing blank values after lookup.
* UI:
* Fix: Libraries and Users tables did not respect the group history setting.
* API:
* Fix: Title field was not searchable in get_library_media_info command.
* New: Added grouping option to get_libraries_table and get_users_table commands.
* New: Added product value to get_history command.
* Other:
* Fix: Could not verify Plex Media Server with unpublished hostnames.
* Change: Automatically logout all Tautulli instances when changing the admin password.
## v2.1.33 (2019-07-27)
* Notifications:

View File

@@ -232,11 +232,11 @@ DOCUMENTATION :: END
hw_d = ' (HW)' if data['transcode_hw_decoding'] else ''
hw_e = ' (HW)' if data['transcode_hw_encoding'] else ''
%>
Transcode (${data['video_codec'].upper()}${hw_d} ${VIDEO_RESOLUTION_OVERRIDES.get(data['video_resolution'], data['video_resolution'])} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
Transcode (${data['video_codec'].upper()}${hw_d} ${data['video_full_resolution']} <i class="fa fa-long-arrow-right"></i> ${data['stream_video_codec'].upper()}${hw_e} ${data['stream_video_full_resolution']})
% elif data['stream_video_decision'] == 'copy':
Direct Stream (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
Direct Stream (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']})
% else:
Direct Play (${data['stream_video_codec'].upper()} ${VIDEO_RESOLUTION_OVERRIDES.get(data['stream_video_resolution'], data['stream_video_resolution'])})
Direct Play (${data['stream_video_codec'].upper()} ${data['stream_video_full_resolution']})
% endif
% elif data['media_type'] == 'photo':
Direct Play (${data['width']}x${data['height']})

View File

@@ -60,7 +60,8 @@
<th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="device">Player</th>
<th align="left" id="product">Product</th>
<th align="left" id="player">Player</th>
<th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
<th align="left" id="paused_counter">Paused</th>
@@ -143,7 +144,7 @@
var colvis = new $.fn.dataTable.ColVis(history_table, {
buttonText: '<i class="fa fa-columns"></i> Select columns',
buttonClass: 'btn btn-dark',
exclude: [0, 11]
exclude: [0, 12]
});
$(colvis.button()).appendTo('div.colvis-button-bar');

View File

@@ -26,6 +26,7 @@
<th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="product">Product</th>
<th align="left" id="device">Player</th>
<th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
@@ -61,7 +62,7 @@
};
history_table = $('#history_table_modal').DataTable(history_table_options);
history_table.columns([0, 3, 4, 8, 10, 11]).visible(false);
history_table.columns([0, 3, 4, 5, 9, 11, 12]).visible(false);
clearSearchButton('history_table_modal', history_table);

View File

@@ -445,7 +445,7 @@
v_res = '4k';
break;
default:
v_res = s.video_resolution + 'p'
v_res = s.video_full_resolution;
}
var sv_res = '';
switch (s.stream_video_resolution.toLowerCase()) {
@@ -456,7 +456,7 @@
sv_res = '4k';
break;
default:
sv_res = s.stream_video_resolution + 'p'
sv_res = s.stream_video_full_resolution;
}
if (s.stream_video_decision === 'transcode') {
var hw_d = (s.transcode_hw_decoding === 1) ? ' (HW)' : '';

View File

@@ -451,6 +451,7 @@ DOCUMENTATION :: END
<th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="product">Product</th>
<th align="left" id="player">Player</th>
<th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
@@ -613,7 +614,7 @@ DOCUMENTATION :: END
$(document).ready(function () {
get_history();
history_table = $('#history_table-RK-${data["rating_key"]}').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 12] });
$(colvis.button()).appendTo('div.colvis-button-bar');
clearSearchButton('history_table-RK-${data["rating_key"]}', history_table);

View File

@@ -49,7 +49,7 @@ history_table_options = {
},
{
"targets": [1],
"data":"date",
"data": "date",
"createdCell": function (td, cellData, rowData, row, col) {
var date = moment(cellData, "X").format(date_format);
if (rowData['state'] !== null) {
@@ -77,7 +77,7 @@ history_table_options = {
},
{
"targets": [2],
"data":"friendly_name",
"data": "friendly_name",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
if (rowData['user_id']) {
@@ -112,7 +112,18 @@ history_table_options = {
},
{
"targets": [4],
"data":"platform",
"data": "platform",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
$(td).html(capitalizeFirstLetter(cellData));
}
},
"width": "10%",
"className": "no-wrap"
},
{
"targets": [5],
"data": "product",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
$(td).html(cellData);
@@ -122,7 +133,7 @@ history_table_options = {
"className": "no-wrap"
},
{
"targets": [5],
"targets": [6],
"data": "player",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
@@ -137,12 +148,12 @@ history_table_options = {
$(td).html('<div><a href="#" data-target="#info-modal" data-toggle="modal"><div style="float: left;">' + transcode_dec + '&nbsp;' + cellData + '</div></a></div>');
}
},
"width": "12%",
"width": "10%",
"className": "no-wrap modal-control"
},
{
"targets": [6],
"data":"full_title",
"targets": [7],
"data": "full_title",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
var parent_info = '';
@@ -155,7 +166,7 @@ history_table_options = {
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'episode') {
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')'; }
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + ' &middot; E' + rowData['media_index'] + ')'; }
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?' + source + 'rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
@@ -171,12 +182,12 @@ history_table_options = {
}
}
},
"width": "33%",
"width": "25%",
"className": "datatable-wrap"
},
{
"targets": [7],
"data":"started",
"targets": [8],
"data": "started",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData === null) {
$(td).html('n/a');
@@ -189,8 +200,8 @@ history_table_options = {
"className": "no-wrap"
},
{
"targets": [8],
"data":"paused_counter",
"targets": [9],
"data": "paused_counter",
"render": function (data, type, full) {
if (data !== null) {
return Math.round(moment.duration(data, 'seconds').as('minutes')) + ' mins';
@@ -203,8 +214,8 @@ history_table_options = {
"className": "no-wrap"
},
{
"targets": [9],
"data":"stopped",
"targets": [10],
"data": "stopped",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData === null || (rowData['state'] != null && rowData['state'] != "stopped")) {
$(td).html('n/a');
@@ -217,8 +228,8 @@ history_table_options = {
"className": "no-wrap"
},
{
"targets": [10],
"data":"duration",
"targets": [11],
"data": "duration",
"render": function (data, type, full) {
if (data !== null) {
return Math.round(moment.duration(data, 'seconds').as('minutes')) + ' mins';
@@ -231,7 +242,7 @@ history_table_options = {
"className": "no-wrap"
},
{
"targets": [11],
"targets": [12],
"data": "watched_status",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData == 1) {
@@ -489,7 +500,8 @@ function childTableFormat(rowData) {
'<th align="left" id="friendly_name">User</th>' +
'<th align="left" id="ip_address">IP Address</th>' +
'<th align="left" id="platform">Platform</th>' +
'<th align="left" id="platform">Player</th>' +
'<th align="left" id="product">Product</th>' +
'<th align="left" id="player">Player</th>' +
'<th align="left" id="title">Title</th>' +
'<th align="left" id="started">Started</th>' +
'<th align="left" id="paused_counter">Paused</th>' +

View File

@@ -107,7 +107,7 @@ history_table_modal_options = {
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'episode') {
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')'; }
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + ' &middot; E' + rowData['media_index'] + ')'; }
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');

View File

@@ -153,7 +153,7 @@ libraries_list_table_options = {
} else if (rowData['media_type'] === 'episode') {
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
if (rowData['rating_key']) {
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')'; }
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + ' &middot; E' + rowData['media_index'] + ')'; }
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
} else {

View File

@@ -91,7 +91,7 @@ user_ip_table_options = {
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'episode') {
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')'; }
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + ' &middot; E' + rowData['media_index'] + ')'; }
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');

View File

@@ -166,7 +166,7 @@ users_list_table_options = {
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;">' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');
} else if (rowData['media_type'] === 'episode') {
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + '&middot; E' + rowData['media_index'] + ')'; }
if (rowData['parent_media_index'] && rowData['media_index']) { parent_info = ' (S' + rowData['parent_media_index'] + ' &middot; E' + rowData['media_index'] + ')'; }
media_type = '<span class="media-type-tooltip" data-toggle="tooltip" title="Episode"><i class="fa fa-television fa-fw"></i></span>';
thumb_popover = '<span class="thumb-tooltip" data-toggle="popover" data-img="pms_image_proxy?img=' + rowData['thumb'] + '&width=300&height=450&fallback=poster" data-height="120" data-width="80">' + cellData + parent_info + '</span>'
$(td).html('<div class="history-title"><a href="info?source=history&rating_key=' + rowData['rating_key'] + '"><div style="float: left;" >' + media_type + '&nbsp;' + thumb_popover + '</div></a></div>');

View File

@@ -205,6 +205,7 @@ DOCUMENTATION :: END
<th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="product">Product</th>
<th align="left" id="player">Player</th>
<th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
@@ -385,7 +386,7 @@ DOCUMENTATION :: END
};
history_table = $('#history_table-SID-${data["section_id"]}').DataTable(history_table_options);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 12] });
$(colvis.button()).appendTo('#button-bar-history');
clearSearchButton('history_table-SID-${data["section_id"]}', history_table);

View File

@@ -184,6 +184,7 @@ DOCUMENTATION :: END
<th align="left" id="friendly_name">User</th>
<th align="left" id="ip_address">IP Address</th>
<th align="left" id="platform">Platform</th>
<th align="left" id="product">Product</th>
<th align="left" id="player">Player</th>
<th align="left" id="title">Title</th>
<th align="left" id="started">Started</th>
@@ -425,7 +426,7 @@ DOCUMENTATION :: END
history_table = $('#history_table-UID-${data["user_id"]}').DataTable(history_table_options);
history_table.column(2).visible(false);
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 11] });
var colvis = new $.fn.dataTable.ColVis(history_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 12] });
$(colvis.button()).appendTo('#button-bar-history');
clearSearchButton('history_table-UID-${data["user_id"]}', history_table);

View File

@@ -217,9 +217,10 @@ def initialize(config_file):
CONFIG.write()
# Check if Tautulli has a jwt_secret
if CONFIG.JWT_SECRET == '' or not CONFIG.JWT_SECRET:
if CONFIG.JWT_SECRET == '' or not CONFIG.JWT_SECRET or CONFIG.JWT_UPDATE_SECRET:
logger.debug(u"Generating JWT secret...")
CONFIG.JWT_SECRET = generate_uuid()
CONFIG.JWT_UPDATE_SECRET = False
CONFIG.write()
# Get the previous version from the file

View File

@@ -17,13 +17,13 @@ import threading
import time
import plexpy
import activity_handler
import activity_processor
import database
import helpers
import libraries
import logger
import notification_handler
import notifiers
import plextv
import pmsconnect
import web_socket
@@ -37,17 +37,23 @@ int_ping_count = 0
def check_active_sessions(ws_request=False):
with monitor_lock:
pms_connect = pmsconnect.PmsConnect()
session_list = pms_connect.get_current_activity()
monitor_db = database.MonitorDatabase()
monitor_process = activity_processor.ActivityProcessor()
db_streams = monitor_process.get_sessions()
# Clear the metadata cache
for stream in db_streams:
activity_handler.delete_metadata_cache(stream['session_key'])
pms_connect = pmsconnect.PmsConnect()
session_list = pms_connect.get_current_activity()
logger.debug(u"Tautulli Monitor :: Checking for active streams.")
if session_list:
media_container = session_list['sessions']
# Check our temp table for what we must do with the new streams
db_streams = monitor_process.get_sessions()
for stream in db_streams:
if any(d['session_key'] == str(stream['session_key']) and d['rating_key'] == str(stream['rating_key'])
for d in media_container):

View File

@@ -119,11 +119,6 @@ AUDIO_CODEC_OVERRIDES = {
VIDEO_RESOLUTION_OVERRIDES = {
'sd': 'SD',
'480': '480p',
'540': '540p',
'576': '576p',
'720': '720p',
'1080': '1080p',
'4k': '4k'
}
@@ -168,11 +163,11 @@ HW_DECODERS = [
'dxva2',
'videotoolbox',
'mediacodecndk',
'vaapi'
'vaapi',
'nvdec'
]
HW_ENCODERS = [
'qsv',
'nvenc',
'mf',
'videotoolbox',
'mediacodecndk',
@@ -366,8 +361,10 @@ NOTIFICATION_PARAMETERS = [
{'name': 'Stream Video Bitrate', 'type': 'int', 'value': 'stream_video_bitrate', 'description': 'The video bitrate (in kbps) of the stream.'},
{'name': 'Stream Video Bit Depth', 'type': 'int', 'value': 'stream_video_bit_depth', 'description': 'The video bit depth of the stream.'},
{'name': 'Stream Video Framerate', 'type': 'str', 'value': 'stream_video_framerate', 'description': 'The video framerate of the stream.'},
{'name': 'Stream Video Full Resolution', 'type': 'str', 'value': 'stream_video_full_resolution', 'description': 'The video resolution of the stream with scan type.'},
{'name': 'Stream Video Ref Frames', 'type': 'int', 'value': 'stream_video_ref_frames', 'description': 'The video reference frames of the stream.'},
{'name': 'Stream Video Resolution', 'type': 'str', 'value': 'stream_video_resolution', 'description': 'The video resolution of the stream.'},
{'name': 'Stream Video Scan Type', 'type': 'str', 'value': 'stream_video_scan_type', 'description': 'The video scan type of the stream.'},
{'name': 'Stream Video Height', 'type': 'int', 'value': 'stream_video_height', 'description': 'The video height of the stream.'},
{'name': 'Stream Video Width', 'type': 'int', 'value': 'stream_video_width', 'description': 'The video width of the stream.'},
{'name': 'Stream Video Language', 'type': 'str', 'value': 'stream_video_language', 'description': 'The video language of the stream.'},
@@ -430,7 +427,7 @@ NOTIFICATION_PARAMETERS = [
{'name': 'Album Count', 'type': 'int', 'value': 'album_count', 'description': 'The number of albums.'},
{'name': 'Track Count', 'type': 'int', 'value': 'track_count', 'description': 'The number of tracks.'},
{'name': 'Year', 'type': 'int', 'value': 'year', 'description': 'The release year for the item.'},
{'name': 'Release Date', 'type': 'int', 'value': 'release_date', 'description': 'The release date (in date format) for the item.'},
{'name': 'Release Date', 'type': 'str', 'value': 'release_date', 'description': 'The release date (in date format) for the item.'},
{'name': 'Air Date', 'type': 'str', 'value': 'air_date', 'description': 'The air date (in date format) for the item.'},
{'name': 'Added Date', 'type': 'str', 'value': 'added_date', 'description': 'The date (in date format) the item was added to Plex.'},
{'name': 'Updated Date', 'type': 'str', 'value': 'updated_date', 'description': 'The date (in date format) the item was updated on Plex.'},
@@ -469,8 +466,10 @@ NOTIFICATION_PARAMETERS = [
{'name': 'Video Bitrate', 'type': 'int', 'value': 'video_bitrate', 'description': 'The video bitrate of the original media.'},
{'name': 'Video Bit Depth', 'type': 'int', 'value': 'video_bit_depth', 'description': 'The video bit depth of the original media.'},
{'name': 'Video Framerate', 'type': 'str', 'value': 'video_framerate', 'description': 'The video framerate of the original media.'},
{'name': 'Video Full Resolution', 'type': 'str', 'value': 'video_full_resolution', 'description': 'The video resolution of the original media with scan type.'},
{'name': 'Video Ref Frames', 'type': 'int', 'value': 'video_ref_frames', 'description': 'The video reference frames of the original media.'},
{'name': 'Video Resolution', 'type': 'str', 'value': 'video_resolution', 'description': 'The video resolution of the original media.'},
{'name': 'Video Scan Tpye', 'type': 'str', 'value': 'video_scan_type', 'description': 'The video scan type of the original media.'},
{'name': 'Video Height', 'type': 'int', 'value': 'video_height', 'description': 'The video height of the original media.'},
{'name': 'Video Width', 'type': 'int', 'value': 'video_width', 'description': 'The video width of the original media.'},
{'name': 'Video Language', 'type': 'str', 'value': 'video_language', 'description': 'The video language of the original media.'},

View File

@@ -624,6 +624,7 @@ _CONFIG_DEFINITIONS = {
'XBMC_ON_CONCURRENT': (int, 'XBMC', 0),
'XBMC_ON_NEWDEVICE': (int, 'XBMC', 0),
'JWT_SECRET': (str, 'Advanced', ''),
'JWT_UPDATE_SECRET': (bool_int, 'Advanced', 0),
'SYSTEM_ANALYTICS': (int, 'Advanced', 1),
'WIN_SYS_TRAY': (int, 'General', 1)
}

View File

@@ -76,6 +76,7 @@ class DataFactory(object):
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" \
THEN users.username ELSE users.friendly_name END) AS friendly_name',
'platform',
'product',
'player',
'ip_address',
'session_history.media_type',
@@ -123,6 +124,7 @@ class DataFactory(object):
'(CASE WHEN friendly_name IS NULL OR TRIM(friendly_name) = "" \
THEN user ELSE friendly_name END) AS friendly_name',
'platform',
'product',
'player',
'ip_address',
'media_type',
@@ -225,6 +227,7 @@ class DataFactory(object):
'user': item['user'],
'friendly_name': item['friendly_name'],
'platform': platform,
'product': item['product'],
'player': item['player'],
'ip_address': item['ip_address'],
'media_type': item['media_type'],
@@ -294,7 +297,7 @@ class DataFactory(object):
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "movie" ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.full_title ' \
'GROUP BY t.full_title, t.year ' \
'ORDER BY %s DESC, started DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query)
@@ -345,7 +348,7 @@ class DataFactory(object):
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "movie" ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.full_title ' \
'GROUP BY t.full_title, t.year ' \
'ORDER BY users_watched DESC, %s DESC, started DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
result = monitor_db.select(query)

View File

@@ -239,7 +239,7 @@ class Libraries(object):
def __init__(self):
pass
def get_datatables_list(self, kwargs=None):
def get_datatables_list(self, kwargs=None, grouping=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
@@ -250,9 +250,14 @@ class Libraries(object):
custom_where = [['library_sections.deleted_section', 0]]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
if session.get_session_shared_libraries():
custom_where.append(['library_sections.section_id', session.get_session_shared_libraries()])
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
columns = ['library_sections.section_id',
'library_sections.section_name',
'library_sections.section_type',
@@ -262,7 +267,7 @@ class Libraries(object):
'library_sections.thumb AS library_thumb',
'library_sections.custom_thumb_url AS custom_thumb',
'library_sections.art',
'COUNT(session_history.id) AS plays',
'COUNT(DISTINCT %s) AS plays' % group_by,
'SUM(CASE WHEN session_history.stopped > 0 THEN (session_history.stopped - session_history.started) \
ELSE 0 END) - SUM(CASE WHEN session_history.paused_counter IS NULL THEN 0 ELSE \
session_history.paused_counter END) AS duration',
@@ -533,7 +538,7 @@ class Libraries(object):
# Search results
search_value = json_data['search']['value'].lower()
if search_value:
searchable_columns = [d['data'] for d in json_data['columns'] if d['searchable']]
searchable_columns = [d['data'] for d in json_data['columns'] if d['searchable']] + ['title']
for row in rows:
for k,v in row.iteritems():
if k in searchable_columns and search_value in v.lower():

View File

@@ -784,8 +784,10 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
'stream_video_bitrate': notify_params['stream_video_bitrate'],
'stream_video_bit_depth': notify_params['stream_video_bit_depth'],
'stream_video_framerate': notify_params['stream_video_framerate'],
'stream_video_full_resolution': notify_params['stream_video_full_resolution'],
'stream_video_ref_frames': notify_params['stream_video_ref_frames'],
'stream_video_resolution': notify_params['stream_video_resolution'],
'stream_video_scan_type': notify_params['stream_video_scan_type'],
'stream_video_height': notify_params['stream_video_height'],
'stream_video_width': notify_params['stream_video_width'],
'stream_video_language': notify_params['stream_video_language'],
@@ -890,8 +892,10 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
'video_bitrate': notify_params['video_bitrate'],
'video_bit_depth': notify_params['video_bit_depth'],
'video_framerate': notify_params['video_framerate'],
'video_full_resolution': notify_params['video_full_resolution'],
'video_ref_frames': notify_params['video_ref_frames'],
'video_resolution': notify_params['video_resolution'],
'video_scan_type': notify_params['video_scan_type'],
'video_height': notify_params['height'],
'video_width': notify_params['width'],
'video_language': notify_params['video_language'],
@@ -1101,6 +1105,8 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
def strip_tag(data, agent_id=None):
# Substitute temporary tokens for < and > in parameter prefix and suffix
data = re.sub(r'{.+?}', lambda m: m.group().replace('<', '%temp_lt_token%').replace('>', '%temp_gt_token%'), data)
if agent_id == 7:
# Allow tags b, i, u, a[href], font[color] for Pushover
@@ -1109,11 +1115,11 @@ def strip_tag(data, agent_id=None):
'u': [],
'a': ['href'],
'font': ['color']}
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
elif agent_id in (10, 14, 20):
# Don't remove tags for Email, Slack, and Discord
return data
pass
elif agent_id == 13:
# Allow tags b, i, code, pre, a[href] for Telegram
@@ -1122,11 +1128,14 @@ def strip_tag(data, agent_id=None):
'code': [],
'pre': [],
'a': ['href']}
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
else:
whitelist = {}
return bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
data = bleach.clean(data, tags=whitelist.keys(), attributes=whitelist, strip=True)
# Resubstitute temporary tokens for < and > in parameter prefix and suffix
return data.replace('%temp_lt_token%', '<').replace('%temp_gt_token%', '>')
def format_group_index(group_keys):
@@ -1332,6 +1341,7 @@ def lookup_tvmaze_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
'tvmaze_json': json.dumps(tvmaze_json)}
db.upsert(table_name='tvmaze_lookup', key_dict=keys, value_dict=tvmaze_info)
tvmaze_info.update(keys)
tvmaze_info.pop('tvmaze_json')
else:
@@ -1394,6 +1404,7 @@ def lookup_themoviedb_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
db.upsert(table_name='themoviedb_lookup', key_dict=keys, value_dict=themoviedb_info)
themoviedb_info.update(keys)
themoviedb_info.pop('themoviedb_json')
else:
@@ -1447,6 +1458,8 @@ def get_themoviedb_info(rating_key=None, media_type=None, themoviedb_id=None):
db.upsert(table_name='themoviedb_lookup', key_dict=keys, value_dict=themoviedb_info)
themoviedb_info.update(keys)
else:
if err_msg:
logger.error(u"Tautulli NotificationHandler :: {}".format(err_msg))

View File

@@ -1242,6 +1242,7 @@ class PmsConnect(object):
'video_language': helpers.get_xml_attr(stream, 'language'),
'video_language_code': helpers.get_xml_attr(stream, 'languageCode'),
'video_profile': helpers.get_xml_attr(stream, 'profile'),
'video_scan_type': helpers.get_xml_attr(stream, 'scanType'),
'selected': int(helpers.get_xml_attr(stream, 'selected') == '1')
})
@@ -1290,7 +1291,7 @@ class PmsConnect(object):
'width': helpers.get_xml_attr(media, 'width'),
'aspect_ratio': helpers.get_xml_attr(media, 'aspectRatio'),
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
'video_resolution': helpers.get_xml_attr(media, 'videoResolution'),
'video_resolution': helpers.get_xml_attr(media, 'videoResolution').lower(),
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
'video_profile': helpers.get_xml_attr(media, 'videoProfile'),
'audio_codec': helpers.get_xml_attr(media, 'audioCodec'),
@@ -1644,12 +1645,15 @@ class PmsConnect(object):
video_stream_info = audio_stream_info = subtitle_stream_info = None
for stream in stream_media_parts_info.getElementsByTagName('Stream'):
if helpers.get_xml_attr(stream, 'streamType') == '1':
if video_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
video_stream_info = stream
elif helpers.get_xml_attr(stream, 'streamType') == '2' and helpers.get_xml_attr(stream, 'selected') == '1':
elif helpers.get_xml_attr(stream, 'streamType') == '2':
if audio_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
audio_stream_info = stream
elif helpers.get_xml_attr(stream, 'streamType') == '3' and helpers.get_xml_attr(stream, 'selected') == '1':
elif helpers.get_xml_attr(stream, 'streamType') == '3':
if subtitle_stream_info is None or helpers.get_xml_attr(stream, 'selected') == '1':
subtitle_stream_info = stream
video_id = audio_id = subtitle_id = None
@@ -1661,6 +1665,7 @@ class PmsConnect(object):
'stream_video_ref_frames': helpers.get_xml_attr(video_stream_info, 'refFrames'),
'stream_video_language': helpers.get_xml_attr(video_stream_info, 'language'),
'stream_video_language_code': helpers.get_xml_attr(video_stream_info, 'languageCode'),
'stream_video_scan_type': helpers.get_xml_attr(video_stream_info, 'scanType'),
'stream_video_decision': helpers.get_xml_attr(video_stream_info, 'decision') or 'direct play'
}
else:
@@ -1670,6 +1675,7 @@ class PmsConnect(object):
'stream_video_ref_frames': '',
'stream_video_language': '',
'stream_video_language_code': '',
'stream_video_scan_type': '',
'stream_video_decision': ''
}
@@ -1730,7 +1736,7 @@ class PmsConnect(object):
if helpers.cast_to_int(stream_video_width) >= 3840:
stream_video_resolution = '4k'
else:
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').rstrip('p')
stream_video_resolution = helpers.get_xml_attr(stream_media_info, 'videoResolution').rstrip('p').lower()
stream_audio_channels = helpers.get_xml_attr(stream_media_info, 'audioChannels')
@@ -1810,7 +1816,7 @@ class PmsConnect(object):
'height': helpers.get_xml_attr(stream_media_info, 'height'),
'width': helpers.get_xml_attr(stream_media_info, 'width'),
'video_codec': helpers.get_xml_attr(stream_media_info, 'videoCodec'),
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution'),
'video_resolution': helpers.get_xml_attr(stream_media_info, 'videoResolution').lower(),
'audio_codec': helpers.get_xml_attr(stream_media_info, 'audioCodec'),
'audio_channels': audio_channels,
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
@@ -1849,6 +1855,7 @@ class PmsConnect(object):
'video_width': '',
'video_language': '',
'video_language_code': '',
'video_scan_type': '',
'video_profile': ''
}
source_audio_details = {'id': '',
@@ -1919,6 +1926,15 @@ class PmsConnect(object):
if transcode_details['transcode_video_codec'] == '*':
transcode_details['transcode_video_codec'] = source_video_details['video_codec']
# Set the full resolution by combining video_resolution and video_scan_type
source_media_details['video_full_resolution'] = plexpy.common.VIDEO_RESOLUTION_OVERRIDES.get(
source_media_details['video_resolution'],
source_media_details['video_resolution'] + (source_video_details['video_scan_type'][:1] or 'p'))
# Set the full resolution by combining stream_video_resolution and stream_video_scan_type
stream_details['stream_video_full_resolution'] = plexpy.common.VIDEO_RESOLUTION_OVERRIDES.get(
stream_details['stream_video_resolution'],
stream_details['stream_video_resolution'] + (video_details['stream_video_scan_type'][:1] or 'p'))
# Get the quality profile
if media_type in ('movie', 'episode', 'clip') and 'stream_bitrate' in stream_details:
if sync_id:
@@ -1945,8 +1961,7 @@ class PmsConnect(object):
if stream_details['optimized_version']:
source_bitrate = helpers.cast_to_int(source_media_details.get('bitrate'))
optimized_version_profile = '{} Mbps {}'.format(round(source_bitrate / 1000.0, 1),
plexpy.common.VIDEO_RESOLUTION_OVERRIDES.get(source_media_details['video_resolution'],
source_media_details['video_resolution']))
source_media_details['video_full_resolution'])
else:
optimized_version_profile = ''
@@ -2467,7 +2482,7 @@ class PmsConnect(object):
media_info = {'container': helpers.get_xml_attr(media, 'container'),
'bitrate': helpers.get_xml_attr(media, 'bitrate'),
'video_codec': helpers.get_xml_attr(media, 'videoCodec'),
'video_resolution': helpers.get_xml_attr(media, 'videoResolution'),
'video_resolution': helpers.get_xml_attr(media, 'videoResolution').lower(),
'video_framerate': helpers.get_xml_attr(media, 'videoFrameRate'),
'audio_codec': helpers.get_xml_attr(media, 'audioCodec'),
'audio_channels': helpers.get_xml_attr(media, 'audioChannels'),

View File

@@ -70,7 +70,7 @@ class Users(object):
def __init__(self):
pass
def get_datatables_list(self, kwargs=None):
def get_datatables_list(self, kwargs=None, grouping=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
@@ -81,18 +81,23 @@ class Users(object):
custom_where = [['users.deleted_user', 0]]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
if session.get_session_user_id():
custom_where.append(['users.user_id', session.get_session_user_id()])
if kwargs.get('user_id'):
custom_where.append(['users.user_id', kwargs.get('user_id')])
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
columns = ['users.user_id',
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" \
THEN users.username ELSE users.friendly_name END) AS friendly_name',
'users.thumb AS user_thumb',
'users.custom_avatar_url AS custom_thumb',
'COUNT(session_history.id) AS plays',
'COUNT(DISTINCT %s) AS plays' % group_by,
'SUM(CASE WHEN session_history.stopped > 0 THEN (session_history.stopped - session_history.started) \
ELSE 0 END) - SUM(CASE WHEN session_history.paused_counter IS NULL THEN 0 ELSE \
session_history.paused_counter END) AS duration',

View File

@@ -1,2 +1,2 @@
PLEXPY_BRANCH = "master"
PLEXPY_RELEASE_VERSION = "v2.1.33"
PLEXPY_BRANCH = "beta"
PLEXPY_RELEASE_VERSION = "v2.1.35-beta"

View File

@@ -353,7 +353,7 @@ class WebInterface(object):
@requireAuth()
@sanitize_out()
@addtoapi("get_libraries_table")
def get_library_list(self, **kwargs):
def get_library_list(self, grouping=None, **kwargs):
""" Get the data on the Tautulli libraries table.
```
@@ -361,6 +361,7 @@ class WebInterface(object):
None
Optional parameters:
grouping (int): 0 or 1
order_column (str): "library_thumb", "section_name", "section_type", "count", "parent_count",
"child_count", "last_accessed", "last_played", "plays", "duration"
order_dir (str): "desc" or "asc"
@@ -423,7 +424,7 @@ class WebInterface(object):
kwargs['json_data'] = build_datatables_json(kwargs, dt_columns, "section_name")
library_data = libraries.Libraries()
library_list = library_data.get_datatables_list(kwargs=kwargs)
library_list = library_data.get_datatables_list(kwargs=kwargs, grouping=grouping)
return library_list
@@ -1016,7 +1017,7 @@ class WebInterface(object):
@requireAuth()
@sanitize_out()
@addtoapi("get_users_table")
def get_user_list(self, **kwargs):
def get_user_list(self, grouping=None, **kwargs):
""" Get the data on Tautulli users table.
```
@@ -1024,6 +1025,7 @@ class WebInterface(object):
None
Optional parameters:
grouping (int): 0 or 1
order_column (str): "user_thumb", "friendly_name", "last_seen", "ip_address", "platform",
"player", "last_played", "plays", "duration"
order_dir (str): "desc" or "asc"
@@ -1082,7 +1084,7 @@ class WebInterface(object):
kwargs['json_data'] = build_datatables_json(kwargs, dt_columns, "friendly_name")
user_data = users.Users()
user_list = user_data.get_datatables_list(kwargs=kwargs)
user_list = user_data.get_datatables_list(kwargs=kwargs, grouping=grouping)
return user_list
@@ -1628,8 +1630,9 @@ class WebInterface(object):
"parent_title": "",
"paused_counter": 0,
"percent_complete": 84,
"platform": "Chrome",
"player": "Plex Web (Chrome)",
"platform": "Windows",
"product": "Plex for Windows",
"player": "Castle-PC",
"rating_key": 4348,
"reference_id": 1123,
"session_key": null,
@@ -1658,6 +1661,7 @@ class WebInterface(object):
("friendly_name", True, True),
("ip_address", True, True),
("platform", True, True),
("product", True, True),
("player", True, True),
("full_title", True, True),
("started", True, False),
@@ -2857,8 +2861,15 @@ class WebInterface(object):
kwargs['http_password'] = make_hash(kwargs['http_password'])
kwargs['http_hashed_password'] = 1
# Flag to refresh JWT uuid to log out clients
kwargs['jwt_update_secret'] = True
elif not kwargs.get('http_hash_password'):
kwargs['http_hashed_password'] = 0
# Flag to refresh JWT uuid to log out clients
kwargs['jwt_update_secret'] = True
else:
kwargs['http_hashed_password'] = 0
@@ -3657,10 +3668,10 @@ class WebInterface(object):
identifier = server['clientIdentifier']
break
# Fallback to checking /identity endpoint is server is unpublished
# Fallback to checking /identity endpoint if the server is unpublished
# Cannot set SSL settings on the PMS if unpublished so 'http' is okay
if not identifier:
scheme = 'https' if ssl else 'http'
scheme = 'https' if helpers.cast_to_int(ssl) else 'http'
url = '{scheme}://{hostname}:{port}'.format(scheme=scheme, hostname=hostname, port=port)
uri = '/identity'
@@ -5031,7 +5042,9 @@ class WebInterface(object):
"stream_video_language": "",
"stream_video_language_code": "",
"stream_video_ref_frames": "4",
"stream_video_full_resolution": "1080p",
"stream_video_resolution": "1080",
"stream_video_scan_type": "progressive",
"stream_video_width": "1920",
"studio": "HBO",
"subtitle_codec": "",
@@ -5084,12 +5097,14 @@ class WebInterface(object):
"video_decision": "direct play",
"video_frame_rate": "23.976",
"video_framerate": "24p",
"video_full_resolution": "1080p",
"video_height": "1078",
"video_language": "",
"video_language_code": "",
"video_profile": "high",
"video_ref_frames": "4",
"video_resolution": "1080",
"video_scan_type": "progressive",
"video_width": "1920",
"view_offset": "1000",
"width": "1920",