mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 07:46:07 -07:00
Mask all info on the homepage
This commit is contained in:
parent
af9786f149
commit
5d7ba8cf14
14 changed files with 251 additions and 73 deletions
|
@ -884,6 +884,7 @@ a:hover .dashboard-activity-poster {
|
|||
float: right;
|
||||
}
|
||||
.dashboard-activity-metadata-user-thumb {
|
||||
background-color: #282828;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
margin-top: 5px;
|
||||
|
|
|
@ -68,20 +68,23 @@ DOCUMENTATION :: END
|
|||
% if data['stream_count'] != '0':
|
||||
% for a in data['sessions']:
|
||||
<div class="dashboard-instance" id="instance-${a['session_key']}">
|
||||
% if a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track':
|
||||
% if (a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track') and a['rating_key']:
|
||||
<a href="info?rating_key=${a['rating_key']}">
|
||||
% else:
|
||||
<a href="#">
|
||||
% endif
|
||||
<div class="dashboard-activity-poster">
|
||||
% if not a['art'].startswith('interfaces') or not a['thumb'].startswith('interfaces'):
|
||||
% if (a['media_type'] == 'movie' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280&fallback=poster&fallback=cover);"></div>
|
||||
% elif (a['media_type'] == 'episode' and not a['indexes']) or (a['indexes'] and not a['view_offset']):
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280&fallback=poster&fallback=cover);"></div>
|
||||
% elif a['indexes']:
|
||||
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280); display: none;"></div>
|
||||
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['bif_thumb']}&width=500&height=280&fallback=cover); display: none;"></div>
|
||||
% else:
|
||||
% if a['media_type'] == 'track':
|
||||
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300);"></div>
|
||||
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300);"></div>
|
||||
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
% elif a['media_type'] == 'clip':
|
||||
% if a['art'][:4] == 'http':
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
|
||||
|
@ -89,17 +92,20 @@ DOCUMENTATION :: END
|
|||
<div class="dashboard-activity-poster-face" style="background-image: url(${a['thumb']});"></div>
|
||||
% else:
|
||||
% if a['art']:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280);"></div>
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['art']}&width=500&height=280&fallback=cover);"></div>
|
||||
% else:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280);"></div>
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=280&fallback=cover);"></div>
|
||||
% endif
|
||||
% endif
|
||||
% elif a['media_type'] == 'photo':
|
||||
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=500);"></div>
|
||||
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=500&height=500&fallback=cover);"></div>
|
||||
% else:
|
||||
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${a['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
% endif
|
||||
% endif
|
||||
% else:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(${a['art']});"></div>
|
||||
% endif
|
||||
<div class="dashboard-activity-button-info">
|
||||
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${a['session_key']}">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
|
@ -212,7 +218,9 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
% endif
|
||||
</div>
|
||||
% if a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track':
|
||||
% if (a['media_type'] == 'movie' or a['media_type'] == 'episode' or a['media_type'] == 'track') and a['rating_key']:
|
||||
</a>
|
||||
% else:
|
||||
</a>
|
||||
% endif
|
||||
<div class="dashboard-activity-progress">
|
||||
|
@ -222,9 +230,13 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-wrapper">
|
||||
% if a['user_id']:
|
||||
<a href="user?user_id=${a['user_id']}">
|
||||
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
|
||||
</a>
|
||||
% else:
|
||||
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${a['user_thumb']});"></div>
|
||||
% endif
|
||||
<div class="dashboard-activity-metadata-title">
|
||||
% if a['state'] == 'playing':
|
||||
<i class="fa fa-play"></i>
|
||||
|
@ -233,6 +245,7 @@ DOCUMENTATION :: END
|
|||
% elif a['state'] == 'buffering':
|
||||
<i class="fa fa-spinner"></i>
|
||||
% endif
|
||||
% if a['title']:
|
||||
% if a['media_type'] == 'episode':
|
||||
<a href="info?rating_key=${a['rating_key']}" title="${a['grandparent_title']} - ${a['title']}">${a['grandparent_title']} - ${a['title']}</a>
|
||||
% elif a['media_type'] == 'movie':
|
||||
|
@ -246,8 +259,12 @@ DOCUMENTATION :: END
|
|||
% else:
|
||||
<span title="${a['title']}">${a['title']}</span>
|
||||
% endif
|
||||
% else:
|
||||
Title
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-subtitle">
|
||||
% if a['media_index'] or a['parent_media_index'] or a['parent_title'] or a['title'] or a['year']:
|
||||
% if a['media_type'] == 'episode':
|
||||
<span title="S${a['parent_media_index']} · E${a['media_index']}">S${a['parent_media_index']} · E${a['media_index']}</span>
|
||||
% elif a['media_type'] == 'movie':
|
||||
|
@ -259,9 +276,14 @@ DOCUMENTATION :: END
|
|||
% else:
|
||||
<span title="${a['year']}">${a['year']}</span>
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-user">
|
||||
% if a['user_id']:
|
||||
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
|
||||
% else:
|
||||
${a['friendly_name']}
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -540,11 +540,13 @@ DOCUMENTATION :: END
|
|||
<h4>
|
||||
% if top_stat['rows'][0]['user_id']:
|
||||
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
|
||||
% else:
|
||||
% elif top_stat['rows'][0]['user']:
|
||||
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
|
||||
% endif
|
||||
${top_stat['rows'][0]['friendly_name']}
|
||||
% if top_stat['rows'][0]['user_id'] or top_stat['rows'][0]['user']:
|
||||
</a>
|
||||
% endif
|
||||
</h4>
|
||||
% if top_stat['stat_type'] == 'total_plays':
|
||||
<h3>${top_stat['rows'][0]['total_plays']}</h3>
|
||||
|
@ -556,7 +558,7 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
% if top_stat['rows'][0]['user_id']:
|
||||
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
|
||||
% else:
|
||||
% elif top_stat['rows'][0]['user']:
|
||||
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
|
||||
% endif
|
||||
% if top_stat['rows'][0]['user_thumb'] != '':
|
||||
|
@ -568,7 +570,9 @@ DOCUMENTATION :: END
|
|||
<div class="home-platforms-instance-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
|
||||
</div>
|
||||
% endif
|
||||
% if top_stat['rows'][0]['user_id'] or top_stat['rows'][0]['user']:
|
||||
</a>
|
||||
% endif
|
||||
% if len(top_stat['rows']) > 1:
|
||||
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
|
||||
<ul class="list-unstyled">
|
||||
|
@ -582,11 +586,13 @@ DOCUMENTATION :: END
|
|||
<h5>
|
||||
% if top_stat['rows'][loop.index]['user_id']:
|
||||
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
|
||||
% else:
|
||||
% elif top_stat['rows'][loop.index]['user']:
|
||||
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
|
||||
% endif
|
||||
${top_stat['rows'][loop.index]['friendly_name']}
|
||||
% if top_stat['rows'][loop.index]['user_id'] or top_stat['rows'][loop.index]['user']:
|
||||
</a>
|
||||
% endif
|
||||
</h5>
|
||||
</div>
|
||||
<div class="home-platforms-instance-list-playcount">
|
||||
|
@ -600,7 +606,7 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
% if top_stat['rows'][loop.index]['user_id']:
|
||||
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
|
||||
% else:
|
||||
% elif top_stat['rows'][loop.index]['user']:
|
||||
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
|
||||
% endif
|
||||
% if top_stat['rows'][loop.index]['user_thumb'] != '':
|
||||
|
@ -612,7 +618,9 @@ DOCUMENTATION :: END
|
|||
<div class="home-platforms-instance-list-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
|
||||
</div>
|
||||
% endif
|
||||
% if top_stat['rows'][loop.index]['user_id'] or top_stat['rows'][loop.index]['user']:
|
||||
</a>
|
||||
% endif
|
||||
<div class="home-platforms-instance-list-number">
|
||||
<h4>${loop.index + 1}</h4>
|
||||
</div>
|
||||
|
|
BIN
data/interfaces/default/images/art.png
Normal file
BIN
data/interfaces/default/images/art.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -46,7 +46,7 @@
|
|||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="padded-header">
|
||||
<ul class="nav nav-header nav-dashboard pull-right">
|
||||
<ul class="nav nav-header nav-dashboard pull-right" style="margin-top: -12px;">
|
||||
<li>
|
||||
<a href="#" id="recently-added-page-left" class="paginate btn-gray disabled" data-id="+1"><i class="fa fa-lg fa-chevron-left"></i></a>
|
||||
</li>
|
||||
|
@ -55,9 +55,9 @@
|
|||
</li>
|
||||
</ul>
|
||||
<h3>Recently Added <small>
|
||||
<a href="#" class="toggle-recently-added-type" data-type="movie">Movies</a>
|
||||
<a href="#" class="toggle-recently-added-type" data-type="season">TV Shows</a>
|
||||
<a href="#" class="toggle-recently-added-type" data-type="album">Music</a></small></h3>
|
||||
<a href="#" class="toggle-recently-added-type btn-gray disabled" id="toggle-recently-added-movie" data-type="movie">Movies</a>
|
||||
<a href="#" class="toggle-recently-added-type btn-gray disabled" id="toggle-recently-added-season" data-type="season">TV Shows</a>
|
||||
<a href="#" class="toggle-recently-added-type btn-gray disabled" id="toggle-recently-added-album" data-type="album">Music</a></small></h3>
|
||||
</div>
|
||||
<div id="recentlyAdded" style="margin-right: -15px;">
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Looking for new items...</div>
|
||||
|
@ -138,6 +138,51 @@
|
|||
complete: function(xhr, status) {
|
||||
$("#recentlyAdded").html(xhr.responseText);
|
||||
highlightAddedScrollerButton();
|
||||
if ($('.dashboard-recent-media-instance li[data-type=movie]').length) { $('#toggle-recently-added-movie').removeClass('disabled'); }
|
||||
if ($('.dashboard-recent-media-instance li[data-type=season]').length) { $('#toggle-recently-added-season').removeClass('disabled'); }
|
||||
if ($('.dashboard-recent-media-instance li[data-type=album]').length) { $('#toggle-recently-added-album').removeClass('disabled'); }
|
||||
|
||||
$('.toggle-recently-added-type').not('.disabled').click(function () {
|
||||
var scroller = $("#recently-added-row-scroller");
|
||||
var media_type = $(this).data('type');
|
||||
var margin_right = $(this).hasClass('text-muted') ? '25px' : 0;
|
||||
var toggle_items = $('.dashboard-recent-media-instance li[data-type=' + media_type + ']');
|
||||
var containerWidth = $("body").find(".container-fluid").width();
|
||||
|
||||
if (margin_right == 0) {
|
||||
toggle_items.animate({ width: 'toggle', marginRight: margin_right }, 1000, function () {
|
||||
toggle_items.hide();
|
||||
|
||||
var scroller_width = $('.dashboard-recent-media-instance li:visible').length * 175;
|
||||
scroller.width(scroller_width);
|
||||
|
||||
if (scroller_width < containerWidth) {
|
||||
$("#recently-added-page-right").addClass("disabled").blur();
|
||||
} else {
|
||||
$("#recently-added-page-right").removeClass("disabled");
|
||||
}
|
||||
})
|
||||
} else {
|
||||
scroller.width(50 * 175);
|
||||
toggle_items.animate({ width: 'toggle', marginRight: margin_right }, 1000, function () {
|
||||
toggle_items.show();
|
||||
|
||||
var scroller_width = $('.dashboard-recent-media-instance li:visible').length * 175;
|
||||
scroller.width(scroller_width);
|
||||
|
||||
if (scroller_width < containerWidth) {
|
||||
$("#recently-added-page-right").addClass("disabled").blur();
|
||||
} else {
|
||||
$("#recently-added-page-right").removeClass("disabled");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
leftTotal = 0;
|
||||
scroller.animate({ left: leftTotal }, 1000);
|
||||
$("#recently-added-page-left").addClass("disabled").blur();
|
||||
$(this).toggleClass('text-muted').blur();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -156,7 +201,7 @@
|
|||
|
||||
function highlightAddedScrollerButton() {
|
||||
var scroller = $("#recently-added-row-scroller");
|
||||
var numElems = scroller.find("li").length;
|
||||
var numElems = scroller.find("li:visible").length;
|
||||
scroller.width(numElems * 175);
|
||||
if (scroller.width() > $("body").find(".container-fluid").width()) {
|
||||
$("#recently-added-page-right").removeClass("disabled");
|
||||
|
@ -192,13 +237,6 @@
|
|||
$("#recently-added-page-right").removeClass("disabled");
|
||||
}
|
||||
});
|
||||
|
||||
$('.toggle-recently-added-type').click(function () {
|
||||
var media_type = $(this).data('type');
|
||||
var margin_right = $(this).hasClass('text-muted') ? '25px' : 0;
|
||||
$('.dashboard-recent-media-instance li[data-type=' + media_type + ']').animate({ width: 'toggle', marginRight: margin_right }, 1000);
|
||||
$(this).toggleClass('text-muted').blur();
|
||||
});
|
||||
</script>
|
||||
|
||||
</%def>
|
||||
|
|
|
@ -42,6 +42,7 @@ notify_strings[NOTIFY_STOPPED] = "Playback stopped"
|
|||
DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png"
|
||||
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
|
||||
DEFAULT_COVER_THUMB = "interfaces/default/images/cover.png"
|
||||
DEFAULT_ART = "interfaces/default/images/art.png"
|
||||
|
||||
PLATFORM_NAME_OVERRIDES = {'Konvergo': 'Plex Media Player',
|
||||
'Mystery 3': 'Playstation 3',
|
||||
|
|
|
@ -148,7 +148,7 @@ class DataFactory(object):
|
|||
|
||||
dict = {'recordsFiltered': query['filteredCount'],
|
||||
'recordsTotal': query['totalCount'],
|
||||
'data': helpers.filter_datatable_session(rows),
|
||||
'data': helpers.filter_session_info(rows, 'user_id'),
|
||||
'draw': query['draw'],
|
||||
'filter_duration': helpers.human_duration(filter_duration, sig='dhm'),
|
||||
'total_duration': helpers.human_duration(total_duration, sig='dhm')
|
||||
|
@ -168,7 +168,7 @@ class DataFactory(object):
|
|||
if stat == 'top_tv':
|
||||
top_tv = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, ' \
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||
|
@ -196,6 +196,7 @@ class DataFactory(object):
|
|||
'last_play': item['last_watch'],
|
||||
'grandparent_thumb': item['grandparent_thumb'],
|
||||
'thumb': '',
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -206,12 +207,12 @@ class DataFactory(object):
|
|||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'stat_type': sort_type,
|
||||
'rows': top_tv})
|
||||
'rows': helpers.filter_session_info(top_tv, 'section_id')})
|
||||
|
||||
elif stat == 'popular_tv':
|
||||
popular_tv = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, ' \
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
|
@ -239,6 +240,7 @@ class DataFactory(object):
|
|||
'total_plays': item['total_plays'],
|
||||
'grandparent_thumb': item['grandparent_thumb'],
|
||||
'thumb': '',
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -248,12 +250,12 @@ class DataFactory(object):
|
|||
popular_tv.append(row)
|
||||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'rows': popular_tv})
|
||||
'rows': helpers.filter_session_info(popular_tv, 'section_id')})
|
||||
|
||||
elif stat == 'top_movies':
|
||||
top_movies = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, ' \
|
||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||
|
@ -281,6 +283,7 @@ class DataFactory(object):
|
|||
'last_play': item['last_watch'],
|
||||
'grandparent_thumb': '',
|
||||
'thumb': item['thumb'],
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -290,12 +293,12 @@ class DataFactory(object):
|
|||
top_movies.append(row)
|
||||
home_stats.append({'stat_id': stat,
|
||||
'stat_type': sort_type,
|
||||
'rows': top_movies})
|
||||
'rows': helpers.filter_session_info(top_movies, 'section_id')})
|
||||
|
||||
elif stat == 'popular_movies':
|
||||
popular_movies = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, ' \
|
||||
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.section_id, ' \
|
||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
|
@ -323,6 +326,7 @@ class DataFactory(object):
|
|||
'total_plays': item['total_plays'],
|
||||
'grandparent_thumb': '',
|
||||
'thumb': item['thumb'],
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -332,12 +336,12 @@ class DataFactory(object):
|
|||
popular_movies.append(row)
|
||||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'rows': popular_movies})
|
||||
'rows': helpers.filter_session_info(popular_movies, 'section_id')})
|
||||
|
||||
elif stat == 'top_music':
|
||||
top_music = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, ' \
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) AS total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
' (CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END) ELSE 0 END) ' \
|
||||
|
@ -365,6 +369,7 @@ class DataFactory(object):
|
|||
'last_play': item['last_watch'],
|
||||
'grandparent_thumb': item['grandparent_thumb'],
|
||||
'thumb': '',
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -375,12 +380,12 @@ class DataFactory(object):
|
|||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'stat_type': sort_type,
|
||||
'rows': top_music})
|
||||
'rows': helpers.filter_session_info(top_music, 'section_id')})
|
||||
|
||||
elif stat == 'popular_music':
|
||||
popular_music = []
|
||||
try:
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, ' \
|
||||
query = 'SELECT t.id, t.grandparent_title, t.grandparent_rating_key, t.grandparent_thumb, t.section_id, ' \
|
||||
'COUNT(DISTINCT t.user_id) AS users_watched, ' \
|
||||
'MAX(t.started) AS last_watch, COUNT(t.id) as total_plays, SUM(t.d) AS total_duration ' \
|
||||
'FROM (SELECT *, SUM(CASE WHEN stopped > 0 THEN (stopped - started) - ' \
|
||||
|
@ -408,6 +413,7 @@ class DataFactory(object):
|
|||
'total_plays': item['total_plays'],
|
||||
'grandparent_thumb': item['grandparent_thumb'],
|
||||
'thumb': '',
|
||||
'section_id': item['section_id'],
|
||||
'user': '',
|
||||
'friendly_name': '',
|
||||
'platform_type': '',
|
||||
|
@ -417,7 +423,7 @@ class DataFactory(object):
|
|||
popular_music.append(row)
|
||||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'rows': popular_music})
|
||||
'rows': helpers.filter_session_info(popular_music, 'section_id')})
|
||||
|
||||
elif stat == 'top_users':
|
||||
top_users = []
|
||||
|
@ -470,7 +476,7 @@ class DataFactory(object):
|
|||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'stat_type': sort_type,
|
||||
'rows': helpers.filter_datatable_session(top_users)})
|
||||
'rows': helpers.mask_session_info(top_users)})
|
||||
|
||||
elif stat == 'top_platforms':
|
||||
top_platform = []
|
||||
|
@ -567,7 +573,7 @@ class DataFactory(object):
|
|||
last_watched.append(row)
|
||||
|
||||
home_stats.append({'stat_id': stat,
|
||||
'rows': helpers.filter_datatable_session(last_watched)})
|
||||
'rows': helpers.filter_session_info(last_watched, 'user_id')})
|
||||
|
||||
elif stat == 'most_concurrent':
|
||||
|
||||
|
@ -686,7 +692,7 @@ class DataFactory(object):
|
|||
}
|
||||
library_stats.append(library)
|
||||
|
||||
return library_stats
|
||||
return helpers.filter_session_info(library_stats, 'section_id')
|
||||
|
||||
def get_stream_details(self, row_id=None):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
|
|
@ -33,7 +33,8 @@ from xml.dom import minidom
|
|||
import xmltodict
|
||||
|
||||
import plexpy
|
||||
from api2 import API2
|
||||
from plexpy import common
|
||||
from plexpy.api2 import API2
|
||||
|
||||
|
||||
def addtoapi(*dargs, **dkwargs):
|
||||
|
@ -564,18 +565,102 @@ def uploadToImgur(imgPath, imgTitle=''):
|
|||
|
||||
return img_url
|
||||
|
||||
def filter_datatable_session(list_of_dicts):
|
||||
|
||||
def allow_session_user(user_id):
|
||||
"""
|
||||
Returns True or False if the user_id is allowed for the user session
|
||||
"""
|
||||
import cherrypy
|
||||
from plexpy.webauth import SESSION_KEY
|
||||
|
||||
if cherrypy.config.get('tools.auth.on'):
|
||||
_session = {}
|
||||
_cp_session = cherrypy.session.get(SESSION_KEY)
|
||||
_session['username'], _session['user_id'], _session['user_group'], _session['expiry'] = \
|
||||
_cp_session if _cp_session else (None, None, None, None)
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
if str(user_id) != _session['user_id']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def allow_session_library(section_id):
|
||||
"""
|
||||
Returns True or False if the section_id is allowed for the user session
|
||||
"""
|
||||
import cherrypy
|
||||
from plexpy.webauth import SESSION_KEY
|
||||
|
||||
if cherrypy.config.get('tools.auth.on'):
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
if str(section_id) not in _session['user_libraries']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def filter_session_info(list_of_dicts, filter_key=None):
|
||||
"""
|
||||
Filters a list of dictionary items to only return the info for the current logged in user
|
||||
"""
|
||||
import cherrypy
|
||||
from plexpy.webauth import SESSION_KEY
|
||||
|
||||
if cherrypy.config.get('tools.auth.on'):
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
|
||||
if filter_key == 'user_id' and _session['user_id']:
|
||||
session_user_id = str(_session['user_id'])
|
||||
return [d for d in list_of_dicts if str(d.get('user_id','')) == session_user_id]
|
||||
|
||||
elif filter_key == 'section_id' and _session['user_libraries']:
|
||||
session_library_ids = _session['user_libraries']
|
||||
return [d for d in list_of_dicts if str(d.get('section_id','')) in session_library_ids]
|
||||
|
||||
return list_of_dicts
|
||||
|
||||
def mask_session_info(list_of_dicts, mask_metadata=False):
|
||||
"""
|
||||
Masks user info in a list of dictionary items to only display info for the current logged in user
|
||||
"""
|
||||
import cherrypy
|
||||
from plexpy.webauth import SESSION_KEY
|
||||
|
||||
if cherrypy.config.get('tools.auth.on'):
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
|
||||
keys_to_mask = {'user_id': '',
|
||||
'user': '',
|
||||
'friendly_name': 'Plex User',
|
||||
'user_thumb': common.DEFAULT_USER_THUMB,
|
||||
'ip_address': 'N/A',
|
||||
'machine_id': ''
|
||||
}
|
||||
|
||||
metadata_to_mask = {'media_index': '',
|
||||
'parent_media_index': '',
|
||||
'art': common.DEFAULT_ART,
|
||||
'parent_thumb': common.DEFAULT_POSTER_THUMB,
|
||||
'grandparent_thumb': common.DEFAULT_POSTER_THUMB,
|
||||
'thumb': common.DEFAULT_POSTER_THUMB,
|
||||
'bif_thumb': '',
|
||||
'grandparent_title': '',
|
||||
'parent_title': '',
|
||||
'title': '',
|
||||
'rating_key': '',
|
||||
'parent_rating_key': '',
|
||||
'grandparent_rating_key': '',
|
||||
'year': ''
|
||||
}
|
||||
|
||||
if _session['user_id']:
|
||||
session_user_id = str(_session['user_id'])
|
||||
return [d for d in list_of_dicts if str(d.get('user_id')) == session_user_id]
|
||||
session_library_ids = _session['user_libraries']
|
||||
|
||||
for d in list_of_dicts:
|
||||
if not (str(d.get('user_id')) == session_user_id or d.get('user') == _session['user']):
|
||||
for k, v in keys_to_mask.iteritems():
|
||||
if k in d: d[k] = keys_to_mask[k]
|
||||
|
||||
if mask_metadata and str(d.get('section_id','')) not in session_library_ids:
|
||||
for k, v in metadata_to_mask.iteritems():
|
||||
if k in d: d[k] = metadata_to_mask[k]
|
||||
|
||||
return list_of_dicts
|
||||
|
||||
return list_of_dicts
|
|
@ -222,7 +222,7 @@ class Libraries(object):
|
|||
|
||||
dict = {'recordsFiltered': query['filteredCount'],
|
||||
'recordsTotal': query['totalCount'],
|
||||
'data': rows,
|
||||
'data': helpers.filter_session_info(rows, 'section_id'),
|
||||
'draw': query['draw']
|
||||
}
|
||||
|
||||
|
@ -700,7 +700,7 @@ class Libraries(object):
|
|||
}
|
||||
user_stats.append(row)
|
||||
|
||||
return helpers.filter_datatable_session(user_stats)
|
||||
return helpers.filter_session_info(user_stats, 'user_id')
|
||||
|
||||
def get_recently_watched(self, section_id=None, limit='10'):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
|
|
|
@ -401,7 +401,7 @@ class PlexTV(object):
|
|||
|
||||
synced_items.append(sync_details)
|
||||
|
||||
return helpers.filter_datatable_session(synced_items)
|
||||
return helpers.filter_session_info(synced_items, 'user_id')
|
||||
|
||||
def get_server_urls(self, include_https=True):
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ class PmsConnect(object):
|
|||
Retrieve data from Plex Server
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, token=None):
|
||||
if plexpy.CONFIG.PMS_URL:
|
||||
url_parsed = urlparse(plexpy.CONFIG.PMS_URL)
|
||||
hostname = url_parsed.hostname
|
||||
|
@ -105,9 +105,11 @@ class PmsConnect(object):
|
|||
port = plexpy.CONFIG.PMS_PORT
|
||||
self.protocol = 'http'
|
||||
|
||||
token = token if token else plexpy.CONFIG.PMS_TOKEN
|
||||
|
||||
self.request_handler = http_handler.HTTPHandler(host=hostname,
|
||||
port=port,
|
||||
token=plexpy.CONFIG.PMS_TOKEN)
|
||||
token=token)
|
||||
|
||||
def get_sessions(self, output_format=''):
|
||||
"""
|
||||
|
@ -492,7 +494,8 @@ class PmsConnect(object):
|
|||
}
|
||||
recents_list.append(recent_items)
|
||||
|
||||
output = {'recently_added': sorted(recents_list, key=lambda k: k['added_at'], reverse=True)}
|
||||
output = {'recently_added': helpers.filter_session_info(
|
||||
sorted(recents_list, key=lambda k: k['added_at'], reverse=True), 'section_id')}
|
||||
return output
|
||||
|
||||
def get_metadata_details(self, rating_key='', get_media_info=False):
|
||||
|
@ -972,7 +975,7 @@ class PmsConnect(object):
|
|||
session_list.append(session_output)
|
||||
|
||||
output = {'stream_count': helpers.get_xml_attr(xml_head[0], 'size'),
|
||||
'sessions': session_list
|
||||
'sessions': helpers.mask_session_info(session_list, True)
|
||||
}
|
||||
|
||||
return output
|
||||
|
|
|
@ -190,7 +190,7 @@ class Users(object):
|
|||
|
||||
dict = {'recordsFiltered': query['filteredCount'],
|
||||
'recordsTotal': query['totalCount'],
|
||||
'data': helpers.filter_datatable_session(rows),
|
||||
'data': helpers.filter_session_info(rows, 'user_id'),
|
||||
'draw': query['draw']
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ class Users(object):
|
|||
|
||||
dict = {'recordsFiltered': query['filteredCount'],
|
||||
'recordsTotal': query['totalCount'],
|
||||
'data': helpers.filter_datatable_session(rows),
|
||||
'data': helpers.filter_session_info(rows, 'user_id'),
|
||||
'draw': query['draw']
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ from datetime import datetime, timedelta
|
|||
import plexpy
|
||||
from plexpy import logger
|
||||
from plexpy.users import Users, user_login
|
||||
from plexpy.pmsconnect import PmsConnect
|
||||
|
||||
|
||||
SESSION_KEY = '_cp_username'
|
||||
|
@ -50,11 +51,10 @@ def check_auth(*args, **kwargs):
|
|||
conditions that the user must fulfill"""
|
||||
conditions = cherrypy.request.config.get('auth.require', None)
|
||||
if conditions is not None:
|
||||
cp_sesssion = cherrypy.session.get(SESSION_KEY)
|
||||
username, user_id, user_group, expiry = cp_sesssion if cp_sesssion else (None, None, None, None)
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
|
||||
if (username and expiry) and expiry > datetime.now():
|
||||
cherrypy.request.login = username
|
||||
if _session and (_session['user'] and _session['expiry']) and _session['expiry'] > datetime.now():
|
||||
cherrypy.request.login = _session['user']
|
||||
for condition in conditions:
|
||||
# A condition is just a callable that returns true or false
|
||||
if not condition():
|
||||
|
@ -148,14 +148,25 @@ class AuthController(object):
|
|||
if user_group == 'guest':
|
||||
user_details = Users().get_details(user=username)
|
||||
user_id = user_details['user_id']
|
||||
|
||||
user_tokens = Users().get_tokens(user_id=user_details['user_id'])
|
||||
server_token = user_tokens['server_token']
|
||||
|
||||
library_details = PmsConnect(token=server_token).get_server_children()
|
||||
user_libraries = tuple(d['section_id'] for d in library_details['libraries_list'])
|
||||
else:
|
||||
user_id = None
|
||||
user_libraries = None
|
||||
|
||||
expiry = datetime.now() + (timedelta(days=30) if remember_me == '1' else timedelta(minutes=60))
|
||||
|
||||
cherrypy.session.regenerate()
|
||||
cherrypy.request.login = username
|
||||
cherrypy.session[SESSION_KEY] = (username, user_id, user_group, expiry)
|
||||
cherrypy.session[SESSION_KEY] = {'user_id': user_id,
|
||||
'user': username,
|
||||
'user_group': user_group,
|
||||
'user_libraries': user_libraries,
|
||||
'expiry': expiry}
|
||||
|
||||
self.on_login(username)
|
||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||
|
@ -169,11 +180,10 @@ class AuthController(object):
|
|||
if not plexpy.CONFIG.HTTP_PASSWORD:
|
||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||
|
||||
cp_sesssion = cherrypy.session.get(SESSION_KEY)
|
||||
username, user_id, user_group, expiry = cp_sesssion if cp_sesssion else (None, None, None, None)
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
cherrypy.session[SESSION_KEY] = None
|
||||
|
||||
if username:
|
||||
if _session['user']:
|
||||
cherrypy.request.login = None
|
||||
self.on_logout(username)
|
||||
self.on_logout(_session['user'])
|
||||
raise cherrypy.HTTPRedirect("login")
|
|
@ -49,15 +49,13 @@ def serve_template(templatename, **kwargs):
|
|||
|
||||
server_name = plexpy.CONFIG.PMS_NAME
|
||||
|
||||
_session = {'username': None,
|
||||
'user_id': None,
|
||||
_session = {'user_id': None,
|
||||
'user': None,
|
||||
'user_group': 'admin',
|
||||
'expiry': None}
|
||||
|
||||
if cherrypy.config.get('tools.auth.on'):
|
||||
_cp_session = cherrypy.session.get(SESSION_KEY)
|
||||
_session['username'], _session['user_id'], _session['user_group'], _session['expiry'] = \
|
||||
_cp_session if _cp_session else (None, None, 'admin', None)
|
||||
_session = cherrypy.session.get(SESSION_KEY)
|
||||
|
||||
try:
|
||||
template = _hplookup.get_template(templatename)
|
||||
|
@ -173,6 +171,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="index.html", title="Home", config=config)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_date_formats(self):
|
||||
""" Get the date and time formats used by plexpy """
|
||||
|
@ -193,6 +192,7 @@ class WebInterface(object):
|
|||
return json.dumps(formats)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def get_current_activity(self, **kwargs):
|
||||
|
||||
try:
|
||||
|
@ -215,6 +215,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="current_activity.html", data=None)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def get_current_activity_header(self, **kwargs):
|
||||
|
||||
try:
|
||||
|
@ -230,6 +231,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="current_activity_header.html", data=None)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def home_stats(self, **kwargs):
|
||||
data_factory = datafactory.DataFactory()
|
||||
|
||||
|
@ -250,6 +252,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="home_stats.html", title="Stats", data=stats_data)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def library_stats(self, **kwargs):
|
||||
data_factory = datafactory.DataFactory()
|
||||
|
||||
|
@ -260,6 +263,7 @@ class WebInterface(object):
|
|||
return serve_template(templatename="library_stats.html", title="Library Stats", data=stats_data)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def get_recently_added(self, count='0', **kwargs):
|
||||
|
||||
try:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue