Initial implementation of login control

This commit is contained in:
JonnyWong16 2016-04-20 21:25:19 -07:00
parent 0aa2537d1e
commit 51a12099e4
24 changed files with 541 additions and 224 deletions

View file

@ -12,14 +12,14 @@ from plexpy.helpers import anon_url
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet"> <link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet"> <link href="${http_root}css/plexpy.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet"> <link href="${http_root}css/font-awesome.min.css" rel="stylesheet">
${next.headIncludes()} ${next.headIncludes()}
<link rel="icon" type="image/x-icon" href="interfaces/default/images/favicon.ico"/> <link rel="icon" type="image/x-icon" href="${http_root}images/favicon.ico"/>
<link rel="shortcut icon" href="interfaces/default/images/favicon.png"> <link rel="shortcut icon" href="${http_root}images/favicon.png">
<!-- Allow web app to be run in full-screen mode. --> <!-- Allow web app to be run in full-screen mode. -->
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-capable" content="yes">
@ -33,99 +33,99 @@ from plexpy.helpers import anon_url
<!-- ICONS --> <!-- ICONS -->
<!-- IE10 icon --> <!-- IE10 icon -->
<meta name="application-name" content="PlexPy" /> <meta name="application-name" content="PlexPy" />
<meta name="msapplication-config" content="interfaces/default/xml/IEconfig.xml"/> <meta name="msapplication-config" content="${http_root}xml/IEconfig.xml"/>
<!-- Android >M39 icon --> <!-- Android >M39 icon -->
<link rel="manifest" href="interfaces/default/json/Android-manifest.json"> <link rel="manifest" href="${http_root}json/Android-manifest.json">
<!-- iPad retina icon --> <!-- iPad retina icon -->
<link href="interfaces/default/images/res/ios/icon-76@2x.png" sizes="152x152" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-76@2x.png" sizes="152x152" rel="apple-touch-icon-precomposed">
<!-- iPad retina icon (iOS < 7) --> <!-- iPad retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon-72@2x.png" sizes="144x144" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-72@2x.png" sizes="144x144" rel="apple-touch-icon-precomposed">
<!-- iPad non-retina icon --> <!-- iPad non-retina icon -->
<link href="interfaces/default/images/res/ios/icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-76.png" sizes="76x76" rel="apple-touch-icon-precomposed">
<!-- iPad non-retina icon (iOS < 7) --> <!-- iPad non-retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-72.png" sizes="72x72" rel="apple-touch-icon-precomposed">
<!-- iPhone 6 Plus icon --> <!-- iPhone 6 Plus icon -->
<link href="interfaces/default/images/res/ios/icon-60@2x.png" sizes="120x120" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-60@2x.png" sizes="120x120" rel="apple-touch-icon-precomposed">
<!-- iPhone retina icon (iOS < 7) --> <!-- iPhone retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon@2x.png" sizes="114x114" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon@2x.png" sizes="114x114" rel="apple-touch-icon-precomposed">
<!-- iPhone non-retina icon (iOS < 7) --> <!-- iPhone non-retina icon (iOS < 7) -->
<link href="interfaces/default/images/res/ios/icon.png" sizes="57x57" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon.png" sizes="57x57" rel="apple-touch-icon-precomposed">
<!-- iPhone / iPod Touch --> <!-- iPhone / iPod Touch -->
<link href="interfaces/default/images/res/ios/icon-60@3x.png" sizes="180x180" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-60@3x.png" sizes="180x180" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-60.png" sizes="60x60" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-60.png" sizes="60x60" rel="apple-touch-icon-precomposed">
<!-- Spotlight Icon --> <!-- Spotlight Icon -->
<link href="interfaces/default/images/res/ios/icon-40.png" sizes="40x40" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-40.png" sizes="40x40" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-40@2x.png" sizes="80x80" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-40@2x.png" sizes="80x80" rel="apple-touch-icon-precomposed">
<!-- iPhone Spotlight and Settings Icon --> <!-- iPhone Spotlight and Settings Icon -->
<link href="interfaces/default/images/res/ios/icon-small.png" sizes="29x29" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-small.png" sizes="29x29" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-small@2x.png" sizes="58x58" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-small@2x.png" sizes="58x58" rel="apple-touch-icon-precomposed">
<!-- iPad Spotlight and Settings Icon --> <!-- iPad Spotlight and Settings Icon -->
<link href="interfaces/default/images/res/ios/icon-50.png" sizes="50x50" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-50.png" sizes="50x50" rel="apple-touch-icon-precomposed">
<link href="interfaces/default/images/res/ios/icon-50@2x.png" sizes="100x100" rel="apple-touch-icon-precomposed"> <link href="${http_root}images/res/ios/icon-50@2x.png" sizes="100x100" rel="apple-touch-icon-precomposed">
<!-- STARTUP IMAGES --> <!-- STARTUP IMAGES -->
<!-- iPad retina portrait startup image --> <!-- iPad retina portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Portrait@2x~ipad.png" <link href="${http_root}images/res/screen/ios/Default-Portrait@2x~ipad.png"
media="(device-width: 768px) and (device-height: 1024px) media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2)
and (orientation: portrait)" and (orientation: portrait)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPad retina landscape startup image --> <!-- iPad retina landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape@2x~ipad.png" <link href="${http_root}images/res/screen/ios/Default-Landscape@2x~ipad.png"
media="(device-width: 768px) and (device-height: 1024px) media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 2) and (-webkit-device-pixel-ratio: 2)
and (orientation: landscape)" and (orientation: landscape)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPad non-retina portrait startup image --> <!-- iPad non-retina portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Portrait~ipad.png" <link href="${http_root}images/res/screen/ios/Default-Portrait~ipad.png"
media="(device-width: 768px) and (device-height: 1024px) media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 1) and (-webkit-device-pixel-ratio: 1)
and (orientation: portrait)" and (orientation: portrait)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPad non-retina landscape startup image --> <!-- iPad non-retina landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape~ipad.png" <link href="${http_root}images/res/screen/ios/Default-Landscape~ipad.png"
media="(device-width: 768px) and (device-height: 1024px) media="(device-width: 768px) and (device-height: 1024px)
and (-webkit-device-pixel-ratio: 1) and (-webkit-device-pixel-ratio: 1)
and (orientation: landscape)" and (orientation: landscape)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone 6 Plus portrait startup image --> <!-- iPhone 6 Plus portrait startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-736h.png" <link href="${http_root}images/res/screen/ios/Default-736h.png"
media="(device-width: 414px) and (device-height: 736px) media="(device-width: 414px) and (device-height: 736px)
and (-webkit-device-pixel-ratio: 3) and (-webkit-device-pixel-ratio: 3)
and (orientation: portrait)" and (orientation: portrait)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone 6 Plus landscape startup image --> <!-- iPhone 6 Plus landscape startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-Landscape-736h.png" <link href="${http_root}images/res/screen/ios/Default-Landscape-736h.png"
media="(device-width: 414px) and (device-height: 736px) media="(device-width: 414px) and (device-height: 736px)
and (-webkit-device-pixel-ratio: 3) and (-webkit-device-pixel-ratio: 3)
and (orientation: landscape)" and (orientation: landscape)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone 6 startup image --> <!-- iPhone 6 startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-667h.png" <link href="${http_root}images/res/screen/ios/Default-667h.png"
media="(device-width: 375px) and (device-height: 667px) media="(device-width: 375px) and (device-height: 667px)
and (-webkit-device-pixel-ratio: 2)" and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone 5 startup image --> <!-- iPhone 5 startup image -->
<link href="interfaces/default/images/res/screen/ios/Default-568h@2x~iphone5.jpg" <link href="${http_root}images/res/screen/ios/Default-568h@2x~iphone5.jpg"
media="(device-width: 320px) and (device-height: 568px) media="(device-width: 320px) and (device-height: 568px)
and (-webkit-device-pixel-ratio: 2)" and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone < 5 retina startup image --> <!-- iPhone < 5 retina startup image -->
<link href="interfaces/default/images/res/screen/ios/Default@2x~iphone.png" <link href="${http_root}images/res/screen/ios/Default@2x~iphone.png"
media="(device-width: 320px) and (device-height: 480px) media="(device-width: 320px) and (device-height: 480px)
and (-webkit-device-pixel-ratio: 2)" and (-webkit-device-pixel-ratio: 2)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
<!-- iPhone < 5 non-retina startup image --> <!-- iPhone < 5 non-retina startup image -->
<link href="interfaces/default/images/res/screen/ios/Default~iphone.png" <link href="${http_root}images/res/screen/ios/Default~iphone.png"
media="(device-width: 320px) and (device-height: 480px) media="(device-width: 320px) and (device-height: 480px)
and (-webkit-device-pixel-ratio: 1)" and (-webkit-device-pixel-ratio: 1)"
rel="apple-touch-startup-image"> rel="apple-touch-startup-image">
@ -158,7 +158,7 @@ from plexpy.helpers import anon_url
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand" href="home"> <a class="navbar-brand" href="home">
<img alt="PlexPy" src="interfaces/default/images/logo-plexpy@2x.png" height="40"> <img alt="PlexPy" src="${http_root}images/logo-plexpy@2x.png" height="40">
</a> </a>
</div> </div>
<div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1"> <div class="collapse navbar-collapse navbar-right" id="navbar-collapse-1">
@ -226,9 +226,9 @@ ${next.headerIncludes()}
${next.body()} ${next.body()}
</div> </div>
<script src="interfaces/default/js/jquery-2.1.4.min.js"></script> <script src="${http_root}js/jquery-2.1.4.min.js"></script>
<script src="interfaces/default/js/bootstrap3/bootstrap.min.js"></script> <script src="${http_root}js/bootstrap3/bootstrap.min.js"></script>
<script src="interfaces/default/js/script.js"></script> <script src="${http_root}js/script.js"></script>
<script> <script>
$('#updateDismiss').click(function() { $('#updateDismiss').click(function() {
$('#updatebar').slideUp('slow'); $('#updatebar').slideUp('slow');

View file

@ -2791,4 +2791,70 @@ a.no-highlight:hover {
#recently-added-row-scroller, #recently-added-row-scroller,
#recently-watched-row-scroller { #recently-watched-row-scroller {
position: relative; position: relative;
}
@media (min-width: 768px) {
.login-container {
max-width: 750px;
}
}
@media (min-width: 992px) {
.login-container {
max-width: 970px;
}
}
@media (min-width: 1200px) {
.login-container {
max-width: 1170px;
}
}
.login-container {
margin-right: auto;
margin-left: auto;
padding-left: 15px;
padding-right: 15px;
}
.login {
margin: 0 auto;
}
.login-logo {
background-image: url(../images/logo-plexpy@2x.png);
background-position: center;
background-repeat: no-repeat;
margin: 0 auto 50px auto;
width: 340px;
height: 100px;
}
.login-container .form-group {
margin-bottom: 20px;
}
.login-container .form-group label {
font-weight: 400;
color: #999;
}
.login-container .form-control {
height: 38px;
line-height: 1.5em;
}
.login-container .form-footer {
margin-top: 40px;
}
.login-container .login-button {
float: right;
text-transform: uppercase;
text-shadow: 0 -1px 1px rgba(0,0,0,.4),0 0 15px rgba(0,0,0,.2);
}
.login-container .remember-group {
display: block;
min-height: 24px;
margin-top: 10px;
margin-bottom: 10px;
vertical-align: middle;
color: #999;
}
.login-container .remember-group .control-label {
display: inline;
margin-bottom: 0;
font-weight: 400;
cursor: pointer;
} }

View file

@ -1,8 +1,8 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -248,12 +248,12 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/moment-duration-format.js"></script> <script src="${http_root}js/moment-duration-format.js"></script>
<script src="interfaces/default/js/highcharts/js/highcharts.js"></script> <script src="${http_root}js/highcharts/js/highcharts.js"></script>
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script> <script>
// Modal popup dialog // Modal popup dialog
@ -302,17 +302,17 @@
} }
} }
</script> </script>
<script src="interfaces/default/js/graphs/plays_by_day.js"></script> <script src="${http_root}js/graphs/plays_by_day.js"></script>
<script src="interfaces/default/js/graphs/plays_by_dayofweek.js"></script> <script src="${http_root}js/graphs/plays_by_dayofweek.js"></script>
<script src="interfaces/default/js/graphs/plays_by_hourofday.js"></script> <script src="${http_root}js/graphs/plays_by_hourofday.js"></script>
<script src="interfaces/default/js/graphs/plays_by_platform.js"></script> <script src="${http_root}js/graphs/plays_by_platform.js"></script>
<script src="interfaces/default/js/graphs/plays_by_user.js"></script> <script src="${http_root}js/graphs/plays_by_user.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_source_resolution.js"></script> <script src="${http_root}js/graphs/plays_by_source_resolution.js"></script>
<script src="interfaces/default/js/graphs/plays_by_stream_resolution.js"></script> <script src="${http_root}js/graphs/plays_by_stream_resolution.js"></script>
<script src="interfaces/default/js/graphs/plays_by_platform_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_platform_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_user_by_stream_type.js"></script> <script src="${http_root}js/graphs/plays_by_user_by_stream_type.js"></script>
<script src="interfaces/default/js/graphs/plays_by_month.js"></script> <script src="${http_root}js/graphs/plays_by_month.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {

View file

@ -1,9 +1,9 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -69,12 +69,12 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="${http_root}js/tables/history_table.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
function loadHistoryTable(media_type) { function loadHistoryTable(media_type) {

View file

@ -29,7 +29,7 @@
</div> </div>
<div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal"> <div class="modal fade" id="info-modal" tabindex="-1" role="dialog" aria-labelledby="info-modal">
</div> </div>
<script src="interfaces/default/js/tables/history_table_modal.js"></script> <script src="${http_root}js/tables/history_table_modal.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$('#date-header').html(moment('${data["start_date"]}','YYYY-MM-DD').format('ddd MMM Do YYYY')); $('#date-header').html(moment('${data["start_date"]}','YYYY-MM-DD').format('ddd MMM Do YYYY'));

View file

@ -101,7 +101,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -137,7 +137,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -177,7 +177,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -209,7 +209,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -253,7 +253,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -289,7 +289,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -329,7 +329,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -361,7 +361,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -405,7 +405,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -441,7 +441,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -481,7 +481,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -513,7 +513,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster2"> <div class="home-platforms-instance-poster2">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -565,7 +565,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-instance-oval" style="background-image: url(interfaces/default/images/gravatar-default.png);"></div> <div class="home-platforms-instance-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -609,7 +609,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-oval" style="background-image: url(interfaces/default/images/gravatar-default.png);"></div> <div class="home-platforms-instance-list-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -644,7 +644,7 @@ DOCUMENTATION :: END
</div> </div>
<div id="platform-stat" class="home-platforms-instance-poster" title="${top_stat['rows'][0]['platform_type']}"> <div id="platform-stat" class="home-platforms-instance-poster" title="${top_stat['rows'][0]['platform_type']}">
<script> <script>
$("#platform-stat").html("<div class='home-platforms-instance-box' style='background-image: url(" + getPlatformImagePath('${top_stat['rows'][0]['platform_type']}') + ");'>"); $("#platform-stat").html("<div class='home-platforms-instance-box' style='background-image: url(" + getPlatformImagePath("${top_stat['rows'][0]['platform_type']}") + ");'>");
</script> </script>
</div> </div>
% if len(top_stat['rows']) > 1: % if len(top_stat['rows']) > 1:
@ -672,7 +672,7 @@ DOCUMENTATION :: END
</div> </div>
<div class="home-platforms-instance-poster" id="home-platforms-instance-poster-${loop.index + 1}" title="${top_stat['rows'][loop.index]['platform_type']}"> <div class="home-platforms-instance-poster" id="home-platforms-instance-poster-${loop.index + 1}" title="${top_stat['rows'][loop.index]['platform_type']}">
<script> <script>
$("#home-platforms-instance-poster-${loop.index + 1}").html("<div class='home-platforms-instance-list-box' style='background-image: url(" + getPlatformImagePath('${top_stat['rows'][loop.index]['platform_type']}') + ");'>"); $("#home-platforms-instance-poster-${loop.index + 1}").html("<div class='home-platforms-instance-list-box' style='background-image: url(" + getPlatformImagePath("${top_stat['rows'][loop.index]['platform_type']}") + ");'>");
</script> </script>
</div> </div>
<div class="home-platforms-instance-list-number"> <div class="home-platforms-instance-list-number">
@ -725,7 +725,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -771,7 +771,7 @@ DOCUMENTATION :: END
</div> </div>
% else: % else:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-poster">
<div class="home-platforms-list-poster-face" style="background-image: url(interfaces/default/images/poster.png);"></div> <div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div>
</div> </div>
% endif % endif
</a> </a>
@ -807,7 +807,7 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-instance-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div> <div class="home-platforms-instance-box" style="background-image: url(${http_root}images/home-stat_most-concurrent.png);"></div>
</div> </div>
% if len(top_stat['rows']) > 1: % if len(top_stat['rows']) > 1:
<div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div> <div class="home-platforms-instance-list-chevron"><i class="fa fa-chevron-down"></i></div>
@ -839,7 +839,7 @@ DOCUMENTATION :: END
</div> </div>
</div> </div>
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-poster">
<div class="home-platforms-instance-list-box" style="background-image: url(interfaces/default/images/home-stat_most-concurrent.png);"></div> <div class="home-platforms-instance-list-box" style="background-image: url(${http_root}images/home-stat_most-concurrent.png);"></div>
</div> </div>
</li> </li>
% endif % endif

View file

@ -65,7 +65,7 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script> <script>
function currentActivityHeader() { function currentActivityHeader() {
$.ajax({ $.ajax({

View file

@ -57,9 +57,9 @@ DOCUMENTATION :: END
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -172,16 +172,16 @@ DOCUMENTATION :: END
% if data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track': % if data['media_type'] == 'movie' or data['media_type'] == 'episode' or data['media_type'] == 'track':
<div class="summary-content-media-info-wrapper"> <div class="summary-content-media-info-wrapper">
% if data['media_type'] != 'track' and data['video_codec']: % if data['media_type'] != 'track' and data['video_codec']:
<img class="summary-content-media-flag" title="${data['video_codec']}" src="interfaces/default/images/media_flags/video_codec/${data['video_codec'] | vf}.png" /> <img class="summary-content-media-flag" title="${data['video_codec']}" src="${http_root}images/media_flags/video_codec/${data['video_codec'] | vf}.png" />
% endif % endif
% if data['media_type'] != 'track' and data['video_resolution']: % if data['media_type'] != 'track' and data['video_resolution']:
<img class="summary-content-media-flag" title="${data['video_resolution']}" src="interfaces/default/images/media_flags/video_resolution/${data['video_resolution']}.png" /> <img class="summary-content-media-flag" title="${data['video_resolution']}" src="${http_root}images/media_flags/video_resolution/${data['video_resolution']}.png" />
% endif % endif
% if data['audio_codec']: % if data['audio_codec']:
<img class="summary-content-media-flag" title="${data['audio_codec']}" src="interfaces/default/images/media_flags/audio_codec/${data['audio_codec'] | af}.png" /> <img class="summary-content-media-flag" title="${data['audio_codec']}" src="${http_root}images/media_flags/audio_codec/${data['audio_codec'] | af}.png" />
% endif % endif
% if data['audio_channels']: % if data['audio_channels']:
<img class="summary-content-media-flag" title="${data['audio_channels']}" src="interfaces/default/images/media_flags/audio_channels/${data['audio_channels']}.png" /> <img class="summary-content-media-flag" title="${data['audio_channels']}" src="${http_root}images/media_flags/audio_channels/${data['audio_channels']}.png" />
% endif % endif
</div> </div>
% endif % endif
@ -415,15 +415,15 @@ DOCUMENTATION :: END
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.rateit.min.js"></script> <script src="${http_root}js/jquery.rateit.min.js"></script>
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
% if data: % if data:
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="${http_root}js/tables/history_table.js"></script>
<!-- Need to find a place to put this --> <!-- Need to find a place to put this -->
% if data['media_type'] == 'show' or data['media_type'] == 'artist': % if data['media_type'] == 'show' or data['media_type'] == 'artist':
<script> <script>

View file

@ -177,63 +177,63 @@ function resetFilters(text){
function getPlatformImagePath(platformName) { function getPlatformImagePath(platformName) {
if (platformName.indexOf("Roku") > -1) { if (platformName.indexOf("Roku") > -1) {
return 'interfaces/default/images/platforms/roku.png'; return 'images/platforms/roku.png';
} else if (platformName.indexOf("Apple TV") > -1) { } else if (platformName.indexOf("Apple TV") > -1) {
return 'interfaces/default/images/platforms/atv.png'; return 'images/platforms/atv.png';
} else if (platformName.indexOf("tvOS") > -1) { } else if (platformName.indexOf("tvOS") > -1) {
return 'interfaces/default/images/platforms/atv.png'; return 'images/platforms/atv.png';
} else if (platformName.indexOf("Firefox") > -1) { } else if (platformName.indexOf("Firefox") > -1) {
return 'interfaces/default/images/platforms/firefox.png'; return 'images/platforms/firefox.png';
} else if (platformName.indexOf("Chromecast") > -1) { } else if (platformName.indexOf("Chromecast") > -1) {
return 'interfaces/default/images/platforms/chromecast.png'; return 'images/platforms/chromecast.png';
} else if (platformName.indexOf("Chrome") > -1) { } else if (platformName.indexOf("Chrome") > -1) {
return 'interfaces/default/images/platforms/chrome.png'; return 'images/platforms/chrome.png';
} else if (platformName.indexOf("Android") > -1) { } else if (platformName.indexOf("Android") > -1) {
return 'interfaces/default/images/platforms/android.png'; return 'images/platforms/android.png';
} else if (platformName.indexOf("Nexus") > -1) { } else if (platformName.indexOf("Nexus") > -1) {
return 'interfaces/default/images/platforms/android.png'; return 'images/platforms/android.png';
} else if (platformName.indexOf("iPad") > -1) { } else if (platformName.indexOf("iPad") > -1) {
return 'interfaces/default/images/platforms/ios.png'; return 'images/platforms/ios.png';
} else if (platformName.indexOf("iPhone") > -1) { } else if (platformName.indexOf("iPhone") > -1) {
return 'interfaces/default/images/platforms/ios.png'; return 'images/platforms/ios.png';
} else if (platformName.indexOf("iOS") > -1) { } else if (platformName.indexOf("iOS") > -1) {
return 'interfaces/default/images/platforms/ios.png'; return 'images/platforms/ios.png';
} else if (platformName.indexOf("Plex Home Theater") > -1) { } else if (platformName.indexOf("Plex Home Theater") > -1) {
return 'interfaces/default/images/platforms/pht.png'; return 'images/platforms/pht.png';
} else if (platformName.indexOf("Linux/RPi-XMBC") > -1) { } else if (platformName.indexOf("Linux/RPi-XMBC") > -1) {
return 'interfaces/default/images/platforms/xbmc.png'; return 'images/platforms/xbmc.png';
} else if (platformName.indexOf("Safari") > -1) { } else if (platformName.indexOf("Safari") > -1) {
return 'interfaces/default/images/platforms/safari.png'; return 'images/platforms/safari.png';
} else if (platformName.indexOf("Internet Explorer") > -1) { } else if (platformName.indexOf("Internet Explorer") > -1) {
return 'interfaces/default/images/platforms/ie.png'; return 'images/platforms/ie.png';
} else if (platformName.indexOf("Microsoft Edge") > -1) { } else if (platformName.indexOf("Microsoft Edge") > -1) {
return 'interfaces/default/images/platforms/msedge.png'; return 'images/platforms/msedge.png';
} else if (platformName.indexOf("Unknown Browser") > -1) { } else if (platformName.indexOf("Unknown Browser") > -1) {
return 'interfaces/default/images/platforms/dafault.png'; return 'images/platforms/dafault.png';
} else if (platformName.indexOf("Windows-XBMC") > -1) { } else if (platformName.indexOf("Windows-XBMC") > -1) {
return 'interfaces/default/images/platforms/xbmc.png'; return 'images/platforms/xbmc.png';
} else if (platformName.indexOf("Xbox") > -1) { } else if (platformName.indexOf("Xbox") > -1) {
return 'interfaces/default/images/platforms/xbox.png'; return 'images/platforms/xbox.png';
} else if (platformName.indexOf("Samsung") > -1) { } else if (platformName.indexOf("Samsung") > -1) {
return 'interfaces/default/images/platforms/samsung.png'; return 'images/platforms/samsung.png';
} else if (platformName.indexOf("Opera") > -1) { } else if (platformName.indexOf("Opera") > -1) {
return 'interfaces/default/images/platforms/opera.png'; return 'images/platforms/opera.png';
} else if (platformName.indexOf("KODI") > -1) { } else if (platformName.indexOf("KODI") > -1) {
return 'interfaces/default/images/platforms/kodi.png'; return 'images/platforms/kodi.png';
} else if (platformName.indexOf("Playstation 3") > -1) { } else if (platformName.indexOf("Playstation 3") > -1) {
return 'interfaces/default/images/platforms/playstation.png'; return 'images/platforms/playstation.png';
} else if (platformName.indexOf("Playstation 4") > -1) { } else if (platformName.indexOf("Playstation 4") > -1) {
return 'interfaces/default/images/platforms/playstation.png'; return 'images/platforms/playstation.png';
} else if (platformName.indexOf("Xbox 360") > -1) { } else if (platformName.indexOf("Xbox 360") > -1) {
return 'interfaces/default/images/platforms/xbox.png'; return 'images/platforms/xbox.png';
} else if (platformName.indexOf("Windows") > -1) { } else if (platformName.indexOf("Windows") > -1) {
return 'interfaces/default/images/platforms/win8.png'; return 'images/platforms/win8.png';
} else if (platformName.indexOf("Windows phone") > -1) { } else if (platformName.indexOf("Windows phone") > -1) {
return 'interfaces/default/images/platforms/wp.png'; return 'images/platforms/wp.png';
} else if (platformName.indexOf("Plex Media Player") > -1) { } else if (platformName.indexOf("Plex Media Player") > -1) {
return 'interfaces/default/images/platforms/pmp.png'; return 'images/platforms/pmp.png';
} else { } else {
return 'interfaces/default/images/platforms/default.png'; return 'images/platforms/default.png';
} }
} }

View file

@ -47,7 +47,7 @@ libraries_list_table_options = {
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(pms_image_proxy?img=' + rowData['library_thumb'] + '&width=80&height=80&fallback=poster);"></div></a>'); $(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(pms_image_proxy?img=' + rowData['library_thumb'] + '&width=80&height=80&fallback=poster);"></div></a>');
} }
} else { } else {
$(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(interfaces/default/images/cover.png);"></div></a>'); $(td).html('<a href="library?section_id=' + rowData['section_id'] + '"><div class="libraries-poster-face" style="background-image: url(../../images/cover.png);"></div></a>');
} }
}, },
"orderable": false, "orderable": false,

View file

@ -57,7 +57,7 @@ users_list_table_options = {
"data": "user_thumb", "data": "user_thumb",
"createdCell": function (td, cellData, rowData, row, col) { "createdCell": function (td, cellData, rowData, row, col) {
if (cellData === '') { if (cellData === '') {
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(interfaces/default/images/gravatar-default-80x80.png);"></div></a>'); $(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(../../images/gravatar-default-80x80.png);"></div></a>');
} else { } else {
$(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + rowData['user_thumb'] + ');"></div></a>'); $(td).html('<a href="user?user_id=' + rowData['user_id'] + '"><div class="users-poster-face" style="background-image: url(' + rowData['user_thumb'] + ');"></div></a>');
} }

View file

@ -1,9 +1,9 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -81,12 +81,12 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/libraries.js"></script> <script src="${http_root}js/tables/libraries.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
libraries_list_table_options.ajax = { libraries_list_table_options.ajax = {

View file

@ -28,9 +28,9 @@ DOCUMENTATION :: END
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -321,10 +321,10 @@ DOCUMENTATION :: END
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
% if data: % if data:
<script> <script>
% if str(data['section_id']).isdigit(): % if str(data['section_id']).isdigit():
@ -341,9 +341,9 @@ DOCUMENTATION :: END
var get_file_sizes = null; var get_file_sizes = null;
% endif % endif
</script> </script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="${http_root}js/tables/history_table.js"></script>
<script src="interfaces/default/js/tables/media_info_table.js"></script> <script src="${http_root}js/tables/media_info_table.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#edit-library-tooltip").tooltip(); $("#edit-library-tooltip").tooltip();

View file

@ -0,0 +1,66 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>PlexPy - ${title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="${http_root}css/bootstrap-wizard.css" rel="stylesheet">
<link href="${http_root}css/plexpy.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="${http_root}css/font-awesome.min.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="${http_root}images/favicon.ico"/>
<link rel="shortcut icon" href="${http_root}images/favicon.ico">
</head>
<body>
<div class="body-container">
<div class="container-fluid">
<div class="row">
<div class="login-container">
<div class="login-logo"></div>
<div class="row">
<div class="col-sm-6 col-sm-offset-3">
<form action="${http_root}auth/login" method="post">
% if msg:
<div class="alert alert-danger" style="text-align: center; padding: 8px;">
${msg}
</div>
% endif
<div class="username-group form-group">
<label for="username" class="control-label">
Username
</label>
<input type="text" id="username" name="username" class="form-control" autocorrect="off" autocapitalize="off" value="${username}">
</div>
<div class="password-group form-group">
<label for="password" class="control-label">
Password
</label>
<input type="password" id="password" name="password" class="form-control">
</div>
<div class="form-footer">
<button type="submit" class="btn btn-lg btn-bright login-button">Sign In</button>
<div class="remember-group">
<label class="control-label">
<input type="checkbox" id="remember_me" name="remember_me" title="for 30 days" value=1 checked="checked" /> Remember me
</label>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="${http_root}js/jquery-2.1.4.min.js"></script>
<script src="${http_root}js/bootstrap3/bootstrap.min.js"></script>
<script src="${http_root}js/bootstrap-wizard.min.js"></script>
</body>
</html>

View file

@ -4,8 +4,8 @@ from plexpy import helpers
%> %>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
<style> <style>
td {word-break: break-all;} td {word-break: break-all;}
</style> </style>
@ -107,13 +107,13 @@ from plexpy import helpers
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/logs.js"></script> <script src="${http_root}js/tables/logs.js"></script>
<script src="interfaces/default/js/tables/plex_logs.js"></script> <script src="${http_root}js/tables/plex_logs.js"></script>
<script src="interfaces/default/js/tables/notification_logs.js"></script> <script src="${http_root}js/tables/notification_logs.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {

View file

@ -1918,9 +1918,9 @@ available_notification_agents = sorted(notifiers.available_notification_agents()
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/parsley.min.js"></script> <script src="${http_root}js/parsley.min.js"></script>
<script src="interfaces/default/js/Sortable.min.js"></script> <script src="${http_root}js/Sortable.min.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {

View file

@ -1,9 +1,9 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<style> <style>
td {word-wrap: break-word} td {word-wrap: break-word}
</style> </style>
@ -46,11 +46,11 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/tables/sync_table.js"></script> <script src="${http_root}js/tables/sync_table.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {
sync_table_options.ajax = { sync_table_options.ajax = {

View file

@ -30,9 +30,9 @@ from plexpy import helpers
%> %>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -301,15 +301,15 @@ from plexpy import helpers
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
% if data: % if data:
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/history_table.js"></script> <script src="${http_root}js/tables/history_table.js"></script>
<script src="interfaces/default/js/tables/user_ips.js"></script> <script src="${http_root}js/tables/user_ips.js"></script>
<script src="interfaces/default/js/tables/sync_table.js"></script> <script src="${http_root}js/tables/sync_table.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {

View file

@ -1,9 +1,9 @@
<%inherit file="base.html"/> <%inherit file="base.html"/>
<%def name="headIncludes()"> <%def name="headIncludes()">
<link rel="stylesheet" href="interfaces/default/css/dataTables.bootstrap.css"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.css">
<link rel="stylesheet" href="interfaces/default/css/dataTables.colVis.css"> <link rel="stylesheet" href="${http_root}css/dataTables.colVis.css">
<link rel="stylesheet" href="interfaces/default/css/plexpy-dataTables.css"> <link rel="stylesheet" href="${http_root}css/plexpy-dataTables.css">
</%def> </%def>
<%def name="body()"> <%def name="body()">
@ -69,12 +69,12 @@
</%def> </%def>
<%def name="javascriptIncludes()"> <%def name="javascriptIncludes()">
<script src="interfaces/default/js/jquery.dataTables.min.js"></script> <script src="${http_root}js/jquery.dataTables.min.js"></script>
<script src="interfaces/default/js/dataTables.colVis.js"></script> <script src="${http_root}js/dataTables.colVis.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script>
<script src="interfaces/default/js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script>
<script src="interfaces/default/js/moment-with-locale.js"></script> <script src="${http_root}js/moment-with-locale.js"></script>
<script src="interfaces/default/js/tables/users.js"></script> <script src="${http_root}js/tables/users.js"></script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
users_list_table_options.ajax = { users_list_table_options.ajax = {

View file

@ -12,14 +12,14 @@ from plexpy import common
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content=""> <meta name="description" content="">
<meta name="author" content=""> <meta name="author" content="">
<link href="interfaces/default/css/bootstrap3/bootstrap.css" rel="stylesheet"> <link href="${http_root}css/bootstrap3/bootstrap.css" rel="stylesheet">
<link href="interfaces/default/css/bootstrap-wizard.css" rel="stylesheet"> <link href="${http_root}css/bootstrap-wizard.css" rel="stylesheet">
<link href="interfaces/default/css/plexpy.css" rel="stylesheet"> <link href="${http_root}css/plexpy.css" rel="stylesheet">
<link href="interfaces/default/css/selectize.bootstrap3.css" rel="stylesheet"> <link href="${http_root}css/selectize.bootstrap3.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css"> <link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css">
<link href="interfaces/default/css/font-awesome.min.css" rel="stylesheet"> <link href="${http_root}css/font-awesome.min.css" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="interfaces/default/images/favicon.ico"/> <link rel="icon" type="image/x-icon" href="${http_root}images/favicon.ico"/>
<link rel="shortcut icon" href="interfaces/default/images/favicon.ico"> <link rel="shortcut icon" href="${http_root}images/favicon.ico">
</head> </head>
<body> <body>
@ -28,7 +28,7 @@ from plexpy import common
<div class="wizard" id="some-wizard" data-title="PlexPy Setup Wizard"> <div class="wizard" id="some-wizard" data-title="PlexPy Setup Wizard">
<div class="wizard-card" data-cardname="card1"> <div class="wizard-card" data-cardname="card1">
<div style="float: right;"> <div style="float: right;">
<img src="interfaces/default/images/logo-plexpy.png"/> <img src="${http_root}images/logo-plexpy.png"/>
</div> </div>
<h3 style="line-height: 50px;">Welcome!</h3> <h3 style="line-height: 50px;">Welcome!</h3>
<br/> <br/>
@ -191,11 +191,11 @@ from plexpy import common
</div> </div>
</div> </div>
<script src="interfaces/default/js/jquery-2.1.4.min.js"></script> <script src="${http_root}js/jquery-2.1.4.min.js"></script>
<script src="interfaces/default/js/bootstrap3/bootstrap.min.js"></script> <script src="${http_root}js/bootstrap3/bootstrap.min.js"></script>
<script src="interfaces/default/js/selectize.min.js"></script> <script src="${http_root}js/selectize.min.js"></script>
<script src="interfaces/default/js/script.js"></script> <script src="${http_root}js/script.js"></script>
<script src="interfaces/default/js/bootstrap-wizard.min.js"></script> <script src="${http_root}js/bootstrap-wizard.min.js"></script>
<script> <script>
$(document).ready(function() { $(document).ready(function() {

View file

@ -74,6 +74,8 @@ UMASK = None
POLLING_FAILOVER = False POLLING_FAILOVER = False
HTTP_ROOT = None
DEV = False DEV = False

158
plexpy/webauth.py Normal file
View file

@ -0,0 +1,158 @@
# This file is part of PlexPy.
#
# PlexPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PlexPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
# http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
# Form based authentication for CherryPy. Requires the
# Session tool to be loaded.
import cherrypy
from cgi import escape
import plexpy
from plexpy import logger
SESSION_KEY = '_cp_username'
def check_credentials(username, password):
"""Verifies credentials for username and password.
Returns None on success or a string describing the error on failure"""
# Adapt to your needs
if username == plexpy.CONFIG.HTTP_USERNAME and password == plexpy.CONFIG.HTTP_PASSWORD:
return None
else:
return u"Incorrect username or password."
# An example implementation which uses an ORM could be:
# u = User.get(username)
# if u is None:
# return u"Username %s is unknown to me." % username
# if u.password != md5.new(password).hexdigest():
# return u"Incorrect password"
def check_auth(*args, **kwargs):
"""A tool that looks in config for 'auth.require'. If found and it
is not None, a login is required and the entry is evaluated as a list of
conditions that the user must fulfill"""
conditions = cherrypy.request.config.get('auth.require', None)
if conditions is not None:
username = cherrypy.session.get(SESSION_KEY)
if username:
cherrypy.request.login = username
for condition in conditions:
# A condition is just a callable that returns true or false
if not condition():
raise cherrypy.HTTPRedirect("auth/login")
else:
raise cherrypy.HTTPRedirect("auth/login")
def require(*conditions):
"""A decorator that appends conditions to the auth.require config
variable."""
def decorate(f):
if not hasattr(f, '_cp_config'):
f._cp_config = dict()
if 'auth.require' not in f._cp_config:
f._cp_config['auth.require'] = []
f._cp_config['auth.require'].extend(conditions)
return f
return decorate
# Conditions are callables that return True
# if the user fulfills the conditions they define, False otherwise
#
# They can access the current username as cherrypy.request.login
#
# Define those at will however suits the application.
def member_of(groupname):
def check():
# replace with actual check if <username> is in <groupname>
return cherrypy.request.login == plexpy.CONFIG.HTTP_USERNAME and groupname == 'admin'
return check
def name_is(reqd_username):
return lambda: reqd_username == cherrypy.request.login
# These might be handy
def any_of(*conditions):
"""Returns True if any of the conditions match"""
def check():
for c in conditions:
if c():
return True
return False
return check
# By default all conditions are required, but this might still be
# needed if you want to use it inside of an any_of(...) condition
def all_of(*conditions):
"""Returns True if all of the conditions match"""
def check():
for c in conditions:
if not c():
return False
return True
return check
# Controller to provide login and logout actions
class AuthController(object):
def on_login(self, username):
"""Called on successful login"""
logger.debug(u"User '%s' logged into PlexPy." % username)
def on_logout(self, username):
"""Called on logout"""
logger.debug(u"User '%s' logged out of PlexPy." % username)
def get_loginform(self, username="", msg=""):
from plexpy.webserve import serve_template
username = escape(username, True)
return serve_template(templatename="login.html", title="Welcome", username=username, msg=msg)
@cherrypy.expose
def login(self, username=None, password=None, remember_me=0):
if username is None or password is None:
return self.get_loginform()
error_msg = check_credentials(username, password)
if error_msg:
logger.debug(u"Invalid login attempt from '%s'." % username)
return self.get_loginform(username, error_msg)
else:
cherrypy.session.regenerate()
cherrypy.session[SESSION_KEY] = cherrypy.request.login = username
self.on_login(username)
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT or "/")
@cherrypy.expose
def logout(self):
sess = cherrypy.session
username = sess.get(SESSION_KEY, None)
sess[SESSION_KEY] = None
if username:
cherrypy.request.login = None
self.on_logout(username)
raise cherrypy.HTTPRedirect("login")

View file

@ -16,6 +16,7 @@
from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, \ from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, \
datafactory, graphs, users, libraries, database, web_socket datafactory, graphs, users, libraries, database, web_socket
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates
from plexpy.webauth import AuthController, require, member_of, name_is
from mako.lookup import TemplateLookup from mako.lookup import TemplateLookup
from mako import exceptions from mako import exceptions
@ -49,17 +50,20 @@ def serve_template(templatename, **kwargs):
try: try:
template = _hplookup.get_template(templatename) template = _hplookup.get_template(templatename)
return template.render(server_name=server_name, **kwargs) return template.render(server_name=server_name, http_root=plexpy.HTTP_ROOT, **kwargs)
except: except:
return exceptions.html_error_template().render() return exceptions.html_error_template().render()
class WebInterface(object): class WebInterface(object):
auth = AuthController()
def __init__(self): def __init__(self):
self.interface_dir = os.path.join(str(plexpy.PROG_DIR), 'data/') self.interface_dir = os.path.join(str(plexpy.PROG_DIR), 'data/')
@cherrypy.expose @cherrypy.expose
@require()
def index(self): def index(self):
if plexpy.CONFIG.FIRST_RUN_COMPLETE: if plexpy.CONFIG.FIRST_RUN_COMPLETE:
raise cherrypy.HTTPRedirect("home") raise cherrypy.HTTPRedirect("home")
@ -142,6 +146,7 @@ class WebInterface(object):
##### Home ##### ##### Home #####
@cherrypy.expose @cherrypy.expose
@require()
def home(self): def home(self):
config = { config = {
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH, "home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
@ -270,6 +275,7 @@ class WebInterface(object):
##### Libraries ##### ##### Libraries #####
@cherrypy.expose @cherrypy.expose
@require()
def libraries(self): def libraries(self):
config = { config = {
"update_section_ids": plexpy.CONFIG.UPDATE_SECTION_IDS "update_section_ids": plexpy.CONFIG.UPDATE_SECTION_IDS
@ -578,6 +584,7 @@ class WebInterface(object):
##### Users ##### ##### Users #####
@cherrypy.expose @cherrypy.expose
@require()
def users(self): def users(self):
return serve_template(templatename="users.html", title="Users") return serve_template(templatename="users.html", title="Users")
@ -749,6 +756,7 @@ class WebInterface(object):
##### History ##### ##### History #####
@cherrypy.expose @cherrypy.expose
@require()
def history(self): def history(self):
return serve_template(templatename="history.html", title="History") return serve_template(templatename="history.html", title="History")
@ -837,6 +845,7 @@ class WebInterface(object):
##### Graphs ##### ##### Graphs #####
@cherrypy.expose @cherrypy.expose
@require()
def graphs(self): def graphs(self):
config = { config = {
@ -1024,6 +1033,7 @@ class WebInterface(object):
##### Sync ##### ##### Sync #####
@cherrypy.expose @cherrypy.expose
@require()
def sync(self): def sync(self):
return serve_template(templatename="sync.html", title="Synced Items") return serve_template(templatename="sync.html", title="Synced Items")
@ -1049,6 +1059,7 @@ class WebInterface(object):
##### Logs ##### ##### Logs #####
@cherrypy.expose @cherrypy.expose
@require()
def logs(self): def logs(self):
return serve_template(templatename="logs.html", title="Log", lineList=plexpy.LOG_LIST) return serve_template(templatename="logs.html", title="Log", lineList=plexpy.LOG_LIST)
@ -1167,6 +1178,7 @@ class WebInterface(object):
##### Settings ##### ##### Settings #####
@cherrypy.expose @cherrypy.expose
@require()
def settings(self): def settings(self):
interface_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/') interface_dir = os.path.join(plexpy.PROG_DIR, 'data/interfaces/')
interface_list = [name for name in os.listdir(interface_dir) if interface_list = [name for name in os.listdir(interface_dir) if

View file

@ -17,7 +17,7 @@ import os
import sys import sys
import cherrypy import cherrypy
from plexpy import logger from plexpy import logger, webauth
import plexpy import plexpy
from plexpy.helpers import create_https_certificates from plexpy.helpers import create_https_certificates
from plexpy.webserve import WebInterface from plexpy.webserve import WebInterface
@ -50,7 +50,7 @@ def initialize(options):
'server.thread_pool': 10, 'server.thread_pool': 10,
'tools.encode.on': True, 'tools.encode.on': True,
'tools.encode.encoding': 'utf-8', 'tools.encode.encoding': 'utf-8',
'tools.decode.on': True, 'tools.decode.on': True
} }
if enable_https: if enable_https:
@ -64,8 +64,17 @@ def initialize(options):
options_dict['environment'] = "test_suite" options_dict['environment'] = "test_suite"
options_dict['engine.autoreload.on'] = True options_dict['engine.autoreload.on'] = True
logger.info("Starting PlexPy web server on %s://%s:%d/", protocol, if options['http_password']:
options['http_host'], options['http_port']) logger.info("Web server authentication is enabled, username is '%s'", options['http_username'])
options_dict['tools.sessions.on'] = True
options_dict['tools.auth.on'] = True
cherrypy.tools.auth = cherrypy.Tool('before_handler', webauth.check_auth)
if not options['http_root'] or options['http_root'] == '/':
plexpy.HTTP_ROOT = options['http_root'] = '/'
else:
plexpy.HTTP_ROOT = options['http_root'] = '/' + options['http_root'].strip('/') + '/'
cherrypy.config.update(options_dict) cherrypy.config.update(options_dict)
conf = { conf = {
@ -83,15 +92,27 @@ def initialize(options):
}, },
'/images': { '/images': {
'tools.staticdir.on': True, 'tools.staticdir.on': True,
'tools.staticdir.dir': "images" 'tools.staticdir.dir': "interfaces/default/images"
}, },
'/css': { '/css': {
'tools.staticdir.on': True, 'tools.staticdir.on': True,
'tools.staticdir.dir': "css" 'tools.staticdir.dir': "interfaces/default/css"
},
'/fonts': {
'tools.staticdir.on': True,
'tools.staticdir.dir': "interfaces/default/fonts"
}, },
'/js': { '/js': {
'tools.staticdir.on': True, 'tools.staticdir.on': True,
'tools.staticdir.dir': "js" 'tools.staticdir.dir': "interfaces/default/js"
},
'/json': {
'tools.staticdir.on': True,
'tools.staticdir.dir': "interfaces/default/json"
},
'/xml': {
'tools.staticdir.on': True,
'tools.staticdir.dir': "interfaces/default/xml"
}, },
'/cache': { '/cache': {
'tools.staticdir.on': True, 'tools.staticdir.on': True,
@ -100,27 +121,19 @@ def initialize(options):
'/favicon.ico': { '/favicon.ico': {
'tools.staticfile.on': True, 'tools.staticfile.on': True,
'tools.staticfile.filename': os.path.abspath(os.path.join(plexpy.PROG_DIR, 'data/interfaces/default/images/favicon.ico')) 'tools.staticfile.filename': os.path.abspath(os.path.join(plexpy.PROG_DIR, 'data/interfaces/default/images/favicon.ico'))
} },
} }
if options['http_password']: if options['http_password']:
logger.info("Web server authentication is enabled, username is '%s'", options['http_username']) conf['/api'] = {'tools.auth.on': False}
conf['/'].update({
'tools.auth_basic.on': True,
'tools.auth_basic.realm': 'PlexPy web server',
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict({
options['http_username']: options['http_password']
})
})
conf['/api'] = {'tools.auth_basic.on': False}
# Prevent time-outs # Prevent time-outs
cherrypy.engine.timeout_monitor.unsubscribe() cherrypy.engine.timeout_monitor.unsubscribe()
cherrypy.tree.mount(WebInterface(), str(options['http_root']), config=conf) cherrypy.tree.mount(WebInterface(), options['http_root'], config=conf)
try: try:
logger.info("Starting PlexPy web server on %s://%s:%d%s", protocol,
options['http_host'], options['http_port'], options['http_root'])
cherrypy.process.servers.check_port(str(options['http_host']), options['http_port']) cherrypy.process.servers.check_port(str(options['http_host']), options['http_port'])
if not plexpy.DEV: if not plexpy.DEV:
cherrypy.server.start() cherrypy.server.start()