Compare commits

..

24 Commits

Author SHA1 Message Date
JonnyWong16
e029f329eb Merge branch 'dev' 2016-09-18 22:11:29 -07:00
JonnyWong16
47de9a752c v1.4.12 2016-09-18 22:11:12 -07:00
JonnyWong16
51c9aa2887 Update FreeBSD service script 2016-09-18 21:58:44 -07:00
JonnyWong16
82499a53d4 Merge pull request #844 from spolyack/pid-fix
Attempt to verify the PID in an existing PID file before giving up.
2016-09-18 21:33:11 -07:00
JonnyWong16
df15302f2c Merge pull request #842 from XusBadia/patch-2
Fix card width on the homepage for iPhone 6/7 Plus
2016-09-18 21:11:24 -07:00
JonnyWong16
039b51262d Update readme 2016-09-18 21:06:44 -07:00
spolyack
465add46d4 Attempt to verify the PID in an existing PID file before giving up.
If the PID doesn't map to a running process, then we can simply ignore the presence of the PID file and overwrite it with the current (new) PID later.
2016-09-18 11:36:09 -04:00
Xus Badia
bce965b402 Fix for iPhone 6/7 Plus
Changed the max-device-width from 400px to 450px so it adjusts to the iPhone 6/7 Plus screen and doesn't leave a gap on the right of the screen.
2016-09-18 07:41:58 +02:00
JonnyWong16
95ce293169 Add FAQ link to dropdown 2016-09-17 15:15:33 -07:00
JonnyWong16
5d604c2cad Make sure all endpoints have kwargs 2016-09-17 14:45:58 -07:00
JonnyWong16
ed2d3ca277 Update git user 2016-09-17 14:40:31 -07:00
JonnyWong16
0478f40d02 Square cover for music home stats 2016-09-17 14:39:58 -07:00
JonnyWong16
a4be73da3b Remove divider 2016-09-17 14:39:38 -07:00
JonnyWong16
762192518f Override MacOSX pms platform 2016-09-03 13:57:17 -07:00
JonnyWong16
fa51df192d Cleanup settings modal text 2016-09-02 13:18:06 -07:00
JonnyWong16
1a5cc02097 Update with support links 2016-09-02 13:01:12 -07:00
JonnyWong16
a07f54ca33 Merge branch 'dev' 2016-09-02 11:51:51 -07:00
JonnyWong16
6a8cbe92a9 v1.4.11 2016-09-02 11:51:26 -07:00
JonnyWong16
16d9376ec9 Add /r/Plex Discord to Readme 2016-09-02 11:48:36 -07:00
JonnyWong16
4356f5c72a Remove unnecessary argument 2016-09-02 10:54:20 -07:00
JonnyWong16
076dc94292 A bit of script notifier cleanup 2016-08-26 19:16:48 -07:00
JonnyWong16
fbc527010a Fix notifications not sending for Local user
Fixes #807
2016-08-26 18:48:09 -07:00
JonnyWong16
5b4a22276d Fix args in the correct order for datatables queries
Fixes #813
2016-08-26 18:14:26 -07:00
JonnyWong16
b55a563fce Fix PlexWatch and Plexivity import 2016-08-26 17:43:10 -07:00
21 changed files with 342 additions and 244 deletions

View File

@@ -1,5 +1,23 @@
# Changelog # Changelog
## v1.4.12 (2016-09-18)
* Fix: PMS update check not working for MacOSX.
* Fix: Square covers for music stats on homepage.
* Fix: Card width on the homepage for iPhone 6/7 Plus. (Thanks @XusBadia)
* Fix: Check for running PID when starting PlexPy. (Thanks @spolyack)
* Fix: FreeBSD service script not stopping PlexPy properly.
* Fix: Some web UI cleanup.
* Change: GitHub repostitory moved.
## v1.4.11 (2016-09-02)
* Fix: PlexWatch and Plexivity import errors.
* Fix: Searching in history datatables.
* Fix: Notifications not sending for Local user.
## v1.4.10 (2016-08-15) ## v1.4.10 (2016-08-15)
* Fix: Missing python ipaddress module preventing PlexPy from starting. * Fix: Missing python ipaddress module preventing PlexPy from starting.

View File

@@ -9,14 +9,14 @@ In case you read this because you are posting an issue, please take a minute and
- Turning your device off and on again. - Turning your device off and on again.
- Analyzing your logs, you just might find the solution yourself! - Analyzing your logs, you just might find the solution yourself!
- Using the **search** function to see if this issue has already been reported/solved. - Using the **search** function to see if this issue has already been reported/solved.
- Checking the [Wiki](https://github.com/drzoidberg33/plexpy/wiki) for - Checking the [Wiki](https://github.com/JonnyWong16/plexpy/wiki) for
[ [Installation] ](https://github.com/drzoidberg33/plexpy/wiki/Installation) and [ [Installation] ](https://github.com/JonnyWong16/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)). [ [FAQs] ](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/drzoidberg33/plexpy) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue. - For basic questions try asking on [Gitter](https://gitter.im/plexpy/general) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue.
##### If nothing has worked: ##### If nothing has worked:
1. Open a new issue on the GitHub [issue tracker](http://github.com/drzoidberg33/plexpy/issues). 1. Open a new issue on the GitHub [issue tracker](http://github.com/JonnyWong16/plexpy/issues).
2. Provide a clear title to easily help identify your problem. 2. Provide a clear title to easily help identify your problem.
3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks). 3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks).
4. Make sure you provide the following information: 4. Make sure you provide the following information:

View File

@@ -122,6 +122,19 @@ def main():
# If the pidfile already exists, plexpy may still be running, so # If the pidfile already exists, plexpy may still be running, so
# exit # exit
if os.path.exists(plexpy.PIDFILE): if os.path.exists(plexpy.PIDFILE):
try:
with open(plexpy.PIDFILE, 'r') as fp:
pid = int(fp.read())
os.kill(pid, 0)
except IOError as e:
raise SystemExit("Unable to read PID file: %s", e)
except OSError:
logger.warn("PID file '%s' already exists, but PID %d is " \
"not running. Ignoring PID file." %
(plexpy.PIDFILE, pid))
else:
# The pidfile exists and points to a live PID. plexpy may
# still be running, so exit.
raise SystemExit("PID file '%s' already exists. Exiting." % raise SystemExit("PID file '%s' already exists. Exiting." %
plexpy.PIDFILE) plexpy.PIDFILE)

View File

@@ -1,14 +1,14 @@
# PlexPy # PlexPy
[![Join the chat at https://gitter.im/drzoidberg33/plexpy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/drzoidberg33/plexpy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/plexpy/general](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/plexpy/general?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv). A python based web application for monitoring, analytics and notifications for [Plex Media Server](https://plex.tv).
This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb). This project is based on code from [Headphones](https://github.com/rembo10/headphones) and [PlexWatchWeb](https://github.com/ecleese/plexWatchWeb).
* [Plex forum thread](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) * [Plex forum thread](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
* [Gitter chat](https://gitter.im/drzoidberg33/plexpy) * [Gitter chat](https://gitter.im/plexpy/general)
* [Discord server](https://discord.gg/011TFFWSuNFI02EKr) | [PlexPy Discord server](https://discord.gg/36ggawe) * [/r/Plex Discord server](https://discord.gg/011TFFWSuNFI02EKr) | [PlexPy Discord server](https://discord.gg/36ggawe)
## Features ## Features
@@ -35,8 +35,8 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
## Installation and Support ## Installation and Support
* [Installation Guides](https://github.com/drzoidberg33/plexpy/wiki/Installation) shows you how to install PlexPy. * [Installation Guides](https://github.com/JonnyWong16/plexpy/wiki/Installation) shows you how to install PlexPy.
* [FAQs](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)) in the wiki can help you with common problems. * [FAQs](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)) in the wiki can help you with common problems.
**Support** the project by implementing new features, solving support tickets and provide bug fixes. **Support** the project by implementing new features, solving support tickets and provide bug fixes.
@@ -48,14 +48,14 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
- Turning your device off and on again. - Turning your device off and on again.
- Analyzing your logs, you just might find the solution yourself! - Analyzing your logs, you just might find the solution yourself!
- Using the **search** function to see if this issue has already been reported/solved. - Using the **search** function to see if this issue has already been reported/solved.
- Checking the [Wiki](https://github.com/drzoidberg33/plexpy/wiki) for - Checking the [Wiki](https://github.com/JonnyWong16/plexpy/wiki) for
[ [Installation] ](https://github.com/drzoidberg33/plexpy/wiki/Installation) and [ [Installation] ](https://github.com/JonnyWong16/plexpy/wiki/Installation) and
[ [FAQs] ](https://github.com/drzoidberg33/plexpy/wiki/Frequently-Asked-Questions-(FAQ)). [ [FAQs] ](https://github.com/JonnyWong16/plexpy/wiki/Frequently-Asked-Questions-(FAQ)).
- For basic questions try asking on [Gitter](https://gitter.im/drzoidberg33/plexpy) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue. - For basic questions try asking on [Gitter](https://gitter.im/plexpy/general) or the [Plex Forums](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) first before opening an issue.
##### If nothing has worked: ##### If nothing has worked:
1. Open a new issue on the GitHub [issue tracker](http://github.com/drzoidberg33/plexpy/issues). 1. Open a new issue on the GitHub [issue tracker](http://github.com/JonnyWong16/plexpy/issues).
2. Provide a clear title to easily help identify your problem. 2. Provide a clear title to easily help identify your problem.
3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks). 3. Use proper [markdown syntax](https://help.github.com/articles/github-flavored-markdown) to structure your post (i.e. code/log in code blocks).
4. Make sure you provide the following information: 4. Make sure you provide the following information:

View File

@@ -220,6 +220,8 @@
<li><a href="settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li> <li><a href="settings"><i class="fa fa-fw fa-cogs"></i> Settings</a></li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
<li><a href="logs"><i class="fa fa-fw fa-list-alt"></i> View Logs</a></li> <li><a href="logs"><i class="fa fa-fw fa-list-alt"></i> View Logs</a></li>
<li><a href="${anon_url('https://github.com/%s/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank"><i class="fa fa-fw fa-question-circle"></i> FAQ</a></li>
<li><a href="settings?support=true"><i class="fa fa-fw fa-comment"></i> Support</a></li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
<li><a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DG783BMSCU3V4')}" target="_blank"><i class="fa fa-fw fa-paypal"></i> Paypal</a></li> <li><a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DG783BMSCU3V4')}" target="_blank"><i class="fa fa-fw fa-paypal"></i> Paypal</a></li>
<li><a href="${anon_url('http://swiftpanda16.tip.me/')}" target="_blank"><i class="fa fa-fw fa-btc"></i> Bitcoin</a></li> <li><a href="${anon_url('http://swiftpanda16.tip.me/')}" target="_blank"><i class="fa fa-fw fa-btc"></i> Bitcoin</a></li>

View File

@@ -22,11 +22,11 @@ DOCUMENTATION :: END
% if plexpy.CURRENT_VERSION: % if plexpy.CURRENT_VERSION:
<tr> <tr>
<td>Git Branch:</td> <td>Git Branch:</td>
<td><a class="no-highlight" href="${anon_url('https://github.com/drzoidberg33/plexpy/tree/%s' % plexpy.CONFIG.GIT_BRANCH)}">${plexpy.CONFIG.GIT_BRANCH}</a></td> <td><a class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/tree/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_BRANCH))}">${plexpy.CONFIG.GIT_BRANCH}</a></td>
</tr> </tr>
<tr> <tr>
<td>Git Commit Hash:</td> <td>Git Commit Hash:</td>
<td><a class="no-highlight" href="${anon_url('https://github.com/drzoidberg33/plexpy/commit/%s' % plexpy.CURRENT_VERSION)}">${plexpy.CURRENT_VERSION}</a></td> <td><a class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/commit/%s' % (plexpy.CONFIG.GIT_USER, plexpy.CONFIG.GIT_BRANCH))}">${plexpy.CURRENT_VERSION}</a></td>
</tr> </tr>
% endif % endif
<tr> <tr>
@@ -72,32 +72,67 @@ DOCUMENTATION :: END
<td>${sys.version}</td> <td>${sys.version}</td>
</tr> </tr>
<tr> <tr>
<td class="top-line">Plex Forums:</td> <td class="top-line">Resources:</td>
<td class="top-line"><a class="no-highlight" href="${anon_url('https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program')}" target="_blank">https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program</a></td> <td class="top-line">
<a id="source-link" class="no-highlight" href="${anon_url('https://github.com/%s/plexpy' % plexpy.CONFIG.GIT_USER)}" target="_blank">GitHub Source</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/%s/plexpy/issues' % plexpy.CONFIG.GIT_USER)}" data-id="issue">GitHub Issues</a> |
<a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/%s/plexpy' % plexpy.CONFIG.GIT_USER)}" data-id="feature request">FeatHub Feature Requests</a> |
<a class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/wiki' % plexpy.CONFIG.GIT_USER)}" target="_blank">PlexPy Wiki</a> |
<a id="faq-source-link" class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/wiki/Frequently-Asked-Questions-(FAQ)' % plexpy.CONFIG.GIT_USER)}" target="_blank">PlexPy FAQ</a>
</td>
</tr> </tr>
<tr> <tr>
<td>Source:</td> <td>Support:</td>
<td><a id="source-link" class="no-highlight" href="${anon_url('https://github.com/drzoidberg33/plexpy')}" target="_blank">https://github.com/drzoidberg33/plexpy</a></td> <td>
</tr> <a class="no-highlight support-modal-link" href="${anon_url('https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program')}" target="_blank">Plex Forums</a> |
<tr> <a class="no-highlight support-modal-link" href="${anon_url('https://gitter.im/plexpy/general')}" target="_blank">PlexPy Gitter Chat</a> |
<td>Wiki:</td> <a id="best-support-link" class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/011TFFWSuNFI02EKr')}" target="_blank">/r/Plex Discord Server</a> |
<td><a class="no-highlight" href="${anon_url('https://github.com/drzoidberg33/plexpy/wiki')}" target="_blank">https://github.com/drzoidberg33/plexpy/wiki</a></td> <a class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/36ggawe')}" target="_blank">PlexPy Discord Server</a>
</tr> </td>
<tr>
<td>Issues:</td>
<td><a class="no-highlight guidelines-modal-link" href="${anon_url('https://github.com/drzoidberg33/plexpy/issues')}" data-id="issue">https://github.com/drzoidberg33/plexpy/issues</a></td>
</tr>
<tr>
<td>Feature Requests:</td>
<td><a class="no-highlight guidelines-modal-link" href="${anon_url('http://feathub.com/drzoidberg33/plexpy')}" data-id="feature request">http://feathub.com/drzoidberg33/plexpy</a></td>
</tr>
<tr>
<td>Gitter Chat:</td>
<td><a class="no-highlight" href="${anon_url('https://gitter.im/drzoidberg33/plexpy')}" target="_blank">https://gitter.im/drzoidberg33/plexpy</a></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div id="guidelines-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="guidelines-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Guidelines</h4>
</div>
<div class="modal-body">
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
<strong>Please read the <a href="#" target="_blank" id="guidelines-link">guidelines</a> in the README document <br />before submitting a new <span id="guidelines-type"></span>!</strong>
<br /><br />
Your post may be removed for failure to follow the guidelines.
</div>
</div>
<div class="modal-footer">
<a href="#" target="_blank" id="guidelines-continue" class="btn btn-bright">Continue</a>
</div>
</div>
</div>
</div>
<div id="support-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="support-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Support</h4>
</div>
<div class="modal-body">
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
<strong>Please read the <a href="#" target="_blank" id="faq-link">FAQ</a> before asking for help!</strong>
</div>
</div>
<div class="modal-footer">
<a href="#" target="_blank" id="support-continue" class="btn btn-bright">Continue</a>
</div>
</div>
</div>
</div>
<script> <script>
$(document).ready(function () { $(document).ready(function () {
$("#install_geoip_db, #reinstall_geoip_db").click(function () { $("#install_geoip_db, #reinstall_geoip_db").click(function () {
@@ -125,5 +160,13 @@ DOCUMENTATION :: END
$('#guidelines-modal').modal('hide'); $('#guidelines-modal').modal('hide');
}); });
}); });
$('.support-modal-link').on('click', function (e) {
e.preventDefault();
$('#faq-link').attr('href', $('#faq-source-link').attr('href'));
$('#support-modal').modal();
$('#support-continue').attr('href', $(this).attr('href')).on('click', function () {
$('#support-modal').modal('hide');
});
});
}); });
</script> </script>

View File

@@ -1929,6 +1929,12 @@ a .library-user-instance-box:hover {
position: absolute; position: absolute;
overflow: hidden; overflow: hidden;
} }
.home-platforms-instance-cover {
margin-left: 0px;
position: absolute;
top: 20px;
overflow: hidden;
}
.home-platforms-instance-poster .home-platforms-poster-face { .home-platforms-instance-poster .home-platforms-poster-face {
background-position: center; background-position: center;
background-size: cover; background-size: cover;
@@ -1938,6 +1944,15 @@ a .library-user-instance-box:hover {
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
} }
.home-platforms-instance-cover .home-platforms-cover-face {
background-position: center;
background-size: cover;
height: 80px;
width: 80px;
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
}
.home-platforms-instance-poster .home-platforms-library-thumb { .home-platforms-instance-poster .home-platforms-library-thumb {
background-position: center; background-position: center;
background-size: cover; background-size: cover;
@@ -2087,6 +2102,12 @@ a .library-user-instance-box:hover {
left: 20px; left: 20px;
overflow: hidden; overflow: hidden;
} }
.home-platforms-instance-list-cover {
position: absolute;
top: 10px;
left: 20px;
overflow: hidden;
}
.home-platforms-instance-list-poster .home-platforms-list-poster-face { .home-platforms-instance-list-poster .home-platforms-list-poster-face {
background-position: center; background-position: center;
background-size: cover; background-size: cover;
@@ -2096,6 +2117,15 @@ a .library-user-instance-box:hover {
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); -moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1); box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
} }
.home-platforms-instance-list-cover .home-platforms-list-cover-face {
background-position: center;
background-size: cover;
height: 40px;
width: 40px;
-webkit-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
-moz-box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
box-shadow: 0 0 4px rgba(0,0,0,.3),inset 0 0 0 1px rgba(255,255,255,.1);
}
.home-platforms-instance-list-box { .home-platforms-instance-list-box {
background-position: center; background-position: center;
background-size: cover; background-size: cover;
@@ -2154,7 +2184,9 @@ a .home-platforms-instance-oval:hover,
a .home-platforms-instance-list-box:hover, a .home-platforms-instance-list-box:hover,
a .home-platforms-instance-list-oval:hover, a .home-platforms-instance-list-oval:hover,
a .home-platforms-poster-face:hover, a .home-platforms-poster-face:hover,
a .home-platforms-list-poster-face:hover a .home-platforms-cover-face:hover,
a .home-platforms-list-poster-face:hover,
a .home-platforms-list-cover-face:hover
{ {
-webkit-box-shadow: inset 0 0 0 2px #e9a049; -webkit-box-shadow: inset 0 0 0 2px #e9a049;
-moz-box-shadow: inset 0 0 0 2px #e9a049; -moz-box-shadow: inset 0 0 0 2px #e9a049;
@@ -2630,7 +2662,7 @@ a .home-platforms-list-poster-face:hover
@media only screen @media only screen
and (min-device-width: 300px) and (min-device-width: 300px)
and (max-device-width: 400px) { and (max-device-width: 450px) {
.home-platforms-instance { .home-platforms-instance {
width: calc(100% - 20px); width: calc(100% - 20px);
} }

View File

@@ -509,21 +509,21 @@ DOCUMENTATION :: END
% if top_stat['rows'][0]['rating_key']: % if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}"> <a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['grandparent_thumb']: % if top_stat['rows'][0]['grandparent_thumb']:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div> <div class="home-platforms-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin': % if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span> <span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif % endif
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
</a> </a>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
% if len(top_stat['rows']) > 1: % if len(top_stat['rows']) > 1:
@@ -558,21 +558,21 @@ DOCUMENTATION :: END
% if top_stat['rows'][loop.index]['rating_key']: % if top_stat['rows'][loop.index]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}"> <a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']: % if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin': % if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span> <span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif % endif
</div> </div>
% else: % else:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
</a> </a>
% else: % else:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
<div class="home-platforms-instance-list-number"> <div class="home-platforms-instance-list-number">
@@ -611,21 +611,21 @@ DOCUMENTATION :: END
% if top_stat['rows'][0]['rating_key']: % if top_stat['rows'][0]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}"> <a href="info?rating_key=${top_stat['rows'][0]['rating_key']}" title="${top_stat['rows'][0]['title']}">
% if top_stat['rows'][0]['grandparent_thumb'] != '': % if top_stat['rows'][0]['grandparent_thumb'] != '':
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div> <div class="home-platforms-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][0]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin': % if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span> <span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif % endif
</div> </div>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
</a> </a>
% else: % else:
<div class="home-platforms-instance-poster"> <div class="home-platforms-instance-cover">
<div class="home-platforms-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
% if len(top_stat['rows']) > 1: % if len(top_stat['rows']) > 1:
@@ -656,21 +656,21 @@ DOCUMENTATION :: END
% if top_stat['rows'][loop.index]['rating_key']: % if top_stat['rows'][loop.index]['rating_key']:
<a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}"> <a href="info?rating_key=${top_stat['rows'][loop.index]['rating_key']}" title="${top_stat['rows'][loop.index]['title']}">
% if top_stat['rows'][loop.index]['grandparent_thumb']: % if top_stat['rows'][loop.index]['grandparent_thumb']:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=poster);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(pms_image_proxy?img=${top_stat['rows'][loop.index]['grandparent_thumb']}&width=300&height=300&fallback=cover);"></div>
% if _session['user_group'] == 'admin': % if _session['user_group'] == 'admin':
<span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span> <span class="overlay-refresh-image" title="Refresh image"><i class="fa fa-refresh refresh_pms_image"></i></span>
% endif % endif
</div> </div>
% else: % else:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
</a> </a>
% else: % else:
<div class="home-platforms-instance-list-poster"> <div class="home-platforms-instance-list-cover">
<div class="home-platforms-list-poster-face" style="background-image: url(${http_root}images/poster.png);"></div> <div class="home-platforms-list-cover-face" style="background-image: url(${http_root}images/cover.png);"></div>
</div> </div>
% endif % endif
<div class="home-platforms-instance-list-number"> <div class="home-platforms-instance-list-number">

View File

@@ -1264,7 +1264,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Year Year
</th> </th>
</tr> </tr>
@@ -1285,7 +1285,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Month Month
</th> </th>
</tr> </tr>
@@ -1316,7 +1316,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Day of the Year Day of the Year
</th> </th>
</tr> </tr>
@@ -1337,7 +1337,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Day of the Month Day of the Month
</th> </th>
</tr> </tr>
@@ -1363,7 +1363,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Day of the Week Day of the Week
</th> </th>
</tr> </tr>
@@ -1389,7 +1389,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Hour Hour
</th> </th>
</tr> </tr>
@@ -1420,7 +1420,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Minute Minute
</th> </th>
</tr> </tr>
@@ -1441,7 +1441,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Second Second
</th> </th>
</tr> </tr>
@@ -1462,7 +1462,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
AM / PM AM / PM
</th> </th>
</tr> </tr>
@@ -1483,7 +1483,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Timezone Timezone
</th> </th>
</tr> </tr>
@@ -1504,7 +1504,7 @@
<table class="notification-params time-options"> <table class="notification-params time-options">
<thead> <thead>
<tr> <tr>
<th> <th colspan="3">
Timestamp Timestamp
</th> </th>
</tr> </tr>
@@ -1574,7 +1574,7 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i <button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i
class="fa fa-remove"></i></button> class="fa fa-remove"></i></button>
<h4 class="modal-title">Notification String Substitutions</h4> <h4 class="modal-title">Notification Parameters</h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div> <div>
@@ -1584,7 +1584,7 @@
<table class="notification-params"> <table class="notification-params">
<thead> <thead>
<tr> <tr>
<th> <th colspan="2">
Global Global
</th> </th>
</tr> </tr>
@@ -1619,7 +1619,7 @@
<table class="notification-params"> <table class="notification-params">
<thead> <thead>
<tr> <tr>
<th> <th colspan="2">
Stream Details Stream Details
</th> </th>
</tr> </tr>
@@ -1778,7 +1778,7 @@
<table class="notification-params"> <table class="notification-params">
<thead> <thead>
<tr> <tr>
<th> <th colspan="2">
Metadata Details Metadata Details
</th> </th>
</tr> </tr>
@@ -1915,12 +1915,12 @@
<tr> <tr>
<td><strong>{imdb_id}</strong></td> <td><strong>{imdb_id}</strong></td>
<td>The IMDB ID for the movie. <span class="small-muted">(e.g. tt2488496)</span> <td>The IMDB ID for the movie. <span class="small-muted">(e.g. tt2488496)</span>
<p class="small-muted">(PMS agent must be Freebase)</p></td> <p class="small-muted">(PMS agent must be Plex Movie)</p></td>
</tr> </tr>
<tr> <tr>
<td><strong>{imdb_url}</strong></td> <td><strong>{imdb_url}</strong></td>
<td>The IMDB URL for the movie. <td>The IMDB URL for the movie.
<p class="small-muted">(PMS agent must be Freebase)</p></td> <p class="small-muted">(PMS agent must be Plex Movie)</p></td>
</tr> </tr>
<tr> <tr>
<td><strong>{thetvdb_id}</strong></td> <td><strong>{thetvdb_id}</strong></td>
@@ -1972,7 +1972,7 @@
<table class="notification-params"> <table class="notification-params">
<thead> <thead>
<tr> <tr>
<th> <th colspan="2">
Plex Update Available Plex Update Available
</th> </th>
</tr> </tr>
@@ -2039,27 +2039,27 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div> <div>
<div class="wellheader">
<h4>Movie Tag <strong>&lt;movie&gt;&lt;/movie&gt;</strong></h4>
</div>
<div> <div>
<p class="help-block">All text inside a <strong>movie</strong> tag will only be sent when the media item being played back is a movie.</p> <h4>Movie Tag</h4>
</div>
<div style="padding-bottom: 10px;">
<p class="help-block">All text inside <span class="inline-pre">&lt;movie&gt;&lt;/movie&gt;</span> tags will only be sent when the media item is a movie.</p>
<p><strong style="color: #fff;">Example:</strong></p> <p><strong style="color: #fff;">Example:</strong></p>
<pre>{user} has started playing {title} &lt;movie&gt;({year})&lt;/movie&gt;</pre> <pre>{user} has started playing {title} &lt;movie&gt;({year})&lt;/movie&gt;</pre>
</div> </div>
<div class="wellheader">
<h4>TV Tag <strong>&lt;tv&gt;&lt;/tv&gt;</strong></h4>
</div>
<div> <div>
<p class="help-block">All text inside a <strong>tv</strong> tag will only be sent when the media item being played back is an episode.</p> <h4>TV Tag</h4>
</div>
<div style="padding-bottom: 10px;">
<p class="help-block">All text inside <span class="inline-pre">&lt;tv&gt;&lt;/tv&gt;</span> tags will only be sent when the media item is an episode.</p>
<p><strong style="color: #fff;">Example:</strong></p> <p><strong style="color: #fff;">Example:</strong></p>
<pre>{user} has started playing {title} &lt;tv&gt;(S{season_num}E{episode_num})&lt;/tv&gt;</pre> <pre>{user} has started playing {title} &lt;tv&gt;(S{season_num}E{episode_num})&lt;/tv&gt;</pre>
</div> </div>
<div class="wellheader"> <div>
<h4>Music Tag <strong>&lt;music&gt;&lt;/music&gt;</strong></h4> <h4>Music Tag</h4>
</div> </div>
<div> <div>
<p class="help-block">All text inside a <strong>music</strong> tag will only be sent when the media item being played back is a music track.</p> <p class="help-block">All text inside <span class="inline-pre">&lt;music&gt;&lt;/music&gt;</span> tags will only be sent when the media item is a track.</p>
<p><strong style="color: #fff;">Example:</strong></p> <p><strong style="color: #fff;">Example:</strong></p>
<pre>{user} has started playing {title} &lt;music&gt;(Track {track_num})&lt;/music&gt;</pre> <pre>{user} has started playing {title} &lt;music&gt;(Track {track_num})&lt;/music&gt;</pre>
</div> </div>
@@ -2101,26 +2101,6 @@
</div> </div>
</div> </div>
</div> </div>
<div id="guidelines-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="guidelines-modal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
<h4 class="modal-title">Guidelines</h4>
</div>
<div class="modal-body">
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
<strong>Please read the <a href="#" target="_blank" id="guidelines-link">guidelines</a> in the README document <br />before submitting a new <span id="guidelines-type"></span>!</strong>
<br /><br />
Your post may be removed for failure to follow the guidelines.
</div>
</div>
<div class="modal-footer">
<a href="#" target="_blank" id="guidelines-continue" class="btn btn-bright">Continue</a>
</div>
</div>
</div>
</div>
</div> </div>
</%def> </%def>
@@ -2141,6 +2121,11 @@
} else if ("${kwargs.get('reinstall_geoip')}" == 'true') { } else if ("${kwargs.get('reinstall_geoip')}" == 'true') {
$('#reinstall_geoip_db').removeClass('no-highlight').css('color','#e9a049'); $('#reinstall_geoip_db').removeClass('no-highlight').css('color','#e9a049');
} }
if ("${kwargs.get('support')}" == 'true') {
$('.support-modal-link').removeClass('no-highlight').css('color','#e9a049');
$('#best-support-link').prepend('<span data-toggle="tooltip" title="Most Active"><i class="fa fa-star"></i></span>&nbsp;')
$('#best-support-link span').tooltip({ container: 'body' });
}
} }
}); });
} }
@@ -2679,7 +2664,7 @@ $(document).ready(function() {
}); });
// Load PMS downloads // Load PMS downloads
function loadUpdateDistros(distro_build) { function loadUpdateDistros() {
var update_params_ajax = $.getJSON('get_server_update_params', function (data) { return data; }); var update_params_ajax = $.getJSON('get_server_update_params', function (data) { return data; });
$.when(update_params_ajax).done(function() { $.when(update_params_ajax).done(function() {

View File

@@ -49,23 +49,33 @@ fi
verify_plexpy_pid() { verify_plexpy_pid() {
# Make sure the pid corresponds to the PlexPy process. # Make sure the pid corresponds to the PlexPy process.
if [ -f ${plexpy_pid} ]; then
pid=`cat ${plexpy_pid} 2>/dev/null` pid=`cat ${plexpy_pid} 2>/dev/null`
ps -p ${pid} | grep -q "python ${plexpy_dir}/PlexPy.py" ps -p ${pid} | grep -q "python2 ${plexpy_dir}/PlexPy.py"
return $? return $?
else
return 0
fi
} }
# Try to stop PlexPy cleanly by calling shutdown over http. # Try to stop PlexPy cleanly by sending SIGTERM
plexpy_stop() { plexpy_stop() {
echo "Stopping $name" echo "Stopping $name"
verify_plexpy_pid verify_plexpy_pid
if [ -n "${pid}" ]; then if [ -n "${pid}" ]; then
kill ${pid}
wait_for_pids ${pid} wait_for_pids ${pid}
echo "Stopped" echo "Stopped."
fi fi
} }
plexpy_status() { plexpy_status() {
verify_plexpy_pid && echo "$name is running as ${pid}" || echo "$name is not running" verify_plexpy_pid
if [ -n "${pid}" ]; then
echo "$name is running as ${pid}."
else
echo "$name is not running."
fi
} }
run_rc_command "$1" run_rc_command "$1"

View File

@@ -58,7 +58,7 @@ verify_plexpy_pid() {
fi fi
} }
# Try to stop PlexPy cleanly by calling shutdown over http. # Try to stop PlexPy cleanly by sending SIGTERM
plexpy_stop() { plexpy_stop() {
echo "Stopping $name." echo "Stopping $name."
verify_plexpy_pid verify_plexpy_pid

View File

@@ -31,14 +31,6 @@ PLATFORM_VERSION = platform.release()
BRANCH = version.PLEXPY_VERSION BRANCH = version.PLEXPY_VERSION
VERSION_NUMBER = version.PLEXPY_RELEASE_VERSION VERSION_NUMBER = version.PLEXPY_RELEASE_VERSION
# Notification Types
NOTIFY_STARTED = 1
NOTIFY_STOPPED = 2
notify_strings = {}
notify_strings[NOTIFY_STARTED] = "Playback started"
notify_strings[NOTIFY_STOPPED] = "Playback stopped"
DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png" DEFAULT_USER_THUMB = "interfaces/default/images/gravatar-default-80x80.png"
DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png" DEFAULT_POSTER_THUMB = "interfaces/default/images/poster.png"
DEFAULT_COVER_THUMB = "interfaces/default/images/cover.png" DEFAULT_COVER_THUMB = "interfaces/default/images/cover.png"
@@ -47,7 +39,11 @@ DEFAULT_ART = "interfaces/default/images/art.png"
PLATFORM_NAME_OVERRIDES = {'Konvergo': 'Plex Media Player', PLATFORM_NAME_OVERRIDES = {'Konvergo': 'Plex Media Player',
'Mystery 3': 'Playstation 3', 'Mystery 3': 'Playstation 3',
'Mystery 4': 'Playstation 4', 'Mystery 4': 'Playstation 4',
'Mystery 5': 'Xbox 360'} 'Mystery 5': 'Xbox 360'
}
PMS_PLATFORM_NAME_OVERRIDES = {'MacOSX': 'Mac'
}
MEDIA_FLAGS_AUDIO = {'ac.?3': 'dolby_digital', MEDIA_FLAGS_AUDIO = {'ac.?3': 'dolby_digital',
'truehd': 'dolby_truehd', 'truehd': 'dolby_truehd',

View File

@@ -170,7 +170,7 @@ _CONFIG_DEFINITIONS = {
'GIT_BRANCH': (str, 'General', 'master'), 'GIT_BRANCH': (str, 'General', 'master'),
'GIT_PATH': (str, 'General', ''), 'GIT_PATH': (str, 'General', ''),
'GIT_TOKEN': (str, 'General', ''), 'GIT_TOKEN': (str, 'General', ''),
'GIT_USER': (str, 'General', 'drzoidberg33'), 'GIT_USER': (str, 'General', 'JonnyWong16'),
'GRAPH_TYPE': (str, 'General', 'plays'), 'GRAPH_TYPE': (str, 'General', 'plays'),
'GRAPH_DAYS': (int, 'General', 30), 'GRAPH_DAYS': (int, 'General', 30),
'GRAPH_TAB': (str, 'General', 'tabs-1'), 'GRAPH_TAB': (str, 'General', 'tabs-1'),
@@ -802,3 +802,8 @@ class Config(object):
if self.CONFIG_VERSION == '5': if self.CONFIG_VERSION == '5':
self.MONITOR_PMS_UPDATES = 0 self.MONITOR_PMS_UPDATES = 0
self.CONFIG_VERSION = '6' self.CONFIG_VERSION = '6'
if self.CONFIG_VERSION == '6':
if self.GIT_USER.lower() == 'drzoidberg33':
self.GIT_USER = 'JonnyWong16'
self.CONFIG_VERSION = '7'

View File

@@ -65,23 +65,20 @@ class DataTables(object):
extracted_columns['column_named'], extracted_columns['column_named'],
parameters['columns']) parameters['columns'])
args = cw_args + w_args
# Build union parameters # Build union parameters
if table_name_union: if table_name_union:
extracted_columns_union = self.extract_columns(columns=columns_union) extracted_columns_union = self.extract_columns(columns=columns_union)
group_u = self.build_grouping(group_by_union) group_u = self.build_grouping(group_by_union)
c_where_u, cwu_args = self.build_custom_where(custom_where_union) c_where_u, cwu_args = self.build_custom_where(custom_where_union)
args += cwu_args
union = 'UNION SELECT %s FROM %s %s %s' % (extracted_columns_union['column_string'], union = 'UNION SELECT %s FROM %s %s %s' % (extracted_columns_union['column_string'],
table_name_union, table_name_union,
c_where_u, c_where_u,
group_u) group_u)
else: else:
union = '' union = ''
cwu_args = []
args = cw_args + cwu_args + w_args
# Build the query # Build the query
query = 'SELECT * FROM (SELECT %s FROM %s %s %s %s %s) %s %s' \ query = 'SELECT * FROM (SELECT %s FROM %s %s %s %s %s) %s %s' \

View File

@@ -616,6 +616,7 @@ def send_notification(agent_id, subject, body, notify_action, **kwargs):
else: else:
logger.debug(u"PlexPy Notifiers :: Notification requested but no agent id received.") logger.debug(u"PlexPy Notifiers :: Notification requested but no agent id received.")
class PrettyMetadata(object): class PrettyMetadata(object):
def __init__(self, metadata): def __init__(self, metadata):
self.metadata = metadata self.metadata = metadata
@@ -625,9 +626,9 @@ class PrettyMetadata(object):
self.poster_url = self.metadata.get('poster_url','') self.poster_url = self.metadata.get('poster_url','')
if not self.poster_url: if not self.poster_url:
if self.metadata['media_type'] in ['artist', 'track']: if self.metadata['media_type'] in ['artist', 'track']:
self.poster_url = 'https://raw.githubusercontent.com/drzoidberg33/plexpy/master/data/interfaces/default/images/cover.png' self.poster_url = 'https://raw.githubusercontent.com/%s/plexpy/master/data/interfaces/default/images/cover.png' % plexpy.CONFIG.GIT_USER
else: else:
self.poster_url = 'https://raw.githubusercontent.com/drzoidberg33/plexpy/master/data/interfaces/default/images/poster.png' self.poster_url = 'https://raw.githubusercontent.com/%s/plexpy/master/data/interfaces/default/images/poster.png' % plexpy.CONFIG.GIT_USER
return self.poster_url return self.poster_url
def get_poster_link(self): def get_poster_link(self):
@@ -683,6 +684,7 @@ class PrettyMetadata(object):
self.plex_url = self.metadata['plex_url'] self.plex_url = self.metadata['plex_url']
return self.plex_url return self.plex_url
class GROWL(object): class GROWL(object):
""" """
Growl notifications, for OS X. Growl notifications, for OS X.
@@ -2114,6 +2116,21 @@ class Scripts(object):
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.script_exts = ('.bat', '.cmd', '.exe', '.php', '.pl', '.ps1', '.py', '.pyw', '.rb', '.sh') self.script_exts = ('.bat', '.cmd', '.exe', '.php', '.pl', '.ps1', '.py', '.pyw', '.rb', '.sh')
self.script_folder = plexpy.CONFIG.SCRIPTS_FOLDER self.script_folder = plexpy.CONFIG.SCRIPTS_FOLDER
self.scripts = {'play': plexpy.CONFIG.SCRIPTS_ON_PLAY_SCRIPT,
'stop': plexpy.CONFIG.SCRIPTS_ON_STOP_SCRIPT,
'pause': plexpy.CONFIG.SCRIPTS_ON_PAUSE_SCRIPT,
'resume': plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT,
'watched': plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT,
'buffer': plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT,
'created': plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT,
'intdown': plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT,
'intup': plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT,
'extdown': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT,
'extup': plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT,
'pmsupdate': plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE_SCRIPT,
'concurrent': plexpy.CONFIG.SCRIPTS_ON_CONCURRENT_SCRIPT,
'newdevice': plexpy.CONFIG.SCRIPTS_ON_NEWDEVICE_SCRIPT
}
def conf(self, options): def conf(self, options):
return cherrypy.config['config'].get('Scripts', options) return cherrypy.config['config'].get('Scripts', options)
@@ -2160,52 +2177,7 @@ class Scripts(object):
if not self.script_folder: if not self.script_folder:
return return
# Make sure we use the correct script.. script = self.scripts.get(notify_action, kwargs.get('script', ''))
if notify_action == 'play':
script = plexpy.CONFIG.SCRIPTS_ON_PLAY_SCRIPT
elif notify_action == 'stop':
script = plexpy.CONFIG.SCRIPTS_ON_STOP_SCRIPT
elif notify_action == 'pause':
script = plexpy.CONFIG.SCRIPTS_ON_PAUSE_SCRIPT
elif notify_action == 'resume':
script = plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT
elif notify_action == 'watched':
script = plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT
elif notify_action == 'buffer':
script = plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT
elif notify_action == 'created':
script = plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT
elif notify_action == 'intdown':
script = plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT
elif notify_action == 'intup':
script = plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT
elif notify_action == 'extdown':
script = plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT
elif notify_action == 'extup':
script = plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT
elif notify_action == 'pmsupdate':
script = plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE_SCRIPT
elif notify_action == 'concurrent':
script = plexpy.CONFIG.SCRIPTS_ON_CONCURRENT_SCRIPT
elif notify_action == 'newdevice':
script = plexpy.CONFIG.SCRIPTS_ON_NEWDEVICE_SCRIPT
else:
# For manual scripts
script = kwargs.get('script', '')
# Don't try to run the script if the action does not have one # Don't try to run the script if the action does not have one
if notify_action and not script: if notify_action and not script:
@@ -2297,98 +2269,98 @@ class Scripts(object):
'input_type': 'text', 'input_type': 'text',
}, },
{'label': 'Playback Start', {'label': 'Playback Start',
'value': plexpy.CONFIG.SCRIPTS_ON_PLAY_SCRIPT, 'value': self.scripts['play'],
'name': 'scripts_on_play_script', 'name': 'scripts_on_play_script',
'description': 'Choose the script for on play.', 'description': 'Choose the script for on play.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Playback Stop', {'label': 'Playback Stop',
'value': plexpy.CONFIG.SCRIPTS_ON_STOP_SCRIPT, 'value': self.scripts['stop'],
'name': 'scripts_on_stop_script', 'name': 'scripts_on_stop_script',
'description': 'Choose the script for on stop.', 'description': 'Choose the script for on stop.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Playback Pause', {'label': 'Playback Pause',
'value': plexpy.CONFIG.SCRIPTS_ON_PAUSE_SCRIPT, 'value': self.scripts['pause'],
'name': 'scripts_on_pause_script', 'name': 'scripts_on_pause_script',
'description': 'Choose the script for on pause.', 'description': 'Choose the script for on pause.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Playback Resume', {'label': 'Playback Resume',
'value': plexpy.CONFIG.SCRIPTS_ON_RESUME_SCRIPT, 'value': self.scripts['resume'],
'name': 'scripts_on_resume_script', 'name': 'scripts_on_resume_script',
'description': 'Choose the script for on resume.', 'description': 'Choose the script for on resume.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Watched', {'label': 'Watched',
'value': plexpy.CONFIG.SCRIPTS_ON_WATCHED_SCRIPT, 'value': self.scripts['watched'],
'name': 'scripts_on_watched_script', 'name': 'scripts_on_watched_script',
'description': 'Choose the script for on watched.', 'description': 'Choose the script for on watched.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Buffer Warnings', {'label': 'Buffer Warnings',
'value': plexpy.CONFIG.SCRIPTS_ON_BUFFER_SCRIPT, 'value': self.scripts['buffer'],
'name': 'scripts_on_buffer_script', 'name': 'scripts_on_buffer_script',
'description': 'Choose the script for buffer warnings.', 'description': 'Choose the script for buffer warnings.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Recently Added', {'label': 'Recently Added',
'value': plexpy.CONFIG.SCRIPTS_ON_CREATED_SCRIPT, 'value': self.scripts['created'],
'name': 'scripts_on_created_script', 'name': 'scripts_on_created_script',
'description': 'Choose the script for recently added.', 'description': 'Choose the script for recently added.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Plex Server Down', {'label': 'Plex Server Down',
'value': plexpy.CONFIG.SCRIPTS_ON_INTDOWN_SCRIPT, 'value': self.scripts['intdown'],
'name': 'scripts_on_intdown_script', 'name': 'scripts_on_intdown_script',
'description': 'Choose the script for Plex server down.', 'description': 'Choose the script for Plex server down.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Plex Server Back Up', {'label': 'Plex Server Back Up',
'value': plexpy.CONFIG.SCRIPTS_ON_INTUP_SCRIPT, 'value': self.scripts['intup'],
'name': 'scripts_on_intup_script', 'name': 'scripts_on_intup_script',
'description': 'Choose the script for Plex server back up.', 'description': 'Choose the script for Plex server back up.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Plex Remote Access Down', {'label': 'Plex Remote Access Down',
'value': plexpy.CONFIG.SCRIPTS_ON_EXTDOWN_SCRIPT, 'value': self.scripts['extdown'],
'name': 'scripts_on_extdown_script', 'name': 'scripts_on_extdown_script',
'description': 'Choose the script for Plex remote access down.', 'description': 'Choose the script for Plex remote access down.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Plex Remote Access Back Up', {'label': 'Plex Remote Access Back Up',
'value': plexpy.CONFIG.SCRIPTS_ON_EXTUP_SCRIPT, 'value': self.scripts['extup'],
'name': 'scripts_on_extup_script', 'name': 'scripts_on_extup_script',
'description': 'Choose the script for Plex remote access back up.', 'description': 'Choose the script for Plex remote access back up.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'Plex Update Available', {'label': 'Plex Update Available',
'value': plexpy.CONFIG.SCRIPTS_ON_PMSUPDATE_SCRIPT, 'value': self.scripts['pmsupdate'],
'name': 'scripts_on_pmsupdate_script', 'name': 'scripts_on_pmsupdate_script',
'description': 'Choose the script for Plex update available.', 'description': 'Choose the script for Plex update available.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'User Concurrent Streams', {'label': 'User Concurrent Streams',
'value': plexpy.CONFIG.SCRIPTS_ON_CONCURRENT_SCRIPT, 'value': self.scripts['concurrent'],
'name': 'scripts_on_concurrent_script', 'name': 'scripts_on_concurrent_script',
'description': 'Choose the script for user concurrent streams.', 'description': 'Choose the script for user concurrent streams.',
'input_type': 'select', 'input_type': 'select',
'select_options': self.list_scripts() 'select_options': self.list_scripts()
}, },
{'label': 'User New Device', {'label': 'User New Device',
'value': plexpy.CONFIG.SCRIPTS_ON_NEWDEVICE_SCRIPT, 'value': self.scripts['newdevice'],
'name': 'scripts_on_newdevice_script', 'name': 'scripts_on_newdevice_script',
'description': 'Choose the script for user new device.', 'description': 'Choose the script for user new device.',
'input_type': 'select', 'input_type': 'select',

View File

@@ -136,6 +136,14 @@ def extract_plexivity_xml(xml=None):
video_decision = helpers.get_xml_attr(e, 'videoDecision') video_decision = helpers.get_xml_attr(e, 'videoDecision')
transcode_width = helpers.get_xml_attr(e, 'width') transcode_width = helpers.get_xml_attr(e, 'width')
# Generate a combined transcode decision value
if video_decision == 'transcode' or audio_decision == 'transcode':
transcode_decision = 'transcode'
elif video_decision == 'copy' or audio_decision == 'copy':
transcode_decision = 'copy'
else:
transcode_decision = 'direct play'
user_id = None user_id = None
if a.getElementsByTagName('User'): if a.getElementsByTagName('User'):
@@ -215,6 +223,7 @@ def extract_plexivity_xml(xml=None):
'transcode_video_codec': transcode_video_codec, 'transcode_video_codec': transcode_video_codec,
'video_decision': video_decision, 'video_decision': video_decision,
'transcode_width': transcode_width, 'transcode_width': transcode_width,
'transcode_decision': transcode_decision,
'user_id': user_id, 'user_id': user_id,
'writers': writers, 'writers': writers,
'actors': actors, 'actors': actors,
@@ -339,6 +348,7 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
'title': row['title'], 'title': row['title'],
'parent_title': extracted_xml['parent_title'], 'parent_title': extracted_xml['parent_title'],
'grandparent_title': row['grandparent_title'], 'grandparent_title': row['grandparent_title'],
'full_title': row['full_title'],
'user_id': user_id, 'user_id': user_id,
'user': row['user'], 'user': row['user'],
'ip_address': row['ip_address'] if row['ip_address'] else extracted_xml['ip_address'], 'ip_address': row['ip_address'] if row['ip_address'] else extracted_xml['ip_address'],
@@ -352,6 +362,7 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
'view_offset': extracted_xml['view_offset'], 'view_offset': extracted_xml['view_offset'],
'video_decision': extracted_xml['video_decision'], 'video_decision': extracted_xml['video_decision'],
'audio_decision': extracted_xml['audio_decision'], 'audio_decision': extracted_xml['audio_decision'],
'transcode_decision': extracted_xml['transcode_decision'],
'duration': extracted_xml['duration'], 'duration': extracted_xml['duration'],
'width': extracted_xml['width'], 'width': extracted_xml['width'],
'height': extracted_xml['height'], 'height': extracted_xml['height'],

View File

@@ -21,6 +21,7 @@ import json
from xml.dom import minidom from xml.dom import minidom
import plexpy import plexpy
import common
import database import database
import helpers import helpers
import http_handler import http_handler
@@ -628,12 +629,13 @@ class PlexTV(object):
return {} return {}
# Get the updates for the platform # Get the updates for the platform
platform_downloads = available_downloads.get('computer').get(plexpy.CONFIG.PMS_PLATFORM) or \ pms_platform = common.PMS_PLATFORM_NAME_OVERRIDES.get(plexpy.CONFIG.PMS_PLATFORM, plexpy.CONFIG.PMS_PLATFORM)
available_downloads.get('nas').get(plexpy.CONFIG.PMS_PLATFORM) platform_downloads = available_downloads.get('computer').get(pms_platform) or \
available_downloads.get('nas').get(pms_platform)
if not platform_downloads: if not platform_downloads:
logger.error(u"PlexPy PlexTV :: Unable to retrieve Plex updates: Could not match server platform: %s." logger.error(u"PlexPy PlexTV :: Unable to retrieve Plex updates: Could not match server platform: %s."
% plexpy.CONFIG.PMS_PLATFORM) % pms_platform)
return {} return {}
v_old = helpers.cast_to_int("".join(v.zfill(4) for v in plexpy.CONFIG.PMS_VERSION.split('-')[0].split('.')[:4])) v_old = helpers.cast_to_int("".join(v.zfill(4) for v in plexpy.CONFIG.PMS_VERSION.split('-')[0].split('.')[:4]))

View File

@@ -130,6 +130,14 @@ def extract_plexwatch_xml(xml=None):
video_decision = helpers.get_xml_attr(e, 'videoDecision') video_decision = helpers.get_xml_attr(e, 'videoDecision')
transcode_width = helpers.get_xml_attr(e, 'width') transcode_width = helpers.get_xml_attr(e, 'width')
# Generate a combined transcode decision value
if video_decision == 'transcode' or audio_decision == 'transcode':
transcode_decision = 'transcode'
elif video_decision == 'copy' or audio_decision == 'copy':
transcode_decision = 'copy'
else:
transcode_decision = 'direct play'
user_id = None user_id = None
if a.getElementsByTagName('User'): if a.getElementsByTagName('User'):
@@ -206,6 +214,7 @@ def extract_plexwatch_xml(xml=None):
'transcode_video_codec': transcode_video_codec, 'transcode_video_codec': transcode_video_codec,
'video_decision': video_decision, 'video_decision': video_decision,
'transcode_width': transcode_width, 'transcode_width': transcode_width,
'transcode_decision': transcode_decision,
'user_id': user_id, 'user_id': user_id,
'writers': writers, 'writers': writers,
'actors': actors, 'actors': actors,
@@ -332,6 +341,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
'title': row['title'], 'title': row['title'],
'parent_title': extracted_xml['parent_title'], 'parent_title': extracted_xml['parent_title'],
'grandparent_title': row['grandparent_title'], 'grandparent_title': row['grandparent_title'],
'full_title': row['full_title'],
'user_id': user_id, 'user_id': user_id,
'user': row['user'], 'user': row['user'],
'ip_address': row['ip_address'] if row['ip_address'] else extracted_xml['ip_address'], 'ip_address': row['ip_address'] if row['ip_address'] else extracted_xml['ip_address'],
@@ -345,6 +355,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
'view_offset': extracted_xml['view_offset'], 'view_offset': extracted_xml['view_offset'],
'video_decision': extracted_xml['video_decision'], 'video_decision': extracted_xml['video_decision'],
'audio_decision': extracted_xml['audio_decision'], 'audio_decision': extracted_xml['audio_decision'],
'transcode_decision': extracted_xml['transcode_decision'],
'duration': extracted_xml['duration'], 'duration': extracted_xml['duration'],
'width': extracted_xml['width'], 'width': extracted_xml['width'],
'height': extracted_xml['height'], 'height': extracted_xml['height'],

View File

@@ -279,7 +279,7 @@ class Users(object):
'shared_libraries': () 'shared_libraries': ()
} }
if not user_id and not user and not email: if user_id is None and not user and not email:
return default_return return default_return
def get_user_details(user_id=user_id, user=user, email=email): def get_user_details(user_id=user_id, user=user, email=email):

View File

@@ -1,2 +1,2 @@
PLEXPY_VERSION = "master" PLEXPY_VERSION = "master"
PLEXPY_RELEASE_VERSION = "1.4.10" PLEXPY_RELEASE_VERSION = "1.4.12"

View File

@@ -81,7 +81,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def index(self): def index(self, **kwargs):
if plexpy.CONFIG.FIRST_RUN_COMPLETE: if plexpy.CONFIG.FIRST_RUN_COMPLETE:
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT + "home") raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT + "home")
else: else:
@@ -168,7 +168,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def home(self): def home(self, **kwargs):
config = { config = {
"home_sections": plexpy.CONFIG.HOME_SECTIONS, "home_sections": plexpy.CONFIG.HOME_SECTIONS,
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH, "home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
@@ -329,7 +329,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def delete_temp_sessions(self): def delete_temp_sessions(self, **kwargs):
result = database.delete_sessions() result = database.delete_sessions()
@@ -343,7 +343,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def libraries(self): def libraries(self, **kwargs):
config = { config = {
"update_section_ids": plexpy.CONFIG.UPDATE_SECTION_IDS "update_section_ids": plexpy.CONFIG.UPDATE_SECTION_IDS
} }
@@ -469,7 +469,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def library(self, section_id=None): def library(self, section_id=None, **kwargs):
if not allow_session_library(section_id): if not allow_session_library(section_id):
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT) raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
@@ -708,7 +708,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def get_media_info_file_sizes(self, section_id=None, rating_key=None): def get_media_info_file_sizes(self, section_id=None, rating_key=None, **kwargs):
get_file_sizes_hold = plexpy.CONFIG.GET_FILE_SIZES_HOLD get_file_sizes_hold = plexpy.CONFIG.GET_FILE_SIZES_HOLD
section_ids = set(get_file_sizes_hold['section_ids']) section_ids = set(get_file_sizes_hold['section_ids'])
rating_keys = set(get_file_sizes_hold['rating_keys']) rating_keys = set(get_file_sizes_hold['rating_keys'])
@@ -999,7 +999,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def delete_duplicate_libraries(self): def delete_duplicate_libraries(self, **kwargs):
library_data = libraries.Libraries() library_data = libraries.Libraries()
result = library_data.delete_duplicate_libraries() result = library_data.delete_duplicate_libraries()
@@ -1013,7 +1013,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def users(self): def users(self, **kwargs):
return serve_template(templatename="users.html", title="Users") return serve_template(templatename="users.html", title="Users")
@cherrypy.expose @cherrypy.expose
@@ -1100,7 +1100,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def user(self, user_id=None): def user(self, user_id=None, **kwargs):
if not allow_session_user(user_id): if not allow_session_user(user_id):
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT) raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
@@ -1566,7 +1566,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def history(self): def history(self, **kwargs):
return serve_template(templatename="history.html", title="History") return serve_template(templatename="history.html", title="History")
@cherrypy.expose @cherrypy.expose
@@ -1740,7 +1740,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def graphs(self): def graphs(self, **kwargs):
config = { config = {
"graph_type": plexpy.CONFIG.GRAPH_TYPE, "graph_type": plexpy.CONFIG.GRAPH_TYPE,
@@ -1753,7 +1753,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def set_graph_config(self, graph_type=None, graph_days=None, graph_tab=None): def set_graph_config(self, graph_type=None, graph_days=None, graph_tab=None, **kwargs):
if graph_type: if graph_type:
plexpy.CONFIG.__setattr__('GRAPH_TYPE', graph_type) plexpy.CONFIG.__setattr__('GRAPH_TYPE', graph_type)
plexpy.CONFIG.write() plexpy.CONFIG.write()
@@ -2203,7 +2203,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def sync(self): def sync(self, **kwargs):
return serve_template(templatename="sync.html", title="Synced Items") return serve_template(templatename="sync.html", title="Synced Items")
@cherrypy.expose @cherrypy.expose
@@ -2229,7 +2229,7 @@ class WebInterface(object):
##### Logs ##### ##### Logs #####
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def logs(self): def logs(self, **kwargs):
return serve_template(templatename="logs.html", title="Log") return serve_template(templatename="logs.html", title="Log")
@cherrypy.expose @cherrypy.expose
@@ -2443,7 +2443,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def delete_logs(self): def delete_logs(self, **kwargs):
log_file = logger.FILENAME log_file = logger.FILENAME
try: try:
open(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), 'w').close() open(os.path.join(plexpy.CONFIG.LOG_DIR, log_file), 'w').close()
@@ -2459,7 +2459,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def toggleVerbose(self): def toggleVerbose(self, **kwargs):
plexpy.VERBOSE = not plexpy.VERBOSE plexpy.VERBOSE = not plexpy.VERBOSE
logger.initLogger(console=not plexpy.QUIET, logger.initLogger(console=not plexpy.QUIET,
log_dir=plexpy.CONFIG.LOG_DIR, verbose=plexpy.VERBOSE) log_dir=plexpy.CONFIG.LOG_DIR, verbose=plexpy.VERBOSE)
@@ -2469,7 +2469,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def log_js_errors(self, page, message, file, line): def log_js_errors(self, page, message, file, line, **kwargs):
""" Logs javascript errors from the web interface. """ """ Logs javascript errors from the web interface. """
logger.error(u"WebUI :: /%s : %s. (%s:%s)" % (page.rpartition('/')[-1], logger.error(u"WebUI :: /%s : %s. (%s:%s)" % (page.rpartition('/')[-1],
message, message,
@@ -2479,7 +2479,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def logFile(self): def logFile(self, **kwargs):
try: try:
with open(os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME), 'r') as f: with open(os.path.join(plexpy.CONFIG.LOG_DIR, logger.FILENAME), 'r') as f:
return '<pre>%s</pre>' % f.read() return '<pre>%s</pre>' % f.read()
@@ -2764,7 +2764,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def backup_config(self): def backup_config(self, **kwargs):
""" Creates a manual backup of the plexpy.db file """ """ Creates a manual backup of the plexpy.db file """
result = config.make_backup() result = config.make_backup()
@@ -2787,11 +2787,12 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def get_server_update_params(self): def get_server_update_params(self, **kwargs):
plex_tv = plextv.PlexTV() plex_tv = plextv.PlexTV()
plexpass = plex_tv.get_plexpass_status() plexpass = plex_tv.get_plexpass_status()
return {'plexpass': plexpass, return {'plexpass': plexpass,
'pms_platform': plexpy.CONFIG.PMS_PLATFORM, 'pms_platform': common.PMS_PLATFORM_NAME_OVERRIDES.get(
plexpy.CONFIG.PMS_PLATFORM, plexpy.CONFIG.PMS_PLATFORM),
'pms_update_channel': plexpy.CONFIG.PMS_UPDATE_CHANNEL, 'pms_update_channel': plexpy.CONFIG.PMS_UPDATE_CHANNEL,
'pms_update_distro': plexpy.CONFIG.PMS_UPDATE_DISTRO, 'pms_update_distro': plexpy.CONFIG.PMS_UPDATE_DISTRO,
'pms_update_distro_build': plexpy.CONFIG.PMS_UPDATE_DISTRO_BUILD} 'pms_update_distro_build': plexpy.CONFIG.PMS_UPDATE_DISTRO_BUILD}
@@ -2799,7 +2800,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def backup_db(self): def backup_db(self, **kwargs):
""" Creates a manual backup of the plexpy.db file """ """ Creates a manual backup of the plexpy.db file """
result = database.make_backup() result = database.make_backup()
@@ -2813,7 +2814,7 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def install_geoip_db(self): def install_geoip_db(self, **kwargs):
""" Downloads and installs the GeoLite2 database """ """ Downloads and installs the GeoLite2 database """
result = helpers.install_geoip_db() result = helpers.install_geoip_db()
@@ -2827,7 +2828,7 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def uninstall_geoip_db(self): def uninstall_geoip_db(self, **kwargs):
""" Uninstalls the GeoLite2 database """ """ Uninstalls the GeoLite2 database """
result = helpers.uninstall_geoip_db() result = helpers.uninstall_geoip_db()
@@ -2957,14 +2958,14 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def facebookStep1(self): def facebookStep1(self, **kwargs):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
facebook = notifiers.FacebookNotifier() facebook = notifiers.FacebookNotifier()
return facebook._get_authorization() return facebook._get_authorization()
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def facebookStep2(self, code): def facebookStep2(self, code, **kwargs):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
facebook = notifiers.FacebookNotifier() facebook = notifiers.FacebookNotifier()
result = facebook._get_credentials(code) result = facebook._get_credentials(code)
@@ -2976,7 +2977,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def osxnotifyregister(self, app): def osxnotifyregister(self, app, **kwargs):
cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store" cherrypy.response.headers['Cache-Control'] = "max-age=0,no-cache,no-store"
from osxnotify import registerapp as osxnotify from osxnotify import registerapp as osxnotify
@@ -3174,20 +3175,20 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def generateAPI(self): def generateAPI(self, **kwargs):
apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32] apikey = hashlib.sha224(str(random.getrandbits(256))).hexdigest()[0:32]
logger.info(u"New API key generated.") logger.info(u"New API key generated.")
return apikey return apikey
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def checkGithub(self): def checkGithub(self, **kwargs):
versioncheck.checkGithub() versioncheck.checkGithub()
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT + "home") raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT + "home")
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def do_state_change(self, signal, title, timer): def do_state_change(self, signal, title, timer, **kwargs):
message = title message = title
quote = self.random_arnold_quotes() quote = self.random_arnold_quotes()
plexpy.SIGNAL = signal plexpy.SIGNAL = signal
@@ -3197,17 +3198,17 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def shutdown(self): def shutdown(self, **kwargs):
return self.do_state_change('shutdown', 'Shutting Down', 15) return self.do_state_change('shutdown', 'Shutting Down', 15)
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def restart(self): def restart(self, **kwargs):
return self.do_state_change('restart', 'Restarting', 30) return self.do_state_change('restart', 'Restarting', 30)
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def update(self): def update(self, **kwargs):
return self.do_state_change('update', 'Updating', 120) return self.do_state_change('update', 'Updating', 120)
@@ -3330,7 +3331,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def download_log(self): def download_log(self, **kwargs):
""" Download the PlexPy log file. """ """ Download the PlexPy log file. """
log_file = logger.FILENAME log_file = logger.FILENAME
try: try:
@@ -3368,7 +3369,7 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def delete_image_cache(self): def delete_image_cache(self, **kwargs):
""" Delete and recreate the image cache directory. """ """ Delete and recreate the image cache directory. """
return self.delete_cache(folder='images') return self.delete_cache(folder='images')
@@ -3376,7 +3377,7 @@ class WebInterface(object):
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
@addtoapi() @addtoapi()
def delete_cache(self, folder=''): def delete_cache(self, folder='', **kwargs):
""" Delete and recreate the cache directory. """ """ Delete and recreate the cache directory. """
cache_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, folder) cache_dir = os.path.join(plexpy.CONFIG.CACHE_DIR, folder)
result = 'success' result = 'success'
@@ -3403,7 +3404,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def delete_poster_url(self, poster_url=''): def delete_poster_url(self, poster_url='', **kwargs):
if poster_url: if poster_url:
data_factory = datafactory.DataFactory() data_factory = datafactory.DataFactory()
@@ -3421,7 +3422,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@requireAuth() @requireAuth()
def search(self, query=''): def search(self, query='', **kwargs):
return serve_template(templatename="search.html", title="Search", query=query) return serve_template(templatename="search.html", title="Search", query=query)
@cherrypy.expose @cherrypy.expose
@@ -4283,7 +4284,7 @@ class WebInterface(object):
@cherrypy.expose @cherrypy.expose
@cherrypy.tools.json_out() @cherrypy.tools.json_out()
@requireAuth(member_of("admin")) @requireAuth(member_of("admin"))
def check_pms_updater(self): def check_pms_updater(self, **kwargs):
pms_connect = pmsconnect.PmsConnect() pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_update_staus() result = pms_connect.get_update_staus()
return result return result