mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-11 07:46:07 -07:00
Persist current activity details between refreshes
This commit is contained in:
parent
83b97111a0
commit
4a0f0238b0
4 changed files with 523 additions and 75 deletions
|
@ -578,17 +578,51 @@ a .users-poster-face:hover {
|
|||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-poster {
|
||||
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-poster-info-bar {
|
||||
opacity: 1;
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-progress-bar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
}
|
||||
.dashboard-instance.hover .bar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0.25),0%,rgba(0,0,0,0),50px);
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
background-image: linear-gradient(to left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
}
|
||||
.dashboard-instance.hover .bufferbar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0.25),0%,rgba(0,0,0,0),50px);
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
background-image: linear-gradient(to left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-metadata-wrapper {
|
||||
margin-top: 11px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
.dashboard-activity-poster {
|
||||
height: 200px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
a:hover .dashboard-activity-poster {
|
||||
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 2px #e9a049;
|
||||
}
|
||||
.dashboard-activity-poster-face {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
|
@ -675,10 +709,10 @@ a:hover .dashboard-activity-poster {
|
|||
}
|
||||
.dashboard-activity-info-details-overlay {
|
||||
text-align: left;
|
||||
background-image: -webkit-gradient(linear,left 0,left 100%,from(rgba(0,0,0,.6)),to(rgba(0,0,0,.8)));
|
||||
background-image: -webkit-linear-gradient(top,rgba(0,0,0,.6),0,rgba(0,0,0,.8),100%);
|
||||
background-image: -moz-linear-gradient(top,rgba(0,0,0,.6) 0,rgba(0,0,0,.8) 100%);
|
||||
background-image: linear-gradient(to bottom,rgba(0,0,0,.6) 0,rgba(0,0,0,.8) 100%);
|
||||
background-image: -webkit-gradient(linear,left 0,left 100%,from(rgba(0,0,0,.75)),to(rgba(0,0,0,0)));
|
||||
background-image: -webkit-linear-gradient(top,rgba(0,0,0,.75),0,rgba(0,0,0,0),100%);
|
||||
background-image: -moz-linear-gradient(top,rgba(0,0,0,.75) 0,rgba(0,0,0,0) 100%);
|
||||
background-image: linear-gradient(to bottom,rgba(0,0,0,.75) 0,rgba(0,0,0,0) 100%);
|
||||
background-repeat: repeat-x;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -746,9 +780,6 @@ a:hover .dashboard-activity-poster {
|
|||
transition: all .2s;
|
||||
z-index: -2;
|
||||
}
|
||||
.dashboard-activity-poster:hover .dashboard-activity-poster-info-bar {
|
||||
opacity: 1;
|
||||
}
|
||||
.dashboard-activity-poster-info-text {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
@ -820,37 +851,6 @@ a:hover .dashboard-activity-poster {
|
|||
height: 6px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-progress-bar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
}
|
||||
.dashboard-instance.hover .bar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0.25),0%,rgba(0,0,0,0),50px);
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
background-image: linear-gradient(to left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
}
|
||||
.dashboard-instance.hover .bufferbar {
|
||||
height: 14px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
border-radius: 0px 0px 3px 3px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
background-image: -webkit-linear-gradient(left,rgba(0,0,0,0.25),0%,rgba(0,0,0,0),50px);
|
||||
background-image: -moz-linear-gradient(left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
background-image: linear-gradient(to left,rgba(0,0,0,0.25) 0%,rgba(0,0,0,0) 50px);
|
||||
}
|
||||
.dashboard-instance.hover .dashboard-activity-metadata-wrapper {
|
||||
margin-top: 11px;
|
||||
transform-origin: top;
|
||||
transition: all .2s ease;
|
||||
}
|
||||
.dashboard-activity-metadata-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
@ -862,7 +862,8 @@ a:hover .dashboard-activity-poster {
|
|||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 25px;
|
||||
color: #fff;
|
||||
max-width: 300px;
|
||||
|
@ -871,7 +872,8 @@ a:hover .dashboard-activity-poster {
|
|||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 25px;
|
||||
color: #999;
|
||||
max-width: 172px;
|
||||
|
@ -881,7 +883,8 @@ a:hover .dashboard-activity-poster {
|
|||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
line-height: 25px;
|
||||
color: #999;
|
||||
text-align: right;
|
||||
|
|
307
data/interfaces/default/current_activity_instance.html
Normal file
307
data/interfaces/default/current_activity_instance.html
Normal file
|
@ -0,0 +1,307 @@
|
|||
<%doc>
|
||||
USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE
|
||||
|
||||
For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/
|
||||
|
||||
Filename: current_activity_instance.html
|
||||
Version: 0.1
|
||||
Variable names: data {dict}
|
||||
|
||||
data :: Usable parameters
|
||||
|
||||
== Global keys ==
|
||||
session_key Returns a unique session id for the active stream
|
||||
rating_key Returns the unique identifier for the media item.
|
||||
media_index Returns the index of the media item.
|
||||
parent_media_index Returns the index of the media item's parent.
|
||||
media_type Returns the type of session. Either 'track', 'episode' or 'movie'.
|
||||
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
|
||||
bif_thumb Returns the location of the item's bif thumbnail. Use with pms_image_proxy.
|
||||
art Returns the location of the item's artwork
|
||||
progress_percent Returns the current progress of the item. 0 to 100.
|
||||
user Returns the name of the user owning the session.
|
||||
user_id Returns the Plex user id if available.
|
||||
machine_id Returns the machine id of the players being used.
|
||||
friendly_name Returns the friendlly name of the user owning the session.
|
||||
user_thumb Returns the profile picture of the user owning the session.
|
||||
state Returns the state of the current session. Either 'playing', 'paused' or 'buffering'.
|
||||
title Returns the name of the episode, movie or music track.
|
||||
year Returns the year of the episode, movie, or clip.
|
||||
ip_address Returns the ip address of the stream.
|
||||
player Returns the name of the platform used to play the stream.
|
||||
platform Returns the type of platform used to play the stream.
|
||||
throttled Returns true if the transcode session is throttled.
|
||||
transcode_progress Returns the current transcode progress of the item. 0 to 100.
|
||||
transcode_speed Returns the current transcode speed of the item.
|
||||
audio_decision Returns the audio transcode decision. Either 'transcode', 'copy' or 'direct play'.
|
||||
audio_codec Returns the name of the audio codec.
|
||||
audio_channels Returns the number of audio channels.
|
||||
grandparent_title Returns the title of the item's grandparent.
|
||||
parent_title Returns the title of the item's parent.
|
||||
video_decision Returns the video transcode decision. Either 'transcode', 'copy' or 'direct play'.
|
||||
video_codec Returns the name of the video codec.
|
||||
height Returns the value of the video height.
|
||||
width Returns the value of the video width.
|
||||
container Returns the value of the media container.
|
||||
bitrate Returns the value of the media bitrate.
|
||||
video_resolution Returns the value of the video resolution.
|
||||
video_framerate Returns the value of the video framerate.
|
||||
video_aspect_ratio Returns the value of the video aspect ratio.
|
||||
transcode_audio_channels Returns the amount of audio channels if there is a transcode session.
|
||||
transcode_audio_codec Returns the name of the audio codec if there is a transcode session.
|
||||
transcode_video_codec Returns the name of the video codec if there is a transcode session.
|
||||
transcode_width Returns the video width if there is a transcode session.
|
||||
transcode_height Returns the video height if there is a transcode session.
|
||||
transcode_container Returns the value of media container if there is a transcode session.
|
||||
transcode_protocol Returns the value of media protocol if there is a transcode session.
|
||||
indexes Returns true if the media has media indexes and are enabled
|
||||
|
||||
DOCUMENTATION :: END
|
||||
</%doc>
|
||||
|
||||
% if data is not None:
|
||||
<div class="dashboard-instance" id="instance-${data['session_key']}" data-id="${data['session_key']}">
|
||||
<div class="dashboard-hover-container">
|
||||
% if (data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track') and data['rating_key']:
|
||||
<a href="info?rating_key=${data['rating_key']}">
|
||||
% else:
|
||||
<a href="#">
|
||||
% endif
|
||||
<div class="dashboard-activity-poster">
|
||||
% if not data['art'].startswith('interfaces') or not data['thumb'].startswith('interfaces'):
|
||||
% if (data['media_type'] == 'movie' and not data['indexes']) or (data['indexes'] and not data['view_offset']):
|
||||
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
|
||||
% elif (data['media_type'] == 'episode' and not data['indexes']) or (data['indexes'] and not data['view_offset']):
|
||||
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
|
||||
% elif data['indexes']:
|
||||
<div id="bif-${data['session_key']}" class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['bif_thumb']}&width=500&height=280&fallback=art); display: none;"></div>
|
||||
% else:
|
||||
% if data['media_type'] == 'track':
|
||||
<div class="dashboard-activity-cover-face-bg" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
% elif data['media_type'] == 'clip':
|
||||
% if data['art'][:4] == 'http':
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
|
||||
% elif data['thumb'][:4] == 'http':
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(${data['thumb']});"></div>
|
||||
% else:
|
||||
% if data['art']:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['art']}&width=500&height=280&fallback=art);"></div>
|
||||
% else:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=art);"></div>
|
||||
% endif
|
||||
% endif
|
||||
% elif data['media_type'] == 'photo':
|
||||
<div class="dashboard-activity-poster-face bif" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=cover);"></div>
|
||||
% else:
|
||||
<div class="dashboard-activity-cover-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=300&fallback=cover);"></div>
|
||||
% endif
|
||||
% endif
|
||||
% else:
|
||||
<div class="dashboard-activity-poster-face" style="background-image: url(${data['art']});"></div>
|
||||
% endif
|
||||
<div class="dashboard-activity-button-info">
|
||||
<button type="button" class="btn btn-activity-info btn-lg" data-target="#stream-${data['session_key']}">
|
||||
<i class="fa fa-info-circle"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="stream-${data['session_key']}" class="dashboard-activity-info-details-overlay">
|
||||
<div class="dashboard-activity-info-details-content">
|
||||
<div id="platform-${data['session_key']}" title="${data['platform']}">
|
||||
<script>
|
||||
$("#platform-${data['session_key']}").html("<div class='dashboard-activity-info-platform-box' style='background-image: url(" + getPlatformImagePath('${data['platform']}') + ");'>");
|
||||
</script>
|
||||
</div>
|
||||
<div class="dashboard-activity-info-platform">
|
||||
<strong>${data['player']}</strong><br />
|
||||
<span id="overlay-play-state-${data['session_key']}">
|
||||
% if data['state'] == 'playing':
|
||||
State <strong>Playing</strong>
|
||||
% elif data['state'] == 'paused':
|
||||
State <strong>Paused</strong>
|
||||
% elif data['state'] == 'buffering':
|
||||
State <strong>Buffering</strong>
|
||||
% endif
|
||||
</span>
|
||||
</div>
|
||||
% if data['media_type'] == 'track':
|
||||
% if data['audio_decision'] == 'direct play':
|
||||
Stream <strong>Direct Play</strong>
|
||||
% elif data['audio_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <strong>
|
||||
Transcoding
|
||||
<span id="transcode-state-${data['session_key']}">
|
||||
(Speed: ${data['transcode_speed']})
|
||||
% if data['throttled'] == '1':
|
||||
(Throttled)
|
||||
% endif
|
||||
</span>
|
||||
</strong>
|
||||
% endif
|
||||
<br />
|
||||
% if data['audio_decision'] == 'direct play':
|
||||
Audio <strong>Direct Play (${data['audio_codec']}) (${data['audio_channels']}ch)</strong>
|
||||
% elif data['audio_decision'] == 'copy':
|
||||
Audio <strong>Direct Stream (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
|
||||
% elif data['audio_decision'] == 'transcode':
|
||||
Audio <strong>Transcode (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
|
||||
% endif
|
||||
% elif data['media_type'] == 'episode' or data['media_type'] == 'movie' or data['media_type'] == 'clip':
|
||||
% if data['video_decision'] == 'direct play' and data['audio_decision'] == 'direct play':
|
||||
Stream <strong>Direct Play</strong>
|
||||
% elif data['video_decision'] == 'copy' and data['audio_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <strong>
|
||||
Transcoding
|
||||
<span id="transcode-state-${data['session_key']}">
|
||||
(Speed: ${data['transcode_speed']})
|
||||
% if data['throttled'] == '1':
|
||||
(Throttled)
|
||||
% endif
|
||||
</span>
|
||||
</strong>
|
||||
% endif
|
||||
<br />
|
||||
% if data['video_decision'] == 'direct play':
|
||||
Video <strong>Direct Play (${data['video_codec']}) (${data['width']}x${data['height']})</strong>
|
||||
% elif data['video_decision'] == 'copy':
|
||||
Video <strong>Direct Stream (${data['transcode_video_codec']}) (${data['width']}x${data['height']})</strong>
|
||||
% elif data['video_decision'] == 'transcode':
|
||||
Video <strong>Transcode (${data['transcode_video_codec']}) (${data['transcode_width']}x${data['transcode_height']})</strong>
|
||||
% endif
|
||||
<br />
|
||||
% if data['audio_decision'] == 'direct play':
|
||||
Audio <strong>Direct Play (${data['audio_codec']}) (${data['audio_channels']}ch)</strong>
|
||||
% elif data['audio_decision'] == 'copy':
|
||||
Audio <strong>Direct Stream (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
|
||||
% elif data['audio_decision'] == 'transcode':
|
||||
Audio <strong>Transcode (${data['transcode_audio_codec']}) (${data['transcode_audio_channels']}ch)</strong>
|
||||
% endif
|
||||
% elif data['media_type'] == 'photo':
|
||||
% if data['video_decision'] == 'direct play':
|
||||
Stream <strong>Direct Play</strong>
|
||||
% elif data['video_decision'] == 'copy':
|
||||
Stream <strong>Direct Stream</strong>
|
||||
% else:
|
||||
Stream <strong>
|
||||
<span id="transcode-state-${data['session_key']}">
|
||||
(Speed: ${data['transcode_speed']})
|
||||
% if data['throttled'] == '1':
|
||||
(Throttled)
|
||||
% endif
|
||||
</span>
|
||||
</strong>
|
||||
% endif
|
||||
% endif
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
% if data['media_type'] != 'photo':
|
||||
<div class="dashboard-activity-poster-info-bar">
|
||||
<div class="dashboard-activity-poster-info-ip-address">
|
||||
% if data['ip_address']:
|
||||
<span>IP: ${data['ip_address']}</span>
|
||||
% else:
|
||||
<span>IP: N/A</span>
|
||||
% endif
|
||||
<br />
|
||||
ETA:
|
||||
<span id="stream-eta-${data['session_key']}">
|
||||
<script>
|
||||
$("#stream-eta-${data['session_key']}").html(moment().add(parseInt("${data['duration']}") - parseInt("${data['view_offset']}"), 'milliseconds').format(time_format));
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
<div class="dashboard-activity-poster-info-time">
|
||||
<span class="progress_time" id="stream-view-offset-${data['session_key']}">
|
||||
<script>
|
||||
$("#stream-view-offset-${data['session_key']}").html(millisecondsToMinutes(parseInt("${data['view_offset']}"), false));
|
||||
</script>
|
||||
</span>/<span class="progress_time" id="stream-duration-${data['session_key']}">
|
||||
<script>
|
||||
$("#stream-duration-${data['session_key']}").html(millisecondsToMinutes(parseInt("${data['duration']}"), false));
|
||||
</script>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
% if (data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track') and data['rating_key']:
|
||||
</a>
|
||||
% else:
|
||||
</a>
|
||||
% endif
|
||||
<div class="dashboard-activity-progress">
|
||||
<div class="dashboard-activity-progress-bar">
|
||||
<div id="bufferbar-${data['session_key']}" class="bufferbar" style="width: ${data['transcode_progress']}%" data-toggle="tooltip" title="Transcoder Progress">${data['transcode_progress']}%</div>
|
||||
<div id="bar-${data['session_key']}" class="bar" style="width: ${data['progress_percent']}%" data-toggle="tooltip" title="Stream Progress">${data['progress_percent']}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-wrapper">
|
||||
% if data['user_id']:
|
||||
<a href="user?user_id=${data['user_id']}">
|
||||
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
|
||||
</a>
|
||||
% else:
|
||||
<div class="dashboard-activity-metadata-user-thumb" style="background-image: url(${data['user_thumb']});"></div>
|
||||
% endif
|
||||
<div class="dashboard-activity-metadata-title">
|
||||
<span id="play-state-${data['session_key']}">
|
||||
% if data['state'] == 'playing':
|
||||
<i class="fa fa-fw fa-play"></i>
|
||||
% elif data['state'] == 'paused':
|
||||
<i class="fa fa-fw fa-pause"></i>
|
||||
% elif data['state'] == 'buffering':
|
||||
<i class="fa fa-fw fa-spinner"></i>
|
||||
% endif
|
||||
</span>
|
||||
% if data['rating_key']:
|
||||
% if data['media_type'] == 'episode':
|
||||
<a href="info?rating_key=${data['grandparent_rating_key']}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
|
||||
- <a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
|
||||
% elif data['media_type'] == 'movie':
|
||||
<a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
|
||||
% elif data['media_type'] == 'clip':
|
||||
<span title="${data['title']}">${data['title']}</span>
|
||||
% elif data['media_type'] == 'track':
|
||||
<a href="info?rating_key=${data['grandparent_rating_key']}" title="${data['grandparent_title']}">${data['grandparent_title']}</a>
|
||||
- <a href="info?rating_key=${data['rating_key']}" title="${data['title']}">${data['title']}</a>
|
||||
% elif data['media_type'] == 'photo':
|
||||
<span title="${data['parent_title']}">${data['parent_title']}</span>
|
||||
% else:
|
||||
<span title="${data['title']}">${data['title']}</span>
|
||||
% endif
|
||||
% else:
|
||||
${data['title']}
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-subtitle">
|
||||
% if data['rating_key']:
|
||||
% if data['media_type'] == 'episode':
|
||||
<a href="info?rating_key=${data['parent_rating_key']}" title="Season ${data['parent_media_index']}" class="text-muted">S${data['parent_media_index']}</a>
|
||||
· <a href="info?rating_key=${data['rating_key']}" title="Episode ${data['media_index']}" class="text-muted">E${data['media_index']}</a>
|
||||
% elif data['media_type'] == 'movie':
|
||||
<span title="${data['year']}">${data['year']}</span>
|
||||
% elif data['media_type'] == 'track':
|
||||
<a href="info?rating_key=${data['parent_rating_key']}" title="${data['parent_title']}">${data['parent_title']}</a>
|
||||
% elif data['media_type'] == 'photo':
|
||||
<span title="${data['title']}">${data['title']}</span>
|
||||
% else:
|
||||
<span title="${data['year']}">${data['year']}</span>
|
||||
% endif
|
||||
% endif
|
||||
</div>
|
||||
<div class="dashboard-activity-metadata-user">
|
||||
% if data['user_id']:
|
||||
<a href="user?user_id=${data['user_id']}" title="${data['friendly_name']}">${data['friendly_name']}</a>
|
||||
% else:
|
||||
${data['friendly_name']}
|
||||
% endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% endif
|
|
@ -13,7 +13,7 @@
|
|||
<h3>Activity</h3>
|
||||
</div>
|
||||
<div id="currentActivity">
|
||||
<div class="text-muted"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
|
||||
<div class="text-muted" id="dashboard-checking-activity"><i class="fa fa-refresh fa-spin"></i> Checking for activity...</div>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -72,70 +72,207 @@
|
|||
|
||||
<%def name="javascriptIncludes()">
|
||||
<script src="${http_root}js/moment-with-locale.js"></script>
|
||||
<script>
|
||||
var date_format = 'YYYY-MM-DD';
|
||||
var time_format = 'hh:mm a';
|
||||
$.ajax({
|
||||
url: 'get_date_formats',
|
||||
type: 'GET',
|
||||
success: function (data) {
|
||||
date_format = data.date_format;
|
||||
time_format = data.time_format;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% if 'current_activity' in config['home_sections']:
|
||||
<script>
|
||||
function currentActivityHeader() {
|
||||
$.ajax({
|
||||
url: 'get_current_activity_header',
|
||||
cache: false,
|
||||
async: true,
|
||||
complete: function(xhr, status) {
|
||||
complete: function (xhr, status) {
|
||||
$("#current-activity-header").html(xhr.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
currentActivityHeader();
|
||||
|
||||
function currentActivity() {
|
||||
function getCurrentActivity() {
|
||||
$.ajax({
|
||||
url: 'get_current_activity',
|
||||
url: 'get_activity',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
async: true,
|
||||
complete: function(xhr, status) {
|
||||
$("#currentActivity").html(xhr.responseText);
|
||||
complete: function (xhr, status) {
|
||||
$('#dashboard-checking-activity').remove();
|
||||
|
||||
var current_activity = $.parseJSON(xhr.responseText);
|
||||
console.log(current_activity)
|
||||
var stream_count = parseInt(current_activity.stream_count);
|
||||
var sessions = current_activity.sessions;
|
||||
|
||||
if (stream_count) {
|
||||
$('#dashboard-no-activity').remove();
|
||||
|
||||
sessions.forEach(function (s) {
|
||||
var key = s.session_key;
|
||||
var instance = $('#instance-' + key);
|
||||
|
||||
// create a new instance if it doesn't exist
|
||||
if (!(instance.length)) {
|
||||
getActivityInstance(s);
|
||||
return;
|
||||
}
|
||||
|
||||
// update play state
|
||||
switch (s.state) {
|
||||
case 'playing':
|
||||
var overlay_state = 'State <strong>Playing</strong>';
|
||||
var state_icon = '<i class="fa fa-fw fa-play"></i> ';
|
||||
break;
|
||||
case 'paused':
|
||||
var overlay_state = 'State <strong>Paused</strong>';
|
||||
var state_icon = '<i class="fa fa-fw fa-pause"></i> ';
|
||||
break;
|
||||
case 'buffering':
|
||||
var overlay_state = 'State <strong>Buffering</strong>';
|
||||
var state_icon = '<i class="fa fa-fw fa-spinner"></i> ';
|
||||
break;
|
||||
default:
|
||||
var overlay_state = 'State <strong>Unknown</strong>';
|
||||
var state_icon = '<i class="fa fa-fw fa-question-circle"></i> ';
|
||||
}
|
||||
$('#overlay-play-state-' + key).html(overlay_state);
|
||||
$('#play-state-' + key).html(state_icon);
|
||||
|
||||
// if using bif indexes, update the bif thumbnail
|
||||
if (s.indexes == 1) {
|
||||
var bif_poster = $('#bif-' + key);
|
||||
bif_poster.animate({ opacity: 0 }, { duration: 1000, queue: false });
|
||||
bif_poster.after($('<div id="bif-' + key + '"class="dashboard-activity-poster-face" style="background-image: url(pms_image_proxy?img='
|
||||
+ s.bif_thumb + '&width=500&height=280&fallback=art);"></div>').fadeIn(1000, function () { bif_poster.remove() }));
|
||||
}
|
||||
|
||||
// if transcoding, update the transcode state
|
||||
if (s.video_decision == 'transcode' || s.audio_decision == 'transcode') {
|
||||
var throttled = (s.throttled == '1') ? ' (Throttled)' : '';
|
||||
$('#transcode-state-' + key).html('(Speed: ' + s.transcode_speed + ')' + throttled);
|
||||
}
|
||||
|
||||
// update the stream progress times
|
||||
$('#stream-eta-' + key).html(moment().add(parseInt(s.duration) - parseInt(s.view_offset), 'milliseconds').format(time_format));
|
||||
$('#stream-view-offset-' + key).html(millisecondsToMinutes(s.view_offset, false));
|
||||
|
||||
// update the progress bars
|
||||
// percent - 3 because of 3px padding-right
|
||||
$('#bufferbar-' + key).width(parseInt(s.transcode_progress) - 3 + '%').html(s.transcode_progress + '%');
|
||||
$('#bar-' + key).width(parseInt(s.progress_percent) - 3 + '%').html(s.progress_percent + '%');
|
||||
|
||||
// add temporary class so we know which instances are still active
|
||||
instance.addClass('updated-temp');
|
||||
});
|
||||
|
||||
// Remove finished instances
|
||||
var all_instances = $('div[id^=instance-]');
|
||||
all_instances.each(function (i, instance) {
|
||||
if ($(instance).hasClass('updated-temp')) {
|
||||
$(instance).removeClass('updated-temp');
|
||||
} else {
|
||||
$(instance).remove();
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
$('#currentActivity').html('<div id="dashboard-no-activity" class="text-muted" style="margin-bottom: 20px;">Nothing is currently being played.</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
currentActivity();
|
||||
|
||||
function getActivityInstance(session) {
|
||||
$.ajax({
|
||||
url: 'get_current_activity_instance',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
async: true,
|
||||
data: session,
|
||||
complete: function(xhr, status) {
|
||||
$('#currentActivity').append(xhr.responseText);
|
||||
$('#instance-' + session.session_key).find('.dashboard-activity-poster-face').hide().fadeIn(1000);
|
||||
$('#bufferbar-' + session.session_key).tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
$('#bar-' + session.session_key).tooltip({ container: 'body', placement: 'right', delay: 50 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentActivity();
|
||||
setInterval(function () {
|
||||
$('.bar, .bufferbar').tooltip('destroy');
|
||||
currentActivityHeader();
|
||||
currentActivity();
|
||||
getCurrentActivity();
|
||||
}, 15000);
|
||||
|
||||
// Show/Hide activity info
|
||||
$('#currentActivity').on('click', '.btn-activity-info', function (e) {
|
||||
e.preventDefault();
|
||||
$($(this).attr('data-target')).toggle();
|
||||
});
|
||||
|
||||
// Add hover class to dashboard-instance
|
||||
$('#currentActivity').on('mouseover', '.dashboard-hover-container', function () {
|
||||
$(this).closest('.dashboard-instance').addClass('hover');
|
||||
});
|
||||
$('#currentActivity').on('mouseleave', '.dashboard-hover-container', function () {
|
||||
var id = $(this).closest('.dashboard-instance').data('id');
|
||||
if (!($('#stream-' + id).is(':visible'))) {
|
||||
$(this).closest('.dashboard-instance').removeClass('hover');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
% endif
|
||||
% if 'watch_stats' in config['home_sections']:
|
||||
<script>
|
||||
function getHomeStats(days) {
|
||||
$.ajax({
|
||||
url: 'home_stats',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
async: true,
|
||||
data: { },
|
||||
complete: function(xhr, status) {
|
||||
complete: function (xhr, status) {
|
||||
$("#home-stats").html(xhr.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
getHomeStats();
|
||||
|
||||
</script>
|
||||
% endif
|
||||
% if 'library_stats' in config['home_sections']:
|
||||
<script>
|
||||
function getLibraryStats() {
|
||||
$.ajax({
|
||||
url: 'library_stats',
|
||||
type: 'GET',
|
||||
cache: false,
|
||||
async: true,
|
||||
data: { },
|
||||
complete: function(xhr, status) {
|
||||
complete: function (xhr, status) {
|
||||
$("#library-stats").html(xhr.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
getLibraryStats();
|
||||
|
||||
</script>
|
||||
% endif
|
||||
% if 'recently_added' in config['home_sections']:
|
||||
<script>
|
||||
function recentlyAdded() {
|
||||
$.ajax({
|
||||
url: 'get_recently_added',
|
||||
type: "GET",
|
||||
async: true,
|
||||
data: { count : 50 },
|
||||
complete: function(xhr, status) {
|
||||
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'); }
|
||||
|
@ -188,17 +325,6 @@
|
|||
}
|
||||
recentlyAdded();
|
||||
|
||||
var date_format = 'YYYY-MM-DD';
|
||||
var time_format = 'hh:mm a';
|
||||
$.ajax({
|
||||
url: 'get_date_formats',
|
||||
type: 'GET',
|
||||
success: function(data) {
|
||||
date_format = data.date_format;
|
||||
time_format = data.time_format;
|
||||
}
|
||||
});
|
||||
|
||||
function highlightAddedScrollerButton() {
|
||||
var scroller = $("#recently-added-row-scroller");
|
||||
var numElems = scroller.find("li:visible").length;
|
||||
|
@ -238,5 +364,5 @@
|
|||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
% endif
|
||||
</%def>
|
|
@ -231,6 +231,12 @@ class WebInterface(object):
|
|||
logger.warn(u"Unable to retrieve data for get_current_activity.")
|
||||
return serve_template(templatename="current_activity.html", data=None)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def get_current_activity_instance(self, **kwargs):
|
||||
|
||||
return serve_template(templatename="current_activity_instance.html", data=kwargs)
|
||||
|
||||
@cherrypy.expose
|
||||
@requireAuth()
|
||||
def get_current_activity_header(self, **kwargs):
|
||||
|
@ -3296,7 +3302,7 @@ class WebInterface(object):
|
|||
|
||||
@cherrypy.expose
|
||||
@cherrypy.tools.json_out()
|
||||
@requireAuth(member_of("admin"))
|
||||
@requireAuth()
|
||||
@addtoapi()
|
||||
def get_activity(self, **kwargs):
|
||||
""" Get the current activity on the PMS.
|
||||
|
@ -3374,9 +3380,15 @@ class WebInterface(object):
|
|||
}
|
||||
```
|
||||
"""
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
pms_connect = pmsconnect.PmsConnect(token=plexpy.CONFIG.PMS_TOKEN)
|
||||
result = pms_connect.get_current_activity()
|
||||
|
||||
data_factory = datafactory.DataFactory()
|
||||
for session in result['sessions']:
|
||||
if not session['ip_address']:
|
||||
ip_address = data_factory.get_session_ip(session['session_key'])
|
||||
session['ip_address'] = ip_address
|
||||
|
||||
if result:
|
||||
return result
|
||||
else:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue