Added restart and shutdown links in settings.

No longer exposing passwords in html forms.
Removed some old headphones js.
Minor styling adjustments.
Current activity on home screen now works.
Some history table fixes and additions.
Info screen for video items now works.
This commit is contained in:
Tim 2015-06-16 17:35:52 +02:00
commit 04b290173c
16 changed files with 1163 additions and 257 deletions

View file

@ -5,14 +5,7 @@
%>
<%def name="headerIncludes()">
<!--
<div id="subhead_container">
<div id="subhead_menu">
<a id="menu_link_shutdown" href="shutdown"><i class="fa fa-power-off"></i> Shut Down</a>
<a id="menu_link_shutdown" href="restart"><i class="fa fa-power-off"></i> Restart</a>
</div>
</div>
-->
</%def>
<%def name="body()">
@ -22,7 +15,15 @@
<div class="span12">
<div class="wellheader-bg">
<div class="dashboard-wellheader-no-chevron">
<h2><i class="fa fa-cog"></i> Settings</h2>
<div class="row-fluid">
<div class="span9"><h2><i class="fa fa-cog"></i> Settings</h2></div>
<div class="span3">
<div class="pull-right">
<h5><a id="menu_link_shutdown" href="shutdown"><i class="fa fa-power-off"></i> Shut Down</a>
&nbsp<a id="menu_link_restart" href="restart"><i class="fa fa-refresh"></i> Restart</a></h5>
</div>
</div>
</div>
</div>
</div>
</div>
@ -898,7 +899,6 @@
}
});
initActions();
initConfigCheckbox("#api_enabled");
initConfigCheckbox("#enable_https");

View file

@ -6650,7 +6650,7 @@ button.close {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 82%;
width: 80%;
margin-right: 5px;
float: left;
}
@ -6665,7 +6665,7 @@ button.close {
overflow: hidden;
white-space: nowrap;
font-size: 14px;
width: 82%;
width: 80%;
margin-right: 5px;
color: #fff;
float: left;

View file

@ -0,0 +1,99 @@
% if activity is not None:
% if activity['stream_count'] != '0':
% for a in activity['sessions']:
<div class="instance" id="instance-${a['sessionKey']}">
<div class="poster">
% if a['type'] == 'track-to-do':
<div class="art-music-face" style="background-image:url(pms_image_proxy?img=${a['thumb']}&width=300&height=300)"></div>
% elif a['type'] == 'movie':
<div class="dashboard-activity-poster-face">
<img src="pms_image_proxy?img=${a['art']}&width=300&height=169"/> <!-- media artwork -->
</div>
% else:
<div class="dashboard-activity-poster-face">
<img src="pms_image_proxy?img=${a['thumb']}&width=300&height=169"/> <!-- media artwork -->
</div>
% endif
<div class='dashboard-activity-metadata-wrapper'>
<div class='dashboard-activity-instance-overlay'>
<div class='dashboard-activity-metadata-progress-minutes'>
<div class='progress progress-warning'>
<div class="bar" style="width: ${a['progressPercent']}%">${a['progressPercent']}%</div>
</div>
</div>
<div class="dashboard-activity-metadata-platform" id="platform-${a['sessionKey']}">
<!-- <img src="interfaces/default/images/platforms/roku.png"> platform image -->
</div>
<div class="dashboard-activity-metadata-user">
${a['user']} is ${a['state']}
</div>
<div class="dashboard-activity-metadata-title">
% if a['type'] == 'episode':
<a href="info?rating_key=${a['ratingKey']}">${a['grandparentTitle']} - ${a['title']}</a>
% elif a['type'] == 'movie':
<a href="info?rating_key=${a['ratingKey']}">${a['title']}</a>
% elif a['type'] == 'track':
${a['artist']} - ${a['track']}
% else:
${a['grandparentTitle']} - ${a['title']}
% endif
</div>
</div>
<div id="stream-${a['sessionKey']}" class="collapse out">
<div class='dashboard-activity-info-details-overlay'>
<div class='dashboard-activity-info-details-content'>
% if a['type'] == 'track':
Artist: <strong>${a['artist']}</strong>
<br>
Album: <strong>${a['album']}</strong>
<br>
% endif
% if a['state'] == 'playing':
State: <strong>Playing</strong>
% elif a['state'] == 'paused':
State: <strong>Paused</strong>
% elif a['state'] == 'buffering':
State: <strong>Buffering</strong>
% endif
<br>
% if a['type'] == 'track':
% if a['audioDecision'] == 'direct play':
Stream: <strong>Direct Play</strong>
% else:
Stream: <strong>Transcoding</strong>
% endif
<br/>
Audio: <strong>${a['audioCodec']} (${a['audioChannels']}ch)</strong>
% elif a['type'] == 'episode' or a['type'] == 'movie':
% if a['videoDecision'] == 'direct play':
Stream: <strong>Direct Play</strong>
% else:
Stream: <strong>Transcoding</strong>
% endif
<br/>
Video: <strong>${a['videoDecision']} (${a['videoCodec']}) (${a['width']}x${a['height']})</strong>
<br/>
Audio: <strong>${a['audioDecision']} (${a['audioCodec']}) (${a['audioChannels']}ch)</strong>
% endif
<br>
</div>
</div>
</div>
</div>
</div>
<div class="dashboard-activity-button-info">
<button type="button" class="btn btn-warning" data-toggle="collapse" data-target="#stream-${a['sessionKey']}">
<i class='icon-info-sign icon-white'></i>
</button>
</div>
</div>
<script>
$("#platform-${a['sessionKey']}").html("<img src='" + getPlatformImagePath('${a['player']}') + "'>");
</script>
% endfor
% else:
<div class="muted">Nothing is currently being watched.</div><br>
% endif
% else:
<div class="muted">There was an error communicating with your Plex Server. Please check your settings.</div><br>
% endif

View file

@ -0,0 +1,9 @@
% if activity != None:
% if activity == '0':
<h3>Activity</h3>
% else:
<h3>Activity <strong>${activity}</strong> stream(s)</h3>
% endif
% else:
<h3>Activity</h3>
% endif

View file

@ -38,6 +38,7 @@
<th align='left' id="stopped"><i class='fa fa-sort'></i> Stopped</th>
<th align='left' id="duration"><i class='fa fa-sort'></i> Duration</th>
<th align='left' id="percent_complete"> Completed</th>
<th align='left' id="rating_key"> RatingKey</th>
</tr>
</thead>
<tbody>
@ -158,11 +159,21 @@
},
{
"targets": [4],
"data":"ip_address"
"data":"ip_address",
"createdCell": function (td, cellData, rowData, row, col) {
if ((cellData == '') || (cellData == '0')) {
$(td).html('n/a');
}
}
},
{
"targets": [5],
"data":"title"
"data":"title",
"createdCell": function (td, cellData, rowData, row, col) {
if (cellData !== '') {
$(td).html('<a href="info?rating_key=' + rowData['rating_key'] + '">' + cellData + '</a>');
}
}
},
{
"targets": [6],
@ -203,6 +214,11 @@
return '<span class="badge">100%</span>';
}
}
},
{
"targets": [11],
"data":"rating_key",
"visible": false
}
],
"drawCallback": function (settings) {

View file

@ -3,16 +3,61 @@
from plexpy import helpers
%>
<%def name="body()">
<div class="container">
</div>
</%def>
<%def name="headIncludes()">
</%def>
<%def name="body()">
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<div id="currentActivityHeader">
<h3>Activity</h3>
</div>
</div>
</div>
<div id="currentActivity">
<div class="muted">Checking for activity...</div><br>
</div>
</div>
</div>
</div>
</div>
</%def>
<%def name="javascriptIncludes()">
<script>
function currentActivity() {
$.ajax({
url: 'get_current_activity',
cache: false,
async: true,
complete: function(xhr, status) {
$("#currentActivity").html(xhr.responseText);
}
});
}
currentActivity();
setInterval(currentActivity, 15000);
function currentActivityHeader() {
$.ajax({
url: 'get_current_activity_header',
cache: false,
async: true,
complete: function(xhr, status) {
$("#currentActivityHeader").html(xhr.responseText);
}
});
}
currentActivityHeader();
setInterval(currentActivityHeader, 15000);
</script>
</%def>

View file

@ -0,0 +1,162 @@
<%inherit file="base.html"/>
<%!
from plexpy import helpers
%>
<%def name="headIncludes()">
</%def>
<%def name="body()">
% if metadata:
<div class="clear"></div>
<div class="container-fluid">
<!-- Some span12 if parameter -->
<div class="row-fluid">
<div class="span12">
<!-- end span12 if -->
<!-- if art -->
<div class="art-face" style="background-image:url(pms_image_proxy?img=${metadata['art']}&width=1920&height=1080)">
<!-- if not art
<div class="art-face">
-->
<div class="summary-wrapper">
<div class="summary-overlay">
<div class="row-fluid">
<div class="span9">
<div class="summary-content-poster hidden-phone hidden-tablet">
% if metadata['type'] == 'episode':
<img src="pms_image_proxy?img=${metadata['parentThumb']}&width=256&height=352">
% else:
<img src="pms_image_proxy?img=${metadata['thumb']}&width=256&height=352">
% endif
</div>
<div class="summary-content">
<div class="summary-content-title">
% if metadata['type'] == 'movie':
<h1>${metadata['title']} (${metadata['year']})</h1>
% elif metadata['type'] == 'season':
<h1>${metadata['parentTitle']} (${metadata['title']})</h1>
% elif metadata['type'] == 'episode':
<h1>${metadata['grandparentTitle']} (Season ${metadata['parentIndex']}, Episode ${metadata['index']}) "${metadata['title']}"</h1>
% else:
<h1>${metadata['title']}</h1>
% endif
</div>
% if metadata['type'] == 'movie':
<div id="stars" class="rateit hidden-phone hidden-tablet" data-rateit-value="" data-rateit-ispreset="true" data-rateit-readonly="true"></div>
% endif
<div class="summary-content-details-wrapper">
<div class="summary-content-director">
% if metadata['type'] == 'episode' or metadata['type'] == 'movie':
% if metadata['directors']:
Directed by <strong> ${metadata['directors'][0]}
% else:
Directed by <strong> unknown
% endif
% elif metadata['type'] == 'show':
Studio <strong> ${metadata['studio']}
% endif
</div>
<div class="summary-content-duration">
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
Runtime <strong> ${metadata['duration']} mins</strong>
% endif
</div>
<div class="summary-content-content-rating">
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
Rated <strong> ${metadata['contentRating']} </strong>
% endif
</div>
</div>
<div class="summary-content-summary">
% if metadata['type'] == 'episode' or metadata['type'] == 'movie' or metadata['type'] == 'show':
<p> ${metadata['summary']} </p>
% endif
</div>
</div>
</div>
% if metadata['type'] == 'episode':
<div class="span3">
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="summary-content-writers">
<h6><strong>Written by</strong></h6>
<ul>
% for writer in metadata['writers']:
% if loop.index < 5:
<li>
${writer}
</li>
% endif
% endfor
</ul>
</div>
</div>
</div>
% elif metadata['type'] == 'movie' or metadata['type'] == 'show':
<div class="span3">
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="summary-content-actors">
<h6><strong>Genres</strong></h6>
<ul>
% for genre in metadata['genres']:
% if loop.index < 5:
<li>
${genre}
</li>
% endif
% endfor
</ul>
</div>
<div class="summary-content-people-wrapper hidden-phone hidden-tablet">
<div class="summary-content-actors">
<h6><strong>Starring</strong></h6>
<ul>
% for actor in metadata['actors']:
% if loop.index < 5:
<li>
${actor}
</li>
% endif
% endfor
</ul>
</div>
</div>
</div>
</div>
% elif metadata['type'] == 'season':
<div class="span3"></div>
% endif
</div>
</div>
</div>
</div>
<!-- span rule -->
</div>
</div>
<!--}-->
</div>
% else:
<div class="clear"></div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span10 offset1">
<h3>Error retrieving item metadata. This media may not be available in the Plex Media Server database anymore.</h3>
</div>
</div>
</div>
% endif
</%def>
<%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.rateit.min.js"></script>
% if metadata['type'] == 'movie':
<script>
// Convert rating to 5 star rating type
var starRating = Math.round(${metadata['rating']} / 2)
$('#stars').attr('data-rateit-value', starRating)
</script>
% endif
</%def>

File diff suppressed because one or more lines are too long

View file

@ -1,142 +1,3 @@
function getThumb(imgElem,id,type) {
if ( type == 'artist' ) {
var thumbURL = "getThumb?ArtistID=" + id;
// var imgURL = "getArtwork?ArtistID=" + id;
} else {
var thumbURL = "getThumb?AlbumID=" + id;
// var imgURL = "getArtwork?AlbumID=" + id;
}
// Get Data from the cache by Artist ID
$.ajax({
url: thumbURL,
cache: true,
success: function(data){
if ( data == "" ) {
var imageUrl = "interfaces/default/images/no-cover-artist.png";
}
else {
var imageUrl = data;
}
$(imgElem).attr("src",imageUrl).hide().fadeIn();
// $(imgElem).wrap('<a href="'+ imgURL +'" rel="dialog" title="' + name + '"></a>');
}
});
}
function getArtwork(imgElem,id,name,type) {
if ( type == 'artist' ) {
var artworkURL = "getArtwork?ArtistID=" + id;
} else {
var artworkURL = "getArtwork?AlbumID=" + id;
}
// Get Data from the cache by Artist ID
$.ajax({
url: artworkURL,
cache: true,
success: function(data){
if ( data == "" || data == undefined ) {
var imageUrl = "interfaces/default/images/no-cover-artist.png";
}
else {
var imageUrl = data;
}
$(imgElem).attr("src",imageUrl).hide().fadeIn();
$(imgElem).wrap('<a href="'+ imageUrl +'" rel="dialog" title="' + name + '"></a>');
}
});
}
function getInfo(elem,id,type) {
if ( type == 'artist' ) {
var infoURL = "getInfo?ArtistID=" + id;
} else {
var infoURL = "getInfo?AlbumID=" + id;
}
// Get Data from the cache by ID
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data){
var summary = data.Summary;
$(elem).append(summary);
}
});
}
function getImageLinks(elem,id,type,unveil) {
if ( type == 'artist' ) {
var infoURL = "getImageLinks?ArtistID=" + id;
} else {
var infoURL = "getImageLinks?AlbumID=" + id;
}
// Get Data from the cache by ID
$.ajax({
url: infoURL,
cache: true,
dataType: "json",
success: function(data){
if (!data) {
// Invalid response
return;
}
if (!data.thumbnail) {
var thumbnail = "interfaces/default/images/no-cover-artist.png";
}
else {
var thumbnail = data.thumbnail;
}
if (!data.artwork) {
var artwork = "interfaces/default/images/no-cover-artist.png";
}
else {
var artwork = data.artwork;
}
if (unveil) {
$(elem).attr("data-src", thumbnail);
$(elem).unveil();
}
else {
$(elem).attr("src", thumbnail);
}
}
});
}
function initHeader() {
//settings
var header = $("#container header");
var fadeSpeed = 100, fadeTo = 0.5, topDistance = 20;
var topbarME = function() { $(header).fadeTo(fadeSpeed,1); }, topbarML = function() { $(header).fadeTo(fadeSpeed,fadeTo); };
var inside = false;
//do
$(window).scroll(function() {
position = $(window).scrollTop();
if(position > topDistance && !inside) {
//add events
topbarML();
$(header).bind('mouseenter',topbarME);
$(header).bind('mouseleave',topbarML);
$("#toTop").fadeIn();
inside = true;
}
else if (position < topDistance){
topbarME();
$(header).unbind('mouseenter',topbarME);
$(header).unbind('mouseleave',topbarML);
$("#toTop").fadeOut();
inside = false;
}
});
}
function initConfigCheckbox(elem) {
var config = $(elem).parent().next();
if ( $(elem).is(":checked") ) {
@ -153,66 +14,6 @@ function initConfigCheckbox(elem) {
}
});
}
function initActions() {
$("#subhead_menu #menu_link_refresh").button();
$("#subhead_menu #menu_link_edit").button();
$("#subhead_menu .menu_link_edit").button();
$("#subhead_menu #menu_link_delete" ).button();
$("#subhead_menu #menu_link_pauze").button();
$("#subhead_menu #menu_link_resume").button();
$("#subhead_menu #menu_link_getextra").button();
$("#subhead_menu #menu_link_removeextra").button();
$("#subhead_menu #menu_link_wanted" ).button();
$("#subhead_menu #menu_link_check").button();
$("#subhead_menu #menu_link_skipped").button();
$("#subhead_menu #menu_link_retry").button();
$("#subhead_menu #menu_link_new").button();
$("#subhead_menu #menu_link_shutdown").button();
$("#subhead_menu #menu_link_scan").button();
}
function refreshSubmenu() {
var url = $(location).attr('href');
$("#subhead_container").load(url + " #subhead_menu",function(){
initActions();
});
}
function refreshTable() {
var url = $(location).attr('href');
$("table.display").load(url + " table.display tbody, table.display thead", function() {
initThisPage();
});
}
function refreshLoadArtist() {
if ( $(".gradeL").length > 0 ) {
var url = $(location).attr('href');
var loadingRow = $("table.display tr.gradeL")
loadingRow.each(function(){
var row = $(this).index() + 1;
var rowLoad = $("table.display tbody tr:nth-child("+row+")");
$(rowLoad).load(url + " table.display tbody tr:nth-child("+ row +") td", function() {
if ( $(rowLoad).children("#status").text() == 'Active' ) {
// Active
$(rowLoad).removeClass('gradeL').addClass('gradeZ');
initThisPage();
} else {
// Still loading
setTimeout(function(){
refreshLoadArtist();
},3000);
}
});
});
}
}
function refreshTab() {
var url = $(location).attr('href');
var tabId = $('.ui-tabs-panel:visible').attr("id");
$('.ui-tabs-panel:visible').load(url + " #"+ tabId, function() {
initThisPage();
});
}
function showMsg(msg,loader,timeout,ms) {
var feedback = $("#ajaxMsg");
@ -240,21 +41,6 @@ function showMsg(msg,loader,timeout,ms) {
}
}
function showArtistMsg(msg) {
var feedback = $("#ajaxMsg2");
update = $("#updatebar");
if ( update.is(":visible") ) {
var height = update.height() + 35;
feedback.css("bottom",height + "px");
} else {
feedback.removeAttr("style");
}
feedback.fadeIn();
var message = $("<i class='fa fa-refresh fa-spin'></i> " + msg + "</div>");
feedback.css("padding","14px 10px")
$(feedback).prepend(message);
}
function doAjaxCall(url,elem,reload,form) {
// Set Message
feedback = $("#ajaxMsg");
@ -312,6 +98,7 @@ function doAjaxCall(url,elem,reload,form) {
$.ajax({
url: url,
data: dataString,
type: 'post',
beforeSend: function(jqXHR, settings) {
// Start loader etc.
feedback.prepend(loader);
@ -371,15 +158,53 @@ function resetFilters(text){
}
}
function initFancybox() {
if ( $("a[rel=dialog]").length > 0 ) {
$.getScript('interfaces/default/js/fancybox/jquery.fancybox-1.3.4.js', function() {
$("head").append("<link rel='stylesheet' href='interfaces/default/js/fancybox/jquery.fancybox-1.3.4.css'>");
$("a[rel=dialog]").fancybox();
});
}
}
function getPlatformImagePath(platformName) {
$(document).ready(function(){
initHeader();
});
if (platformName.indexOf("Roku") > -1) {
return 'interfaces/default/images/platforms/roku.png';
} else if (platformName.indexOf("Apple TV") > -1) {
return 'interfaces/default/images/platforms/appletv.png';
} else if (platformName.indexOf("Firefox") > -1) {
return 'interfaces/default/images/platforms/firefox.png';
} else if (platformName.indexOf("Chromecast") > -1) {
return 'interfaces/default/images/platforms/chromecast.png';
} else if (platformName.indexOf("Chrome") > -1) {
return 'interfaces/default/images/platforms/chrome.png';
} else if (platformName.indexOf("Android") > -1) {
return 'interfaces/default/images/platforms/android.png';
} else if (platformName.indexOf("Nexus") > -1) {
return 'interfaces/default/images/platforms/android.png';
} else if (platformName.indexOf("iPad") > -1) {
return 'interfaces/default/images/platforms/ios.png';
} else if (platformName.indexOf("iPhone") > -1) {
return 'interfaces/default/images/platforms/ios.png';
} else if (platformName.indexOf("iOS") > -1) {
return 'interfaces/default/images/platforms/ios.png';
} else if (platformName.indexOf("Plex Home Theater") > -1) {
return 'interfaces/default/images/platforms/pht.png';
} else if (platformName.indexOf("Linux/RPi-XMBC") > -1) {
return 'interfaces/default/images/platforms/xbmc.png';
} else if (platformName.indexOf("Safari") > -1) {
return 'interfaces/default/images/platforms/safari.png';
} else if (platformName.indexOf("Internet Explorer") > -1) {
return 'interfaces/default/images/platforms/ie.png';
} else if (platformName.indexOf("Unknown Browser") > -1) {
return 'interfaces/default/images/platforms/dafault.png';
} else if (platformName.indexOf("Windows-XBMC") > -1) {
return 'interfaces/default/images/platforms/xbmc.png';
} else if (platformName.indexOf("Xbox") > -1) {
return 'interfaces/default/images/platforms/xbox.png';
} else if (platformName.indexOf("Samsung") > -1) {
return 'interfaces/default/images/platforms/samsung.png';
} else if (platformName.indexOf("Opera") > -1) {
return 'interfaces/default/images/platforms/opera.png';
} else if (platformName.indexOf("KODI") > -1) {
return 'interfaces/default/images/platforms/kodi.png';
} else if (platformName.indexOf("Mystery 3") > -1) {
return 'interfaces/default/images/platforms/playstation.png';
} else if (platformName.indexOf("Mystery 4") > -1) {
return 'interfaces/default/images/platforms/playstation.png';
} else {
return 'interfaces/default/images/platforms/default.png';
}
}

View file

@ -71,7 +71,6 @@
<script>
$(document).ready(function() {
initActions();
$('#log_table').dataTable( {
"processing": false,

View file

@ -5,9 +5,16 @@
</%def>
<%def name="body()">
<div class="table_wrapper">
<div id="shutdown">
<h1><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}</h1>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div class="wellbg">
<div class="wellheader">
<div class="dashboard-wellheader">
<h2><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}</h2>
</div>
</div>
</div>
</div>
</div>
</%def>