Compare commits
13 Commits
v2.0.25
...
v2.0.26-be
Author | SHA1 | Date | |
---|---|---|---|
![]() |
818e7723ff | ||
![]() |
a69008e179 | ||
![]() |
91c647f9ae | ||
![]() |
36b80aa6d3 | ||
![]() |
c35fcc727c | ||
![]() |
749e1fcebe | ||
![]() |
084732706d | ||
![]() |
2aff7713cd | ||
![]() |
683a782723 | ||
![]() |
5108e1bb09 | ||
![]() |
d8298a12eb | ||
![]() |
042b48c1fd | ||
![]() |
8fac54aa71 |
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,9 +1,20 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 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)
|
## v2.0.25 (2018-03-22)
|
||||||
|
|
||||||
* Monitoring:
|
* Monitoring:
|
||||||
* Fix: Fix websocket not reconnecting causing activity monitoring and notifications to not work.
|
* Fix: Websocket not reconnecting causing activity monitoring and notifications to not work.
|
||||||
* Fix: Error checking for synced streams without Plex Pass.
|
* Fix: Error checking for synced streams without Plex Pass.
|
||||||
|
|
||||||
|
|
||||||
|
@@ -294,10 +294,6 @@ object {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
.padded-header h3 small {
|
|
||||||
font-size: 13px;
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
.btn {
|
.btn {
|
||||||
outline:0px !important;
|
outline:0px !important;
|
||||||
}
|
}
|
||||||
@@ -2377,6 +2373,18 @@ a .library-user-instance-box:hover {
|
|||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
width: 175px;
|
width: 175px;
|
||||||
}
|
}
|
||||||
|
.home-padded-header .info-bar {
|
||||||
|
float: left;
|
||||||
|
margin-left: 15px;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
.home-padded-header .info-bar small {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: normal;
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
.home-padded-header .button-bar {
|
.home-padded-header .button-bar {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,7 @@ DOCUMENTATION :: END
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from urllib import quote
|
from urllib import quote
|
||||||
from plexpy import helpers
|
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
|
import plexpy
|
||||||
%>
|
%>
|
||||||
<%
|
<%
|
||||||
@@ -108,7 +108,11 @@ DOCUMENTATION :: END
|
|||||||
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-cover" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=300&fallback=cover&refresh=true);"></div>
|
||||||
</a>
|
</a>
|
||||||
% elif data['media_type'] in ('photo', 'clip'):
|
% elif data['media_type'] in ('photo', 'clip'):
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
% if data['extra_type']:
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['art'].replace('/art', '/thumb') or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||||
|
% else:
|
||||||
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(pms_image_proxy?img=${data['parent_thumb'] or data['thumb']}&width=300&height=450&fallback=poster&refresh=true);"></div>
|
||||||
|
% endif
|
||||||
% else:
|
% else:
|
||||||
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/art.png);"></div>
|
<div id="poster-${sk}" class="dashboard-activity-poster" style="background-image: url(images/art.png);"></div>
|
||||||
% endif
|
% endif
|
||||||
@@ -301,10 +305,9 @@ DOCUMENTATION :: END
|
|||||||
<li class="dashboard-activity-info-item">
|
<li class="dashboard-activity-info-item">
|
||||||
<div class="sub-heading">Bandwidth</div>
|
<div class="sub-heading">Bandwidth</div>
|
||||||
<div class="sub-value time-right">
|
<div class="sub-value time-right">
|
||||||
% if data['media_type'] != 'photo' and helpers.cast_to_int(data['bandwidth']):
|
% if data['media_type'] != 'photo' and data['bandwidth'] != 'Unknown':
|
||||||
<%
|
<%
|
||||||
bw = helpers.cast_to_int(data['bandwidth'])
|
bw = helpers.cast_to_int(data['bandwidth'])
|
||||||
if bw != "Unknown":
|
|
||||||
if bw > 1000:
|
if bw > 1000:
|
||||||
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
|
bw = str(round(bw / 1000.0, 1)) + ' Mbps'
|
||||||
else:
|
else:
|
||||||
@@ -439,9 +442,14 @@ DOCUMENTATION :: END
|
|||||||
<a id="metadata-parent_title-${sk}" href="${parent_href}" title="${data['parent_title']}" class="sub-heading">${data['parent_title']}</a>
|
<a id="metadata-parent_title-${sk}" href="${parent_href}" title="${data['parent_title']}" class="sub-heading">${data['parent_title']}</a>
|
||||||
% elif data['media_type'] == 'photo':
|
% elif data['media_type'] == 'photo':
|
||||||
<span title="${data['title']}" class="sub-heading">${data['title']}</span>
|
<span title="${data['title']}" class="sub-heading">${data['title']}</span>
|
||||||
|
% else:
|
||||||
|
% if data['extra_type']:
|
||||||
|
<% extra_type = EXTRA_TYPES.get(data['extra_type'], data['sub_type'].capitalize()) %>
|
||||||
|
<span title="${data['year']} (${extra_type})" class="sub-heading">${data['year']} (${extra_type})</span>
|
||||||
% else:
|
% else:
|
||||||
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
<span title="${data['year']}" class="sub-heading">${data['year']}</span>
|
||||||
% endif
|
% endif
|
||||||
|
% endif
|
||||||
% elif data['channel_title']:
|
% elif data['channel_title']:
|
||||||
<span title="${data['channel_title']}" class="sub-heading">${data['channel_title']}</span>
|
<span title="${data['channel_title']}" class="sub-heading">${data['channel_title']}</span>
|
||||||
% if data['media_type'] == 'episode' and data['parent_media_index'] and data['media_index']:
|
% if data['media_type'] == 'episode' and data['parent_media_index'] and data['media_index']:
|
||||||
|
@@ -113,7 +113,7 @@
|
|||||||
// Load user ids and names (for the selector)
|
// Load user ids and names (for the selector)
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_user_names',
|
url: 'get_user_names',
|
||||||
type: 'get',
|
type: 'GET',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var select = $('#history-user');
|
var select = $('#history-user');
|
||||||
@@ -130,6 +130,7 @@
|
|||||||
function loadHistoryTable(media_type, selected_user_id) {
|
function loadHistoryTable(media_type, selected_user_id) {
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
|
type: 'POST',
|
||||||
data: function (d) {
|
data: function (d) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify(d),
|
json_data: JSON.stringify(d),
|
||||||
|
@@ -10,8 +10,16 @@
|
|||||||
% if section == 'current_activity':
|
% if section == 'current_activity':
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<div class="padded-header" id="current-activity-header">
|
<div class="home-padded-header padded-header" id="current-activity-header">
|
||||||
<h3><span id="sessions-shortcut">Activity</span>
|
<h3 class="pull-left"><span id="sessions-shortcut">Current Activity</span></h3>
|
||||||
|
<div class="button-bar">
|
||||||
|
<div class="input-group pull-left" style="width: 1px; margin-right: 3px" id="activity-refresh-interval-selection">
|
||||||
|
<span class="input-group-addon btn-dark inactive">Refresh Every</span>
|
||||||
|
<input type="number" class="form-control number-input" name="activity-refresh-interval" id="activity-refresh-interval" value="${config['home_refresh_interval']}" min="2" data-default="2" data-toggle="tooltip" title="Min: 2 seconds" />
|
||||||
|
<span class="input-group-addon btn-dark inactive">seconds</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-bar">
|
||||||
<small>
|
<small>
|
||||||
<span id="currentActivityHeader" style="display: none;">
|
<span id="currentActivityHeader" style="display: none;">
|
||||||
Streams: <span id="currentActivityHeader-streams"></span> |
|
Streams: <span id="currentActivityHeader-streams"></span> |
|
||||||
@@ -19,7 +27,7 @@
|
|||||||
<span id="currentActivityHeader-bandwidth-tooltip" data-toggle="tooltip" title="Streaming Brain Estimate (Required Bandwidth)"><i class="fa fa-info-circle"></i></span>
|
<span id="currentActivityHeader-bandwidth-tooltip" data-toggle="tooltip" title="Streaming Brain Estimate (Required Bandwidth)"><i class="fa fa-info-circle"></i></span>
|
||||||
</span>
|
</span>
|
||||||
</small>
|
</small>
|
||||||
</h3>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="currentActivity">
|
<div id="currentActivity">
|
||||||
<% from plexpy import PLEX_SERVER_UP %>
|
<% from plexpy import PLEX_SERVER_UP %>
|
||||||
@@ -507,17 +515,15 @@
|
|||||||
|
|
||||||
$('#location-' + key).html(s.location.toUpperCase());
|
$('#location-' + key).html(s.location.toUpperCase());
|
||||||
|
|
||||||
if (s.media_type !== 'photo' && parseInt(s.bandwidth)) {
|
if (s.media_type !== 'photo' && s.bandwidth !== 'Unknown') {
|
||||||
var bw = parseInt(s.bandwidth);
|
var bw = parseInt(s.bandwidth) || 0;
|
||||||
if (bw !== "Unknown") {
|
|
||||||
if (bw > 1000) {
|
if (bw > 1000) {
|
||||||
bw = (bw / 1000).toFixed(1) + ' Mbps';
|
bw = (bw / 1000).toFixed(1) + ' Mbps';
|
||||||
} else {
|
} else {
|
||||||
bw = bw + ' kbps'
|
bw = bw + ' kbps'
|
||||||
}
|
}
|
||||||
}
|
|
||||||
$('#stream-bandwidth-' + key).html(bw);
|
$('#stream-bandwidth-' + key).html(bw);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Update the stream progress times
|
// Update the stream progress times
|
||||||
$('#stream-eta-' + key).html(moment().add(parseInt(s.duration) - parseInt(s.view_offset), 'milliseconds').format(time_format));
|
$('#stream-eta-' + key).html(moment().add(parseInt(s.duration) - parseInt(s.view_offset), 'milliseconds').format(time_format));
|
||||||
@@ -585,11 +591,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
getCurrentActivity();
|
getCurrentActivity();
|
||||||
setInterval(function () {
|
|
||||||
|
function refreshActivity(seconds) {
|
||||||
|
return setInterval(function () {
|
||||||
if (!(create_instances.length) && activity_ready) {
|
if (!(create_instances.length) && activity_ready) {
|
||||||
getCurrentActivity();
|
getCurrentActivity();
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, seconds * 1000);
|
||||||
|
}
|
||||||
|
var refresh_interval = $('#activity-refresh-interval').val();
|
||||||
|
var activityRefresh = refreshActivity(refresh_interval);
|
||||||
|
|
||||||
setInterval(function(){
|
setInterval(function(){
|
||||||
$('.progress_time_offset').each(function () {
|
$('.progress_time_offset').each(function () {
|
||||||
@@ -604,7 +615,7 @@
|
|||||||
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
if ($(this).data('state') === 'playing' && $(this).data('view_offset') >= 0) {
|
||||||
var view_offset = parseInt($(this).data('view_offset'));
|
var view_offset = parseInt($(this).data('view_offset'));
|
||||||
var stream_duration = parseInt($(this).data('stream_duration'));
|
var stream_duration = parseInt($(this).data('stream_duration'));
|
||||||
var progress_percent = Math.min(Math.trunc(view_offset / stream_duration * 100), 100)
|
var progress_percent = Math.min(Math.trunc(view_offset / stream_duration * 100), 100);
|
||||||
$(this).width(progress_percent - 3 + '%').html(progress_percent + '%')
|
$(this).width(progress_percent - 3 + '%').html(progress_percent + '%')
|
||||||
.attr('data-original-title', 'Stream Progress ' + progress_percent + '%')
|
.attr('data-original-title', 'Stream Progress ' + progress_percent + '%')
|
||||||
.data('view_offset', Math.min(view_offset + 1000, stream_duration));
|
.data('view_offset', Math.min(view_offset + 1000, stream_duration));
|
||||||
@@ -685,6 +696,16 @@
|
|||||||
window.open(sessions_url, '_blank');
|
window.open(sessions_url, '_blank');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#activity-refresh-interval').change(function () {
|
||||||
|
forceMinMax($(this));
|
||||||
|
clearInterval(activityRefresh);
|
||||||
|
refresh_interval = $(this).val();
|
||||||
|
activityRefresh = refreshActivity(refresh_interval);
|
||||||
|
$.post('set_home_stats_config', { refresh_interval: refresh_interval });
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#activity-refresh-interval').tooltip({ container: 'body', placement: 'top', html: true });
|
||||||
% endif
|
% endif
|
||||||
</script>
|
</script>
|
||||||
% endif
|
% endif
|
||||||
|
@@ -547,7 +547,7 @@ DOCUMENTATION :: END
|
|||||||
function get_history() {
|
function get_history() {
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
@@ -563,7 +563,7 @@ DOCUMENTATION :: END
|
|||||||
function get_history() {
|
function get_history() {
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
@@ -579,7 +579,7 @@ DOCUMENTATION :: END
|
|||||||
function get_history() {
|
function get_history() {
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
|
@@ -37,7 +37,6 @@ sync_table_options = {
|
|||||||
"data": "state",
|
"data": "state",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData === 'pending') {
|
if (cellData === 'pending') {
|
||||||
$(td).addClass('currentlyWatching');
|
|
||||||
$(td).html('Pending...');
|
$(td).html('Pending...');
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData.toProperCase());
|
$(td).html(cellData.toProperCase());
|
||||||
@@ -66,7 +65,7 @@ sync_table_options = {
|
|||||||
"data": "sync_title",
|
"data": "sync_title",
|
||||||
"createdCell": function (td, cellData, rowData, row, col) {
|
"createdCell": function (td, cellData, rowData, row, col) {
|
||||||
if (cellData !== '') {
|
if (cellData !== '') {
|
||||||
if (rowData['metadata_type'] !== '') {
|
if (rowData['rating_key']) {
|
||||||
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
|
||||||
} else {
|
} else {
|
||||||
$(td).html(cellData);
|
$(td).html(cellData);
|
||||||
@@ -74,7 +73,7 @@ sync_table_options = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"className": "datatable-wrap"
|
"className": "datatable-wrap"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"targets": [4],
|
"targets": [4],
|
||||||
"data": "metadata_type",
|
"data": "metadata_type",
|
||||||
@@ -150,6 +149,11 @@ sync_table_options = {
|
|||||||
"preDrawCallback": function (settings) {
|
"preDrawCallback": function (settings) {
|
||||||
var msg = "<i class='fa fa-refresh fa-spin'></i> Fetching rows...";
|
var msg = "<i class='fa fa-refresh fa-spin'></i> Fetching rows...";
|
||||||
showMsg(msg, false, false, 0)
|
showMsg(msg, false, false, 0)
|
||||||
|
},
|
||||||
|
"rowCallback": function (row, rowData, rowIndex) {
|
||||||
|
if (rowData['state'] === 'pending') {
|
||||||
|
$(row).addClass('current-activity-row');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -91,7 +91,7 @@
|
|||||||
json_data: JSON.stringify(d)
|
json_data: JSON.stringify(d)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
libraries_list_table = $('#libraries_list_table').DataTable(libraries_list_table_options);
|
libraries_list_table = $('#libraries_list_table').DataTable(libraries_list_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(libraries_list_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 1] });
|
var colvis = new $.fn.dataTable.ColVis(libraries_list_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 1] });
|
||||||
|
@@ -374,7 +374,7 @@ DOCUMENTATION :: END
|
|||||||
// Build watch history table
|
// Build watch history table
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
@@ -406,7 +406,7 @@ DOCUMENTATION :: END
|
|||||||
// Build media info table
|
// Build media info table
|
||||||
media_info_table_options.ajax = {
|
media_info_table_options.ajax = {
|
||||||
url: 'get_library_media_info',
|
url: 'get_library_media_info',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
|
@@ -229,8 +229,8 @@
|
|||||||
var selected_log_level = null;
|
var selected_log_level = null;
|
||||||
function loadtautullilogs(logfile, selected_log_level) {
|
function loadtautullilogs(logfile, selected_log_level) {
|
||||||
log_table_options.ajax = {
|
log_table_options.ajax = {
|
||||||
url: "get_log",
|
url: 'get_log',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function (d) {
|
data: function (d) {
|
||||||
return {
|
return {
|
||||||
logfile: logfile,
|
logfile: logfile,
|
||||||
@@ -249,7 +249,8 @@
|
|||||||
|
|
||||||
function loadPlexLogs() {
|
function loadPlexLogs() {
|
||||||
plex_log_table_options.ajax = {
|
plex_log_table_options.ajax = {
|
||||||
url: "get_plex_log?log_type=server"
|
url: 'get_plex_log?log_type=server',
|
||||||
|
type: 'POST'
|
||||||
};
|
};
|
||||||
plex_log_table_options.initComplete = bindLogLevelFilter;
|
plex_log_table_options.initComplete = bindLogLevelFilter;
|
||||||
plex_log_table = $('#plex_log_table').DataTable(plex_log_table_options);
|
plex_log_table = $('#plex_log_table').DataTable(plex_log_table_options);
|
||||||
@@ -257,7 +258,8 @@
|
|||||||
|
|
||||||
function loadPlexScannerLogs() {
|
function loadPlexScannerLogs() {
|
||||||
plex_log_table_options.ajax = {
|
plex_log_table_options.ajax = {
|
||||||
url: "get_plex_log?log_type=scanner"
|
url: 'get_plex_log?log_type=scanner',
|
||||||
|
type: 'POST'
|
||||||
};
|
};
|
||||||
plex_log_table_options.initComplete = bindLogLevelFilter;
|
plex_log_table_options.initComplete = bindLogLevelFilter;
|
||||||
plex_scanner_log_table = $('#plex_scanner_log_table').DataTable(plex_log_table_options);
|
plex_scanner_log_table = $('#plex_scanner_log_table').DataTable(plex_log_table_options);
|
||||||
@@ -265,7 +267,8 @@
|
|||||||
|
|
||||||
function loadNotificationLogs() {
|
function loadNotificationLogs() {
|
||||||
notification_log_table_options.ajax = {
|
notification_log_table_options.ajax = {
|
||||||
url: "get_notification_log",
|
url: 'get_notification_log',
|
||||||
|
type: 'POST',
|
||||||
data: function (d) {
|
data: function (d) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify(d)
|
json_data: JSON.stringify(d)
|
||||||
@@ -278,7 +281,8 @@
|
|||||||
function loadLoginLogs() {
|
function loadLoginLogs() {
|
||||||
login_log_table_options.pageLength = 50;
|
login_log_table_options.pageLength = 50;
|
||||||
login_log_table_options.ajax = {
|
login_log_table_options.ajax = {
|
||||||
url: "get_user_logins",
|
url: 'get_user_logins',
|
||||||
|
type: 'POST',
|
||||||
data: function (d) {
|
data: function (d) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify(d)
|
json_data: JSON.stringify(d)
|
||||||
|
@@ -267,6 +267,10 @@
|
|||||||
|
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-homepage">
|
<div role="tabpanel" class="tab-pane" id="tabs-homepage">
|
||||||
|
|
||||||
|
<div class="padded-header">
|
||||||
|
<h3>Activity</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>Sections</h3>
|
<h3>Sections</h3>
|
||||||
</div>
|
</div>
|
||||||
@@ -666,12 +670,7 @@
|
|||||||
<label for="pms_url">Plex Server URL</label>
|
<label for="pms_url">Plex Server URL</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" id="pms_url" name="pms_url" value="${config['pms_url']}" size="30" readonly>
|
<input type="text" class="form-control" id="pms_url" name="pms_url" value="${config['pms_url']}" size="30" readonly>
|
||||||
<span class="input-group-btn">
|
|
||||||
<button class="btn btn-form" type="button" id="test_pms_url_button">Test URL</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
@@ -1861,6 +1860,9 @@ $(document).ready(function() {
|
|||||||
$('#pms_url_manual').prop('checked', false);
|
$('#pms_url_manual').prop('checked', false);
|
||||||
$('#pms_url').val('Please verify your server above to retrieve the URL');
|
$('#pms_url').val('Please verify your server above to retrieve the URL');
|
||||||
PMSCloudCheck();
|
PMSCloudCheck();
|
||||||
|
},
|
||||||
|
onDropdownOpen: function() {
|
||||||
|
this.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var select_pms = $select_pms[0].selectize;
|
var select_pms = $select_pms[0].selectize;
|
||||||
@@ -1934,11 +1936,11 @@ $(document).ready(function() {
|
|||||||
data: {
|
data: {
|
||||||
hostname: pms_ip,
|
hostname: pms_ip,
|
||||||
port: pms_port,
|
port: pms_port,
|
||||||
identifier: pms_identifier,
|
|
||||||
ssl: pms_ssl,
|
ssl: pms_ssl,
|
||||||
remote: pms_is_remote,
|
remote: pms_is_remote,
|
||||||
manual: pms_url_manual,
|
manual: pms_url_manual,
|
||||||
get_url: serverChanged
|
get_url: true,
|
||||||
|
test_websocket: true
|
||||||
},
|
},
|
||||||
cache: true,
|
cache: true,
|
||||||
async: true,
|
async: true,
|
||||||
@@ -1951,15 +1953,23 @@ $(document).ready(function() {
|
|||||||
var result = xhr;
|
var result = xhr;
|
||||||
var identifier = result.identifier;
|
var identifier = result.identifier;
|
||||||
var url = result.url;
|
var url = result.url;
|
||||||
|
var ws = result.ws;
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
$("#pms_identifier").val(identifier);
|
$("#pms_identifier").val(identifier);
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
$("#pms_url").val(url);
|
$("#pms_url").val(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ws === false) {
|
||||||
|
$("#pms_verify").html('<i class="fa fa-close"></i>').fadeIn('fast');
|
||||||
|
$("#pms_ip_group").addClass("has-error");
|
||||||
|
showMsg('<i class="fa fa-exclamation-circle"></i> Server found but unable to connect websocket.<br>Check the <a href="logs">logs</a> for errors.', false, true, 5000, true)
|
||||||
|
} else {
|
||||||
$("#pms_verify").html('<i class="fa fa-check"></i>').fadeIn('fast');
|
$("#pms_verify").html('<i class="fa fa-check"></i>').fadeIn('fast');
|
||||||
$("#pms_ip_group").removeClass("has-error");
|
$("#pms_ip_group").removeClass("has-error");
|
||||||
|
|
||||||
serverChanged = false;
|
serverChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (_callback) {
|
if (_callback) {
|
||||||
_callback();
|
_callback();
|
||||||
@@ -1987,13 +1997,6 @@ $(document).ready(function() {
|
|||||||
$("#pms_web_url").val(pms_web_url || 'https://app.plex.tv/desktop');
|
$("#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(){
|
$('#test_pms_web_button').on('click', function(){
|
||||||
var pms_web_url = $.trim($("#pms_web_url").val());
|
var pms_web_url = $.trim($("#pms_web_url").val());
|
||||||
window.open(pms_web_url, '_blank');
|
window.open(pms_web_url, '_blank');
|
||||||
|
@@ -100,7 +100,7 @@
|
|||||||
// Load user ids and names (for the selector)
|
// Load user ids and names (for the selector)
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: 'get_user_names',
|
url: 'get_user_names',
|
||||||
type: 'get',
|
type: 'GET',
|
||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
success: function (data) {
|
success: function (data) {
|
||||||
var select = $('#sync-user');
|
var select = $('#sync-user');
|
||||||
@@ -116,7 +116,8 @@
|
|||||||
|
|
||||||
function loadSyncTable(selected_user_id) {
|
function loadSyncTable(selected_user_id) {
|
||||||
sync_table_options.ajax = {
|
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);
|
sync_table = $('#sync_table').DataTable(sync_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(sync_table, {
|
var colvis = new $.fn.dataTable.ColVis(sync_table, {
|
||||||
|
@@ -413,7 +413,7 @@ DOCUMENTATION :: END
|
|||||||
// Build watch history table
|
// Build watch history table
|
||||||
history_table_options.ajax = {
|
history_table_options.ajax = {
|
||||||
url: 'get_history',
|
url: 'get_history',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
@@ -442,7 +442,8 @@ DOCUMENTATION :: END
|
|||||||
function loadSyncTable() {
|
function loadSyncTable() {
|
||||||
// Build user sync table
|
// Build user sync table
|
||||||
sync_table_options.ajax = {
|
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 = $('#sync_table-UID-${data["user_id"]}').DataTable(sync_table_options);
|
||||||
sync_table.column(2).visible(false);
|
sync_table.column(2).visible(false);
|
||||||
@@ -457,7 +458,7 @@ DOCUMENTATION :: END
|
|||||||
// Build user IP table
|
// Build user IP table
|
||||||
user_ip_table_options.ajax = {
|
user_ip_table_options.ajax = {
|
||||||
url: 'get_user_ips',
|
url: 'get_user_ips',
|
||||||
type: 'post',
|
type: 'POST',
|
||||||
data: function ( d ) {
|
data: function ( d ) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify( d ),
|
json_data: JSON.stringify( d ),
|
||||||
@@ -474,6 +475,7 @@ DOCUMENTATION :: END
|
|||||||
// Build user login table
|
// Build user login table
|
||||||
login_log_table_options.ajax = {
|
login_log_table_options.ajax = {
|
||||||
url: 'get_user_logins',
|
url: 'get_user_logins',
|
||||||
|
type: 'POST',
|
||||||
data: function(d) {
|
data: function(d) {
|
||||||
return {
|
return {
|
||||||
json_data: JSON.stringify(d),
|
json_data: JSON.stringify(d),
|
||||||
|
@@ -94,7 +94,7 @@
|
|||||||
json_data: JSON.stringify(d)
|
json_data: JSON.stringify(d)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
users_list_table = $('#users_list_table').DataTable(users_list_table_options);
|
users_list_table = $('#users_list_table').DataTable(users_list_table_options);
|
||||||
var colvis = new $.fn.dataTable.ColVis(users_list_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 1] });
|
var colvis = new $.fn.dataTable.ColVis(users_list_table, { buttonText: '<i class="fa fa-columns"></i> Select columns', buttonClass: 'btn btn-dark', exclude: [0, 1] });
|
||||||
|
@@ -374,6 +374,9 @@ $(document).ready(function() {
|
|||||||
$('#pms_is_remote_checkbox').prop('disabled', false);
|
$('#pms_is_remote_checkbox').prop('disabled', false);
|
||||||
$('#pms_ssl_checkbox').prop('disabled', false);
|
$('#pms_ssl_checkbox').prop('disabled', false);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onDropdownOpen: function() {
|
||||||
|
this.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var select_pms = $select_pms[0].selectize;
|
var select_pms = $select_pms[0].selectize;
|
||||||
|
@@ -1597,6 +1597,9 @@ def dbcheck():
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Rename notifiers in the database
|
# Rename notifiers in the database
|
||||||
|
result = c_db.execute('SELECT agent_label FROM notifiers '
|
||||||
|
'WHERE agent_label = "XBMC" OR agent_label = "OSX Notify"').fetchone()
|
||||||
|
if result:
|
||||||
logger.debug(u"Altering database. Renaming notifiers.")
|
logger.debug(u"Altering database. Renaming notifiers.")
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'UPDATE notifiers SET agent_label = "Kodi" WHERE agent_label = "XBMC"'
|
'UPDATE notifiers SET agent_label = "Kodi" WHERE agent_label = "XBMC"'
|
||||||
|
@@ -171,6 +171,16 @@ HW_ENCODERS = [
|
|||||||
'nvenc'
|
'nvenc'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
EXTRA_TYPES = {
|
||||||
|
'1': 'Trailer',
|
||||||
|
'2': 'Deleted Scene',
|
||||||
|
'3': 'Interview',
|
||||||
|
'5': 'Behind the Scenes',
|
||||||
|
'6': 'Scene',
|
||||||
|
'10': 'Featurette',
|
||||||
|
'11': 'Short'
|
||||||
|
}
|
||||||
|
|
||||||
SCHEDULER_LIST = [
|
SCHEDULER_LIST = [
|
||||||
'Check GitHub for updates',
|
'Check GitHub for updates',
|
||||||
'Check for server response',
|
'Check for server response',
|
||||||
|
@@ -209,6 +209,7 @@ _CONFIG_DEFINITIONS = {
|
|||||||
'HOME_STATS_CARDS': (list, 'General', ['top_movies', 'popular_movies', 'top_tv', 'popular_tv', 'top_music', \
|
'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']),
|
'popular_music', 'last_watched', 'top_users', 'top_platforms', 'most_concurrent']),
|
||||||
'HOME_STATS_RECENTLY_ADDED_COUNT': (int, 'General', 50),
|
'HOME_STATS_RECENTLY_ADDED_COUNT': (int, 'General', 50),
|
||||||
|
'HOME_REFRESH_INTERVAL': (int, 'General', 10),
|
||||||
'HTTPS_CREATE_CERT': (int, 'General', 1),
|
'HTTPS_CREATE_CERT': (int, 'General', 1),
|
||||||
'HTTPS_CERT': (str, 'General', ''),
|
'HTTPS_CERT': (str, 'General', ''),
|
||||||
'HTTPS_CERT_CHAIN': (str, 'General', ''),
|
'HTTPS_CERT_CHAIN': (str, 'General', ''),
|
||||||
|
@@ -3307,11 +3307,18 @@ class TELEGRAM(Notifier):
|
|||||||
if poster_content:
|
if poster_content:
|
||||||
poster_filename = 'poster_{}.jpg'.format(pretty_metadata.parameters['rating_key'])
|
poster_filename = 'poster_{}.jpg'.format(pretty_metadata.parameters['rating_key'])
|
||||||
files = {'photo': (poster_filename, poster_content, 'image/jpeg')}
|
files = {'photo': (poster_filename, poster_content, 'image/jpeg')}
|
||||||
|
|
||||||
|
if len(text) > 200:
|
||||||
|
data['disable_notification'] = True
|
||||||
|
else:
|
||||||
data['caption'] = text
|
data['caption'] = text
|
||||||
|
|
||||||
return self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']),
|
r = self.make_request('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']),
|
||||||
data=data, files=files)
|
data=data, files=files)
|
||||||
|
|
||||||
|
if not data.pop('disable_notification', None):
|
||||||
|
return r
|
||||||
|
|
||||||
data['text'] = text
|
data['text'] = text
|
||||||
|
|
||||||
if self.config['disable_web_preview']:
|
if self.config['disable_web_preview']:
|
||||||
|
@@ -1096,7 +1096,9 @@ class PmsConnect(object):
|
|||||||
'genres': genres,
|
'genres': genres,
|
||||||
'labels': labels,
|
'labels': labels,
|
||||||
'collections': collections,
|
'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:
|
else:
|
||||||
@@ -1687,7 +1689,9 @@ class PmsConnect(object):
|
|||||||
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
'audio_channel_layout': common.AUDIO_CHANNELS.get(audio_channels, audio_channels),
|
||||||
'channel_icon': helpers.get_xml_attr(session, 'sourceIcon'),
|
'channel_icon': helpers.get_xml_attr(session, 'sourceIcon'),
|
||||||
'channel_title': helpers.get_xml_attr(session, 'sourceTitle'),
|
'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:
|
else:
|
||||||
channel_stream = 0
|
channel_stream = 0
|
||||||
|
@@ -1,2 +1,2 @@
|
|||||||
PLEXPY_BRANCH = "master"
|
PLEXPY_BRANCH = "beta"
|
||||||
PLEXPY_RELEASE_VERSION = "v2.0.25"
|
PLEXPY_RELEASE_VERSION = "v2.0.26-beta"
|
||||||
|
@@ -27,6 +27,8 @@ from hashing_passwords import make_hash
|
|||||||
from mako.lookup import TemplateLookup
|
from mako.lookup import TemplateLookup
|
||||||
from mako import exceptions
|
from mako import exceptions
|
||||||
|
|
||||||
|
import websocket
|
||||||
|
|
||||||
import plexpy
|
import plexpy
|
||||||
import activity_pinger
|
import activity_pinger
|
||||||
import common
|
import common
|
||||||
@@ -171,6 +173,7 @@ class WebInterface(object):
|
|||||||
"home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE,
|
"home_stats_type": plexpy.CONFIG.HOME_STATS_TYPE,
|
||||||
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
|
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
|
||||||
"home_stats_recently_added_count": plexpy.CONFIG.HOME_STATS_RECENTLY_ADDED_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_name": plexpy.CONFIG.PMS_NAME,
|
||||||
"pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD,
|
"pms_is_cloud": plexpy.CONFIG.PMS_IS_CLOUD,
|
||||||
"update_show_changelog": plexpy.CONFIG.UPDATE_SHOW_CHANGELOG
|
"update_show_changelog": plexpy.CONFIG.UPDATE_SHOW_CHANGELOG
|
||||||
@@ -283,7 +286,11 @@ class WebInterface(object):
|
|||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def set_home_stats_config(self, time_range=None, stats_type=None, stats_count=None, recently_added_count=None, **kwargs):
|
def set_home_stats_config(self, refresh_interval=None, time_range=None, stats_type=None, stats_count=None,
|
||||||
|
recently_added_count=None, **kwargs):
|
||||||
|
if refresh_interval:
|
||||||
|
plexpy.CONFIG.__setattr__('HOME_REFRESH_INTERVAL', refresh_interval)
|
||||||
|
plexpy.CONFIG.write()
|
||||||
if time_range:
|
if time_range:
|
||||||
plexpy.CONFIG.__setattr__('HOME_STATS_LENGTH', time_range)
|
plexpy.CONFIG.__setattr__('HOME_STATS_LENGTH', time_range)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
@@ -3463,7 +3470,7 @@ class WebInterface(object):
|
|||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_server_id(self, hostname=None, port=None, identifier=None, ssl=0, remote=0, manual=0,
|
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.
|
""" Get the PMS server identifier.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -3519,6 +3526,23 @@ class WebInterface(object):
|
|||||||
pms_url_manual=manual,
|
pms_url_manual=manual,
|
||||||
pms_identifier=identifier)
|
pms_identifier=identifier)
|
||||||
result['url'] = server['pms_url']
|
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
|
return result
|
||||||
else:
|
else:
|
||||||
logger.warn('Unable to retrieve the PMS identifier.')
|
logger.warn('Unable to retrieve the PMS identifier.')
|
||||||
@@ -3697,6 +3721,9 @@ class WebInterface(object):
|
|||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
def info(self, rating_key=None, source=None, query=None, **kwargs):
|
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
|
metadata = None
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
Reference in New Issue
Block a user