mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-10 23:42:37 -07:00
Rename PlexPy to Tautulli
This commit is contained in:
parent
55bdde808b
commit
19f029cff0
50 changed files with 867 additions and 870 deletions
22
PlexPy.py
22
PlexPy.py
|
@ -6,20 +6,20 @@
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -43,11 +43,11 @@ signal.signal(signal.SIGTERM, plexpy.sig_handler)
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""
|
"""
|
||||||
PlexPy application entry point. Parses arguments, setups encoding and
|
Tautulli application entry point. Parses arguments, setups encoding and
|
||||||
initializes the application.
|
initializes the application.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Fixed paths to PlexPy
|
# Fixed paths to Tautulli
|
||||||
if hasattr(sys, 'frozen'):
|
if hasattr(sys, 'frozen'):
|
||||||
plexpy.FULL_PATH = os.path.abspath(sys.executable)
|
plexpy.FULL_PATH = os.path.abspath(sys.executable)
|
||||||
else:
|
else:
|
||||||
|
@ -81,9 +81,9 @@ def main():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-d', '--daemon', action='store_true', help='Run as a daemon')
|
'-d', '--daemon', action='store_true', help='Run as a daemon')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-p', '--port', type=int, help='Force PlexPy to run on a specified port')
|
'-p', '--port', type=int, help='Force Tautulli to run on a specified port')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--dev', action='store_true', help='Start PlexPy in the development environment')
|
'--dev', action='store_true', help='Start Tautulli in the development environment')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--datadir', help='Specify a directory where to store your data files')
|
'--datadir', help='Specify a directory where to store your data files')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
@ -93,7 +93,7 @@ def main():
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--pidfile', help='Create a pid file (only relevant when running as a daemon)')
|
'--pidfile', help='Create a pid file (only relevant when running as a daemon)')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'--nofork', action='store_true', help='Start PlexPy as a service, do not fork when restarting')
|
'--nofork', action='store_true', help='Start Tautulli as a service, do not fork when restarting')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ def main():
|
||||||
|
|
||||||
if args.dev:
|
if args.dev:
|
||||||
plexpy.DEV = True
|
plexpy.DEV = True
|
||||||
logger.debug(u"PlexPy is running in the dev environment.")
|
logger.debug(u"Tautulli is running in the dev environment.")
|
||||||
|
|
||||||
if args.daemon:
|
if args.daemon:
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
|
@ -120,7 +120,7 @@ def main():
|
||||||
|
|
||||||
if args.nofork:
|
if args.nofork:
|
||||||
plexpy.NOFORK = True
|
plexpy.NOFORK = True
|
||||||
logger.info("PlexPy is running as a service, it will not fork when restarted.")
|
logger.info("Tautulli is running as a service, it will not fork when restarted.")
|
||||||
|
|
||||||
if args.pidfile:
|
if args.pidfile:
|
||||||
plexpy.PIDFILE = str(args.pidfile)
|
plexpy.PIDFILE = str(args.pidfile)
|
||||||
|
|
12
README.md
12
README.md
|
@ -1,8 +1,8 @@
|
||||||
# PlexPy
|
# Tautulli
|
||||||
|
|
||||||
[](https://discord.gg/36ggawe)
|
[](https://discord.gg/36ggawe)
|
||||||
[](https://gitter.im/plexpy/general)
|
[](https://discord.gg/36ggawe)
|
||||||
[](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
|
[](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program)
|
||||||
|
|
||||||
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).
|
||||||
|
|
||||||
|
@ -29,11 +29,11 @@ This project is based on code from [Headphones](https://github.com/rembo10/headp
|
||||||
|
|
||||||
* [Full preview gallery on Imgur](https://imgur.com/a/RwQPM)
|
* [Full preview gallery on Imgur](https://imgur.com/a/RwQPM)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Installation and Support
|
## Installation and Support
|
||||||
|
|
||||||
* [Installation Guides](https://github.com/JonnyWong16/plexpy/wiki/Installation) shows you how to install PlexPy.
|
* [Installation Guides](https://github.com/JonnyWong16/plexpy/wiki/Installation) shows you how to install Tautulli.
|
||||||
* [FAQs](https://github.com/JonnyWong16/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.
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
% if _session['user_group'] == 'admin':
|
% if _session['user_group'] == 'admin':
|
||||||
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
|
% if plexpy.CONFIG.CHECK_GITHUB and not plexpy.CURRENT_VERSION:
|
||||||
<div id="updatebar" style="display: none;">
|
<div id="updatebar" style="display: none;">
|
||||||
You're running an unknown version of PlexPy.<br />
|
You're running an unknown version of Tautulli.<br />
|
||||||
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
|
<a href="update">Update</a> or <a href="#" id="updateDismiss">Close</a>
|
||||||
</div>
|
</div>
|
||||||
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win':
|
% elif plexpy.CONFIG.CHECK_GITHUB and plexpy.CURRENT_VERSION != plexpy.LATEST_VERSION and plexpy.COMMITS_BEHIND > 0 and plexpy.INSTALL_TYPE != 'win':
|
||||||
|
@ -210,13 +210,13 @@ ${next.modalIncludes()}
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||||
<h4 class="modal-title">PlexPy Donation</h4>
|
<h4 class="modal-title">Tautulli Donation</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12" style="text-align: center;">
|
<div class="col-md-12" style="text-align: center;">
|
||||||
<h4>
|
<h4>
|
||||||
<strong>Thank you for supporting PlexPy!</strong>
|
<strong>Thank you for supporting Tautulli!</strong>
|
||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
Please select a donation method.
|
Please select a donation method.
|
||||||
|
@ -236,7 +236,7 @@ ${next.modalIncludes()}
|
||||||
<p>
|
<p>
|
||||||
Click the button below to continue to PayPal.
|
Click the button below to continue to PayPal.
|
||||||
</p>
|
</p>
|
||||||
<a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=PlexPy¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank">
|
<a href="${anon_url('https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=6XPPKTDSX9QFL&lc=US&item_name=Tautulli¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted')}" target="_blank">
|
||||||
<img src="images/gold-rect-paypal-34px.png" alt="PayPal">
|
<img src="images/gold-rect-paypal-34px.png" alt="PayPal">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -244,7 +244,7 @@ ${next.modalIncludes()}
|
||||||
<p>
|
<p>
|
||||||
Click the button below to continue to Flattr.
|
Click the button below to continue to Flattr.
|
||||||
</p>
|
</p>
|
||||||
<a href="${anon_url('https://flattr.com/submit/auto?user_id=JonnyWong16&url=https://github.com/JonnyWong16/plexpy&title=PlexPy&language=en_GB&tags=github&category=software')}" target="_blank">
|
<a href="${anon_url('https://flattr.com/submit/auto?user_id=JonnyWong16&url=https://github.com/JonnyWong16/plexpy&title=Tautulli&language=en_GB&tags=github&category=software')}" target="_blank">
|
||||||
<img src="images/flattr-badge-large.png" alt="Flattr">
|
<img src="images/flattr-badge-large.png" alt="Flattr">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -306,7 +306,7 @@ ${next.modalIncludes()}
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#nav-shutdown").click(function() {
|
$("#nav-shutdown").click(function() {
|
||||||
$("#confirm-message").text("Are you sure you want to shutdown PlexPy?");
|
$("#confirm-message").text("Are you sure you want to shutdown Tautulli?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
window.location.href = "shutdown";
|
window.location.href = "shutdown";
|
||||||
|
@ -314,7 +314,7 @@ ${next.modalIncludes()}
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#nav-restart").click(function() {
|
$("#nav-restart").click(function() {
|
||||||
$("#confirm-message").text("Are you sure you want to restart PlexPy?");
|
$("#confirm-message").text("Are you sure you want to restart Tautulli?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
window.location.href = "restart";
|
window.location.href = "restart";
|
||||||
|
|
|
@ -77,17 +77,16 @@ DOCUMENTATION :: END
|
||||||
<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 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('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 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 class="no-highlight" href="${anon_url('https://github.com/%s/plexpy/wiki' % plexpy.CONFIG.GIT_USER)}" target="_blank">Tautulli 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>
|
<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">Tautulli FAQ</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Support:</td>
|
<td>Support:</td>
|
||||||
<td>
|
<td>
|
||||||
<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> |
|
<a class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/36ggawe')}" target="_blank">Tautulli Discord Server</a> |
|
||||||
<a class="no-highlight support-modal-link" href="${anon_url('https://gitter.im/plexpy/general')}" target="_blank">PlexPy Gitter Chat</a> |
|
<a class="no-highlight support-modal-link" href="${anon_url('https://www.reddit.com/r/Tautulli')}" target="_blank">Tautulli Subreddit</a> |
|
||||||
<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> |
|
<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>
|
||||||
<a class="no-highlight support-modal-link" href="${anon_url('https://discord.gg/36ggawe')}" target="_blank">PlexPy Discord Server</a>
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -99,7 +98,7 @@ DOCUMENTATION :: END
|
||||||
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
|
var msg = 'Are you sure you want to install the GeoLite2 database?<br /><br />' +
|
||||||
'The database is used to lookup IP address geolocation info.<br />' +
|
'The database is used to lookup IP address geolocation info.<br />' +
|
||||||
'The database will be downloaded from <a href="${anon_url("https://dev.maxmind.com/geoip/geoip2/geolite2/")}" target="_blank">MaxMind</a>, <br />' +
|
'The database will be downloaded from <a href="${anon_url("https://dev.maxmind.com/geoip/geoip2/geolite2/")}" target="_blank">MaxMind</a>, <br />' +
|
||||||
'and requires <strong>100MB</strong> of free space to install in your PlexPy directory.<br />'
|
'and requires <strong>100MB</strong> of free space to install in your Tautulli directory.<br />'
|
||||||
var url = 'install_geoip_db';
|
var url = 'install_geoip_db';
|
||||||
confirmAjaxCall(url, msg, null, 'Installing GeoLite2 database.', getConfigurationTable);
|
confirmAjaxCall(url, msg, null, 'Installing GeoLite2 database.', getConfigurationTable);
|
||||||
});
|
});
|
||||||
|
|
|
@ -45,7 +45,7 @@ DOCUMENTATION :: END
|
||||||
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
|
<input type="text" class="form-control" id="custom_thumb_url" name="custom_thumb_url" value="${data['library_thumb']}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Change the library's picture in PlexPy. To reset to default, leave this field empty and save.</p>
|
<p class="help-block">Change the library's picture in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
|
|
|
@ -54,7 +54,7 @@ DOCUMENTATION :: END
|
||||||
<input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}">
|
<input type="text" class="form-control" id="custom_avatar_url" name="custom_avatar_url" value="${data['user_thumb']}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Change the users profile picture in PlexPy. To reset to default, leave this field empty and save.</p>
|
<p class="help-block">Change the users profile picture in Tautulli. To reset to default, leave this field empty and save.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
|
@ -72,7 +72,7 @@ DOCUMENTATION :: END
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="allow_guest" name="allow_guest" value="1" ${helpers.checked(data['allow_guest'])}> Allow Guest Access
|
<input type="checkbox" id="allow_guest" name="allow_guest" value="1" ${helpers.checked(data['allow_guest'])}> Allow Guest Access
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Uncheck this if you do not want to allow this user to login to PlexPy.</p>
|
<p class="help-block">Uncheck this if you do not want to allow this user to login to Tautulli.</p>
|
||||||
</div>
|
</div>
|
||||||
% if data['user_id']:
|
% if data['user_id']:
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -128,7 +128,7 @@
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||||
<h4 class="modal-title">PlexPy Updated</h4>
|
<h4 class="modal-title">Tautulli Updated</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
<div class='container-fluid'>
|
<div class='container-fluid'>
|
||||||
% if config['update_section_ids'] == 1:
|
% if config['update_section_ids'] == 1:
|
||||||
<div id="update_section_ids_message" style="text-align: center; margin-top: 20px;">
|
<div id="update_section_ids_message" style="text-align: center; margin-top: 20px;">
|
||||||
<i class="fa fa-exclamation-triangle"></i> PlexPy needs to update the Library IDs in your databse. Click the "<strong>Refresh libraries</strong>" button below to begin the update.
|
<i class="fa fa-exclamation-triangle"></i> Tautulli needs to update the Library IDs in your databse. Click the "<strong>Refresh libraries</strong>" button below to begin the update.
|
||||||
</div>
|
</div>
|
||||||
% elif config['update_section_ids'] == -1:
|
% elif config['update_section_ids'] == -1:
|
||||||
<div id="update_section_ids_message" style="text-align: center; margin-top: 20px;">
|
<div id="update_section_ids_message" style="text-align: center; margin-top: 20px;">
|
||||||
<i class="fa fa-refresh fa-spin"></i> PlexPy is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.
|
<i class="fa fa-refresh fa-spin"></i> Tautulli is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.
|
||||||
<br />
|
<br />
|
||||||
You may leave this page and come back later.
|
You may leave this page and come back later.
|
||||||
</div>
|
</div>
|
||||||
|
@ -199,7 +199,7 @@
|
||||||
$("#refresh-libraries-list").click(function () {
|
$("#refresh-libraries-list").click(function () {
|
||||||
if ("${config['update_section_ids']}" == "1") {
|
if ("${config['update_section_ids']}" == "1") {
|
||||||
$('#update_section_ids_message').html(
|
$('#update_section_ids_message').html(
|
||||||
'<i class="fa fa-refresh fa-spin"></i> PlexPy is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.' +
|
'<i class="fa fa-refresh fa-spin"></i> Tautulli is updating library IDs in the database. This could take a few minutes to hours depending on the size of your database.' +
|
||||||
'<br />' +
|
'<br />' +
|
||||||
'You may leave this page and come back later.');
|
'You may leave this page and come back later.');
|
||||||
$(this).prop('disabled', true);
|
$(this).prop('disabled', true);
|
||||||
|
|
|
@ -230,7 +230,7 @@ DOCUMENTATION :: END
|
||||||
% else:
|
% else:
|
||||||
<div id="get_file_sizes_message" style="text-align: center; margin-top: 20px; display: none;">
|
<div id="get_file_sizes_message" style="text-align: center; margin-top: 20px; display: none;">
|
||||||
% endif
|
% endif
|
||||||
<i class="fa fa-refresh fa-spin"></i> PlexPy is calculating the file sizes for the library's media info. This could take a few minutes depending on the size of your library.
|
<i class="fa fa-refresh fa-spin"></i> Tautulli is calculating the file sizes for the library's media info. This could take a few minutes depending on the size of your library.
|
||||||
<br />
|
<br />
|
||||||
You may leave this page and come back later.
|
You may leave this page and come back later.
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -56,8 +56,8 @@
|
||||||
<div class='table-card-back'>
|
<div class='table-card-back'>
|
||||||
<div>
|
<div>
|
||||||
<ul id="log_tabs" class="nav nav-pills" role="tablist">
|
<ul id="log_tabs" class="nav nav-pills" role="tablist">
|
||||||
<li role="presentation" class="active"><a id="plexpy-logs-btn" href="#tabs-plexpy_log" aria-controls="tabs-plexpy_log" role="tab" data-toggle="tab">PlexPy Logs</a></li>
|
<li role="presentation" class="active"><a id="plexpy-logs-btn" href="#tabs-plexpy_log" aria-controls="tabs-plexpy_log" role="tab" data-toggle="tab">Tautulli Logs</a></li>
|
||||||
<li role="presentation"><a id="plexpy-api-logs-btn" href="#tabs-plexpy_api_log" aria-controls="tabs-plexpy_api_log" role="tab" data-toggle="tab">PlexPy API Logs</a></li>
|
<li role="presentation"><a id="plexpy-api-logs-btn" href="#tabs-plexpy_api_log" aria-controls="tabs-plexpy_api_log" role="tab" data-toggle="tab">Tautulli API Logs</a></li>
|
||||||
<li role="presentation"><a id="plex-logs-btn" href="#tabs-plex_log" aria-controls="tabs-plex_log" role="tab" data-toggle="tab">Plex Media Server Logs</a></li>
|
<li role="presentation"><a id="plex-logs-btn" href="#tabs-plex_log" aria-controls="tabs-plex_log" role="tab" data-toggle="tab">Plex Media Server Logs</a></li>
|
||||||
<li role="presentation"><a id="plex-scanner-logs-btn" href="#tabs-plex_scanner_log" aria-controls="tabs-plex_scanner_log" role="tab" data-toggle="tab">Plex Media Scanner Logs</a></li>
|
<li role="presentation"><a id="plex-scanner-logs-btn" href="#tabs-plex_scanner_log" aria-controls="tabs-plex_scanner_log" role="tab" data-toggle="tab">Plex Media Scanner Logs</a></li>
|
||||||
<li role="presentation"><a id="plexpy-websocket-logs-btn" href="#tabs-plex_websocket_log" aria-controls="tabs-plex_websocket_log" role="tab" data-toggle="tab">Plex Websocket Logs</a></li>
|
<li role="presentation"><a id="plexpy-websocket-logs-btn" href="#tabs-plex_websocket_log" aria-controls="tabs-plex_websocket_log" role="tab" data-toggle="tab">Plex Websocket Logs</a></li>
|
||||||
|
@ -386,7 +386,7 @@
|
||||||
$("#clear-logs").click(function () {
|
$("#clear-logs").click(function () {
|
||||||
var logfile = $(".tab-pane.active").data('logfile')
|
var logfile = $(".tab-pane.active").data('logfile')
|
||||||
|
|
||||||
$("#confirm-message").text("Are you sure you want to clear the PlexPy logs?");
|
$("#confirm-message").text("Are you sure you want to clear the Tautulli logs?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -421,7 +421,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear-notify-logs").click(function () {
|
$("#clear-notify-logs").click(function () {
|
||||||
$("#confirm-message").text("Are you sure you want to clear the PlexPy notification logs?");
|
$("#confirm-message").text("Are you sure you want to clear the Tautulli notification logs?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
@ -442,7 +442,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear-login-logs").click(function () {
|
$("#clear-login-logs").click(function () {
|
||||||
$("#confirm-message").text("Are you sure you want to clear the PlexPy login logs?");
|
$("#confirm-message").text("Are you sure you want to clear the Tautulli login logs?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#delete-mobile-device').click(function () {
|
$('#delete-mobile-device').click(function () {
|
||||||
var msg = 'Are you sure you want to unregister the device <strong>${device["device_name"]}</strong> from PlexPy?';
|
var msg = 'Are you sure you want to unregister the device <strong>${device["device_name"]}</strong> from Tautulli?';
|
||||||
var url = 'delete_mobile_device';
|
var url = 'delete_mobile_device';
|
||||||
confirmAjaxCall(url, msg, { mobile_device_id: '${device["id"]}' }, null, deleteCallback);
|
confirmAjaxCall(url, msg, { mobile_device_id: '${device["id"]}' }, null, deleteCallback);
|
||||||
});
|
});
|
||||||
|
|
|
@ -262,7 +262,7 @@
|
||||||
<label for="test_subject">Subject Line</label>
|
<label for="test_subject">Subject Line</label>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<input class="form-control" type="text" id="test_subject" name="test_subject" value="PlexPy">
|
<input class="form-control" type="text" id="test_subject" name="test_subject" value="Tautulli">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">Set a custom subject line.</p>
|
<p class="help-block">Set a custom subject line.</p>
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<li role="presentation"><a href="#tabs-notification_agents" aria-controls="tabs-notification_agents" role="tab" data-toggle="tab">Notification Agents</a></li>
|
<li role="presentation"><a href="#tabs-notification_agents" aria-controls="tabs-notification_agents" role="tab" data-toggle="tab">Notification Agents</a></li>
|
||||||
<li role="presentation"><a href="#tabs-extra_settings" aria-controls="tabs-extra_settings" role="tab" data-toggle="tab">Extra Settings</a></li>
|
<li role="presentation"><a href="#tabs-extra_settings" aria-controls="tabs-extra_settings" role="tab" data-toggle="tab">Extra Settings</a></li>
|
||||||
<li role="presentation"><a href="#tabs-import_backups" aria-controls="tabs-import_backups" role="tab" data-toggle="tab">Import & Backups</a></li>
|
<li role="presentation"><a href="#tabs-import_backups" aria-controls="tabs-import_backups" role="tab" data-toggle="tab">Import & Backups</a></li>
|
||||||
<li role="presentation"><a href="#tabs-android_app" aria-controls="tabs-android_app" role="tab" data-toggle="tab">PlexPy Android App <sup><small>Beta</small></sup></a></li>
|
<li role="presentation"><a href="#tabs-android_app" aria-controls="tabs-android_app" role="tab" data-toggle="tab">Tautulli Remote Android App <sup><small>beta</small></sup></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
|
@ -62,14 +62,14 @@
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>PlexPy Configuration</h3>
|
<h3>Tautulli Configuration</h3>
|
||||||
</div>
|
</div>
|
||||||
<div id="plexpy-configuration-table">
|
<div id="plexpy-configuration-table">
|
||||||
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading configuration table...</div>
|
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading configuration table...</div>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>PlexPy Scheduled Tasks</h3>
|
<h3>Tautulli Scheduled Tasks</h3>
|
||||||
</div>
|
</div>
|
||||||
<div id="plexpy-scheduler-table">
|
<div id="plexpy-scheduler-table">
|
||||||
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading scheduler table...</div>
|
<div class='text-muted'><i class="fa fa-refresh fa-spin"></i> Loading scheduler table...</div>
|
||||||
|
@ -157,14 +157,14 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="check_github" name="check_github" value="1" ${config['check_github']}> Enable Updates
|
<input type="checkbox" id="check_github" name="check_github" value="1" ${config['check_github']}> Enable Updates
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Check for PlexPy updates periodically.</p>
|
<p class="help-block">Check for Tautulli updates periodically.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="git_update_options">
|
<div id="git_update_options">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="plexpy_auto_update" name="plexpy_auto_update" value="1" ${config['plexpy_auto_update']}> Update Automatically
|
<input type="checkbox" id="plexpy_auto_update" name="plexpy_auto_update" value="1" ${config['plexpy_auto_update']}> Update Automatically
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Update PlexPy automatically if an update is available.</p>
|
<p class="help-block">Update Tautulli automatically if an update is available.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="git_token">GitHub API Token</label>
|
<label for="git_token">GitHub API Token</label>
|
||||||
|
@ -362,7 +362,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" name="launch_browser" id="launch_browser" value="1" ${config['launch_browser']}> Launch Browser on Startup
|
<input type="checkbox" name="launch_browser" id="launch_browser" value="1" ${config['launch_browser']}> Launch Browser on Startup
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Launch browser pointed to PlexPy on startup.</p>
|
<p class="help-block">Launch browser pointed to Tautulli on startup.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
|
@ -375,7 +375,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" class="http-settings" name="https_create_cert" id="https_create_cert" value="1" ${config['https_create_cert']} /> Create Self-signed Certificate
|
<input type="checkbox" class="http-settings" name="https_create_cert" id="https_create_cert" value="1" ${config['https_create_cert']} /> Create Self-signed Certificate
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Check to have PlexPy create a self-signed SSL certificate. Uncheck if you want to use your own certificate.</p>
|
<p class="help-block">Check to have Tautulli create a self-signed SSL certificate. Uncheck if you want to use your own certificate.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="https_options_self-signed">
|
<div id="https_options_self-signed">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -385,7 +385,7 @@
|
||||||
<input type="text" class="form-control http-settings" id="https_domain" name="https_domain" value="${config['https_domain']}">
|
<input type="text" class="form-control http-settings" id="https_domain" name="https_domain" value="${config['https_domain']}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The domain names used to access PlexPy, separated by commas (,).</p>
|
<p class="help-block">The domain names used to access Tautulli, separated by commas (,).</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="https_ip">HTTPS IPs</label>
|
<label for="https_ip">HTTPS IPs</label>
|
||||||
|
@ -394,7 +394,7 @@
|
||||||
<input type="text" class="form-control http-settings" id="https_ip" name="https_ip" value="${config['https_ip']}">
|
<input type="text" class="form-control http-settings" id="https_ip" name="https_ip" value="${config['https_ip']}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The IP addresses used to access PlexPy, separated by commas (,).</p>
|
<p class="help-block">The IP addresses used to access Tautulli, separated by commas (,).</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -478,10 +478,10 @@
|
||||||
|
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="allow_guest_access" name="allow_guest_access" value="1" ${config['allow_guest_access']}> Allow Guest Access to PlexPy
|
<input type="checkbox" id="allow_guest_access" name="allow_guest_access" value="1" ${config['allow_guest_access']}> Allow Guest Access to Tautulli
|
||||||
</label>
|
</label>
|
||||||
<span id="allowGuestCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
<span id="allowGuestCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
||||||
<p class="help-block">Allow shared users to login to PlexPy using their Plex.tv account. Individual user access needs to be enabled from Users > Edit Mode.</p>
|
<p class="help-block">Allow shared users to login to Tautulli using their Plex.tv account. Individual user access needs to be enabled from Users > Edit Mode.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
|
@ -492,7 +492,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="api_enabled" name="api_enabled" value="1" ${config['api_enabled']}> Enable API
|
<input type="checkbox" id="api_enabled" name="api_enabled" value="1" ${config['api_enabled']}> Enable API
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Allow remote applications to interface with PlexPy.</p>
|
<p class="help-block">Allow remote applications to interface with Tautulli.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="apioptions">
|
<div id="apioptions">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -525,7 +525,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="monitor_pms_updates" name="monitor_pms_updates" value="1" ${config['monitor_pms_updates']}> Monitor Plex Updates
|
<input type="checkbox" id="monitor_pms_updates" name="monitor_pms_updates" value="1" ${config['monitor_pms_updates']}> Monitor Plex Updates
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Enable to have PlexPy check if updates are available for the Plex Media Server.</p>
|
<p class="help-block">Enable to have Tautulli check if updates are available for the Plex Media Server.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="pms_update_options">
|
<div id="pms_update_options">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -550,7 +550,7 @@
|
||||||
<input type="checkbox" id="monitor_remote_access" name="monitor_remote_access" value="1" ${config['monitor_remote_access']}> Monitor Plex Remote Access
|
<input type="checkbox" id="monitor_remote_access" name="monitor_remote_access" value="1" ${config['monitor_remote_access']}> Monitor Plex Remote Access
|
||||||
</label>
|
</label>
|
||||||
<span id="remoteAccessCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
<span id="remoteAccessCheck" style="color: #eb8600; padding-left: 10px;"></span>
|
||||||
<p class="help-block">Enable to have PlexPy check if remote access to the Plex Media Server goes down.</p>
|
<p class="help-block">Enable to have Tautulli check if remote access to the Plex Media Server goes down.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group has-feedback" id="pms-ip-group">
|
<div class="form-group has-feedback" id="pms-ip-group">
|
||||||
|
@ -583,7 +583,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="pms_is_remote" name="pms_is_remote" value="1" ${config['pms_is_remote']}> Remote Server
|
<input type="checkbox" id="pms_is_remote" name="pms_is_remote" value="1" ${config['pms_is_remote']}> Remote Server
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Check this if your Plex Server is not on the same local network as PlexPy.</p>
|
<p class="help-block">Check this if your Plex Server is not on the same local network as Tautulli.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
|
@ -626,7 +626,7 @@
|
||||||
<div id="pms_logs_folder_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="pms_logs_folder_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
Optional: Set your Plex logs folder to use PlexPy as a log viewer. Plex logs are not needed for PlexPy to function.
|
Optional: Set your Plex logs folder to use Tautulli as a log viewer. Plex logs are not needed for Tautulli to function.
|
||||||
A complete folder path is required, shortcuts are not recognized, and the logs must be accessible from the machine where PlexPy is installed.
|
A complete folder path is required, shortcuts are not recognized, and the logs must be accessible from the machine where PlexPy is installed.
|
||||||
<a href="${anon_url('https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files')}" target="_blank">Click here</a> for help.
|
<a href="${anon_url('https://support.plex.tv/hc/en-us/articles/200250417-Plex-Media-Server-Log-Files')}" target="_blank">Click here</a> for help.
|
||||||
</p>
|
</p>
|
||||||
|
@ -669,13 +669,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="refresh_users_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="refresh_users_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The interval (in hours) PlexPy will request an updated friends list from Plex.tv. Minimum 1, maximum 24, default 12.</p>
|
<p class="help-block">The interval (in hours) Tautulli will request an updated friends list from Plex.tv. Minimum 1, maximum 24, default 12.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="refresh_users_on_startup" name="refresh_users_on_startup" value="1" ${config['refresh_users_on_startup']}> Refresh Users List on Startup
|
<input type="checkbox" id="refresh_users_on_startup" name="refresh_users_on_startup" value="1" ${config['refresh_users_on_startup']}> Refresh Users List on Startup
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Refresh the users list when PlexPy starts.</p>
|
<p class="help-block">Refresh the users list when Tautulli starts.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
|
@ -690,13 +690,13 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="refresh_libraries_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="refresh_libraries_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The interval (in hours) PlexPy will request an updated libraries list from your Plex Media Server. Minimum 1, maximum 24, default 12.</p>
|
<p class="help-block">The interval (in hours) Tautulli will request an updated libraries list from your Plex Media Server. Minimum 1, maximum 24, default 12.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="refresh_libraries_on_startup" name="refresh_libraries_on_startup" value="1" ${config['refresh_libraries_on_startup']}> Refresh Libraries List on Startup
|
<input type="checkbox" id="refresh_libraries_on_startup" name="refresh_libraries_on_startup" value="1" ${config['refresh_libraries_on_startup']}> Refresh Libraries List on Startup
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Refresh the libraries list when PlexPy starts.</p>
|
<p class="help-block">Refresh the libraries list when Tautulli starts.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||||
|
@ -743,7 +743,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="buffer_wait_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="buffer_wait_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The value (in seconds) PlexPy should wait before triggering the next buffer warning. 0 to always trigger.</p>
|
<p class="help-block">The value (in seconds) Tautulli should wait before triggering the next buffer warning. 0 to always trigger.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||||
|
@ -776,7 +776,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="notify_concurrent_threshold_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="notify_concurrent_threshold_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The number of concurrent streams by a single user for PlexPy to trigger a notification. Minimum 2.</p>
|
<p class="help-block">The number of concurrent streams by a single user for Tautulli to trigger a notification. Minimum 2.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
|
@ -817,7 +817,7 @@
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
Enable to send another recently added notification when adding a new version of existing media.<br />
|
Enable to send another recently added notification when adding a new version of existing media.<br />
|
||||||
Note: If multiple versions are available, PlexPy will assume the higher quality one is newer.
|
Note: If multiple versions are available, Tautulli will assume the higher quality one is newer.
|
||||||
</p>
|
</p>
|
||||||
</div>-->
|
</div>-->
|
||||||
|
|
||||||
|
@ -894,7 +894,7 @@
|
||||||
<label>
|
<label>
|
||||||
<input type="checkbox" id="get_file_sizes" name="get_file_sizes" value="1" ${config['get_file_sizes']}> Calculate Total File Sizes <span style="color: #eb8600; padding-left: 10px;">[experimental]</span>
|
<input type="checkbox" id="get_file_sizes" name="get_file_sizes" value="1" ${config['get_file_sizes']}> Calculate Total File Sizes <span style="color: #eb8600; padding-left: 10px;">[experimental]</span>
|
||||||
</label>
|
</label>
|
||||||
<p class="help-block">Enable if you want PlexPy to calculate the total file size for TV Shows/Seasons and Artists/Albums on the media info tables.</p>
|
<p class="help-block">Enable if you want Tautulli to calculate the total file size for TV Shows/Seasons and Artists/Albums on the media info tables.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
<label>
|
<label>
|
||||||
|
@ -1009,7 +1009,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="backup_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
<div id="backup_interval_error" class="alert alert-danger settings-alert" role="alert"></div>
|
||||||
</div>
|
</div>
|
||||||
<p class="help-block">The interval (in hours) PlexPy will backup the database and configuration file. Minimum 1, maximum 24, default 6.</p>
|
<p class="help-block">The interval (in hours) Tautulli will backup the database and configuration file. Minimum 1, maximum 24, default 6.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="backup_interval">Backup Days</label>
|
<label for="backup_interval">Backup Days</label>
|
||||||
|
@ -1070,13 +1070,13 @@
|
||||||
<div role="tabpanel" class="tab-pane" id="tabs-android_app">
|
<div role="tabpanel" class="tab-pane" id="tabs-android_app">
|
||||||
|
|
||||||
<div class="padded-header">
|
<div class="padded-header">
|
||||||
<h3>PlexPy Android App</h3>
|
<h3>Tautulli Remote Android App</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Get the App</label>
|
<label>Get the App</label>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
Get the <a href="${anon_url('https://play.google.com/store/apps/details?id=com.williamcomartin.plexpyremote')}" target="_blank">PlexPy Remote</a> app on Google Play<sup>TM</sup> to access PlexPy from your Android device!<br />
|
Get the <a href="${anon_url('https://play.google.com/store/apps/details?id=com.williamcomartin.plexpyremote')}" target="_blank">Tautulli Remote</a> app on Google Play<sup>TM</sup> to access Tautulli from your Android device!<br />
|
||||||
<span class="google-play-badge">
|
<span class="google-play-badge">
|
||||||
<a href="${anon_url('https://play.google.com/store/apps/details?id=com.williamcomartin.plexpyremote')}" target="_blank"><img alt="Get it on Google Play" src="images/en-play-badge.png" /></a>
|
<a href="${anon_url('https://play.google.com/store/apps/details?id=com.williamcomartin.plexpyremote')}" target="_blank"><img alt="Get it on Google Play" src="images/en-play-badge.png" /></a>
|
||||||
</span>
|
</span>
|
||||||
|
@ -1189,7 +1189,7 @@
|
||||||
<div class="modal-body" id="modal-text">
|
<div class="modal-body" id="modal-text">
|
||||||
<div>
|
<div>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
This will attempt to fetch a new Plex.tv token for you. PlexPy does not store your username and password.
|
This will attempt to fetch a new Plex.tv token for you. Tautulli does not store your username and password.
|
||||||
Note: This will not work on Internet Explorer 9 or lower.
|
Note: This will not work on Internet Explorer 9 or lower.
|
||||||
</p>
|
</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -1421,7 +1421,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
|
<div style="text-align: center; margin-top: 20px; margin-bottom: 20px;">
|
||||||
You have changed settings that require PlexPy to restart.<br />Click the restart button below to restart now.
|
You have changed settings that require Tautulli to restart.<br />Click the restart button below to restart now.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
@ -1435,25 +1435,25 @@
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true"><i class="fa fa-remove"></i></button>
|
||||||
<h4 class="modal-title">Register PlexPy Android App</h4>
|
<h4 class="modal-title">Register Tautulli Android App</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<label>Instructions</label>
|
<label>Instructions</label>
|
||||||
<p class="help-block">
|
<p class="help-block">
|
||||||
Scan the QR code below with the PlexPy Android app to automatically register it with the server (make sure the PlexPy Address below is correct)
|
Scan the QR code below with the Tautulli Android app to automatically register it with the server (make sure the Tautulli Address below is correct)
|
||||||
or manually enter the connection info and device token into the app settings.
|
or manually enter the connection info and device token into the app settings.
|
||||||
</p>
|
</p>
|
||||||
<label>QR Code</label>
|
<label>QR Code</label>
|
||||||
<pre id="api_qr_code" style="text-align: center"></pre>
|
<pre id="api_qr_code" style="text-align: center"></pre>
|
||||||
<label>PlexPy Address</label>
|
<label>Tautulli Address</label>
|
||||||
<input type="text" class="form-control" id="api_qr_address">
|
<input type="text" class="form-control" id="api_qr_address">
|
||||||
<p class="help-block" id="api_qr_localhost" style="display: none;">
|
<p class="help-block" id="api_qr_localhost" style="display: none;">
|
||||||
Note: <span class="inline-pre">127.0.0.1</span> and <span class="inline-pre">localhost</span> will not work.
|
Note: <span class="inline-pre">127.0.0.1</span> and <span class="inline-pre">localhost</span> will not work.
|
||||||
Please enter an internal or external IP address, or hostname or domain instead.
|
Please enter an internal or external IP address, or hostname or domain instead.
|
||||||
</p>
|
</p>
|
||||||
<p class="help-block" id="api_qr_private" style="display: none;">
|
<p class="help-block" id="api_qr_private" style="display: none;">
|
||||||
Note: This is a private IP address. PlexPy will not be reachable outside of your home network.
|
Note: This is a private IP address. Tautulli will not be reachable outside of your home network.
|
||||||
Access PlexPy via an externally address or manually enter the address above to generate the QR code for remote access.
|
Access Tautulli via an externally address or manually enter the address above to generate the QR code for remote access.
|
||||||
</p>
|
</p>
|
||||||
<p class="help-block" id="api_qr_https" style="display: none;">
|
<p class="help-block" id="api_qr_https" style="display: none;">
|
||||||
Note: This URL is not secure. Requests between the app and the server will not be encrypted.
|
Note: This URL is not secure. Requests between the app and the server will not be encrypted.
|
||||||
|
@ -1491,8 +1491,6 @@
|
||||||
}
|
}
|
||||||
if ("${kwargs.get('support')}" == 'true') {
|
if ("${kwargs.get('support')}" == 'true') {
|
||||||
$('.support-modal-link').removeClass('no-highlight').css('color','#e9a049');
|
$('.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> ')
|
|
||||||
$('#best-support-link span').tooltip({ container: 'body' });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1628,7 +1626,7 @@ $(document).ready(function() {
|
||||||
initConfigCheckbox('#monitor_pms_updates');
|
initConfigCheckbox('#monitor_pms_updates');
|
||||||
|
|
||||||
$('#menu_link_shutdown').click(function() {
|
$('#menu_link_shutdown').click(function() {
|
||||||
$('#confirm-message').text("Are you sure you want to shutdown PlexPy?");
|
$('#confirm-message').text("Are you sure you want to shutdown Tautulli?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
window.location.href = 'shutdown';
|
window.location.href = 'shutdown';
|
||||||
|
@ -1636,7 +1634,7 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#menu_link_restart').click(function() {
|
$('#menu_link_restart').click(function() {
|
||||||
$("#confirm-message").text("Are you sure you want to restart PlexPy?");
|
$("#confirm-message").text("Are you sure you want to restart Tautulli?");
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
window.location.href = 'restart';
|
window.location.href = 'restart';
|
||||||
|
@ -1674,31 +1672,31 @@ $(document).ready(function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#backup_config").click(function () {
|
$("#backup_config").click(function () {
|
||||||
var msg = 'Are you sure you want to create a backup of the PlexPy config?';
|
var msg = 'Are you sure you want to create a backup of the Tautulli config?';
|
||||||
var url = 'backup_config';
|
var url = 'backup_config';
|
||||||
confirmAjaxCall(url, msg);
|
confirmAjaxCall(url, msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#backup_database").click(function () {
|
$("#backup_database").click(function () {
|
||||||
var msg = 'Are you sure you want to create a backup of the PlexPy database?';
|
var msg = 'Are you sure you want to create a backup of the Tautulli database?';
|
||||||
var url = 'backup_db';
|
var url = 'backup_db';
|
||||||
confirmAjaxCall(url, msg);
|
confirmAjaxCall(url, msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear_cache").click(function () {
|
$("#clear_cache").click(function () {
|
||||||
var msg = 'Are you sure you want to clear the PlexPy cache?';
|
var msg = 'Are you sure you want to clear the Tautulli cache?';
|
||||||
var url = 'delete_cache';
|
var url = 'delete_cache';
|
||||||
confirmAjaxCall(url, msg);
|
confirmAjaxCall(url, msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear_image_cache").click(function () {
|
$("#clear_image_cache").click(function () {
|
||||||
var msg = 'Are you sure you want to clear the PlexPy image cache?';
|
var msg = 'Are you sure you want to clear the Tautulli image cache?';
|
||||||
var url = 'delete_image_cache';
|
var url = 'delete_image_cache';
|
||||||
confirmAjaxCall(url, msg);
|
confirmAjaxCall(url, msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#clear_logs").click(function () {
|
$("#clear_logs").click(function () {
|
||||||
var msg = 'Are you sure you want to clear the PlexPy logs?';
|
var msg = 'Are you sure you want to clear the Tautulli logs?';
|
||||||
var url = 'delete_logs';
|
var url = 'delete_logs';
|
||||||
confirmAjaxCall(url, msg);
|
confirmAjaxCall(url, msg);
|
||||||
});
|
});
|
||||||
|
@ -1719,7 +1717,7 @@ $(document).ready(function() {
|
||||||
showMsg('<i class="fa fa-exclamation-circle"></i> Already on the ' + current_remote + ' ' + current_branch + ' branch.', false, true, 5000, true)
|
showMsg('<i class="fa fa-exclamation-circle"></i> Already on the ' + current_remote + ' ' + current_branch + ' branch.', false, true, 5000, true)
|
||||||
} else {
|
} else {
|
||||||
var msg = 'Are you sure you want to switch to the <strong>' + new_remote + '/' + new_branch + '</strong> branch?' +
|
var msg = 'Are you sure you want to switch to the <strong>' + new_remote + '/' + new_branch + '</strong> branch?' +
|
||||||
'<br />Switching branches may cause PlexPy to become unstable.<br /><br />PlexPy will restart.';
|
'<br />Switching branches may cause Tautulli to become unstable.<br /><br />Tautulli will restart.';
|
||||||
$('#confirm-message').html(msg);
|
$('#confirm-message').html(msg);
|
||||||
$('#confirm-modal').modal();
|
$('#confirm-modal').modal();
|
||||||
$('#confirm-modal').one('click', '#confirm-button', function () {
|
$('#confirm-modal').one('click', '#confirm-button', function () {
|
||||||
|
|
|
@ -22,10 +22,10 @@
|
||||||
<div class="modal-body" id="modal-text">
|
<div class="modal-body" id="modal-text">
|
||||||
<div align="center">
|
<div align="center">
|
||||||
% if message == "Shutting Down":
|
% if message == "Shutting Down":
|
||||||
<h3><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h3>
|
<h3><i class="fa fa-refresh fa-spin"></i> Tautulli is ${message}.</h3>
|
||||||
<br />
|
<br />
|
||||||
% else:
|
% else:
|
||||||
<h3><i class="fa fa-refresh fa-spin"></i> PlexPy is ${message}.</h3>
|
<h3><i class="fa fa-refresh fa-spin"></i> Tautulli is ${message}.</h3>
|
||||||
<br />
|
<br />
|
||||||
<h4>Restart in <span class="countdown"></span></h4>
|
<h4>Restart in <span class="countdown"></span></h4>
|
||||||
% endif
|
% endif
|
||||||
|
|
|
@ -73,11 +73,11 @@ DOCUMENTATION :: END
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
% if not update:
|
% if not update:
|
||||||
<div style="text-align: center; margin-top: 20px;">
|
<div style="text-align: center; margin-top: 20px;">
|
||||||
<i class="fa fa-exclamation-triangle"></i> PlexPy cannot find this item's metadata. Either this media item is not available in the Plex Media Server library or it has been moved.
|
<i class="fa fa-exclamation-triangle"></i> Tautulli cannot find this item's metadata. Either this media item is not available in the Plex Media Server library or it has been moved.
|
||||||
</div>
|
</div>
|
||||||
% endif
|
% endif
|
||||||
<div style="text-align: center; margin-top: 20px;">
|
<div style="text-align: center; margin-top: 20px;">
|
||||||
<i class="fa fa-info-circle"></i> Please select the correct match below to update the PlexPy database.
|
<i class="fa fa-info-circle"></i> Please select the correct match below to update the Tautulli database.
|
||||||
</div>
|
</div>
|
||||||
<div class='table-card-header'>
|
<div class='table-card-header'>
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
|
@ -116,7 +116,7 @@ DOCUMENTATION :: END
|
||||||
<div class="summary-content-wrapper">
|
<div class="summary-content-wrapper">
|
||||||
<div class='col-md-12'>
|
<div class='col-md-12'>
|
||||||
<div style="text-align: center; margin-top: 20px;">
|
<div style="text-align: center; margin-top: 20px;">
|
||||||
<i class="fa fa-exclamation-triangle"></i> PlexPy cannot find this item's metadata. Either this media item is not available in the Plex Media Server library or it has been moved.
|
<i class="fa fa-exclamation-triangle"></i> Tautulli cannot find this item's metadata. Either this media item is not available in the Plex Media Server library or it has been moved.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -66,7 +66,7 @@ DOCUMENTATION :: END
|
||||||
<li><a id="history-tab-btn" href="#userHistory" data-toggle="tab">History</a></li>
|
<li><a id="history-tab-btn" href="#userHistory" data-toggle="tab">History</a></li>
|
||||||
<li><a id="sync-tab-btn" href="#userSyncItems" data-toggle="tab">Synced Items</a></li>
|
<li><a id="sync-tab-btn" href="#userSyncItems" data-toggle="tab">Synced Items</a></li>
|
||||||
<li><a id="ip-tab-btn" href="#userAddresses" data-toggle="tab">IP Addresses</a></li>
|
<li><a id="ip-tab-btn" href="#userAddresses" data-toggle="tab">IP Addresses</a></li>
|
||||||
<li><a id="login-tab-btn" href="#userLogins" data-toggle="tab">PlexPy Logins</a></li>
|
<li><a id="login-tab-btn" href="#userLogins" data-toggle="tab">Tautulli Logins</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -278,7 +278,7 @@ DOCUMENTATION :: END
|
||||||
<div class='table-card-header'>
|
<div class='table-card-header'>
|
||||||
<div class="header-bar">
|
<div class="header-bar">
|
||||||
<span>
|
<span>
|
||||||
<i class="fa fa-sign-in"></i> PlexPy Login for <strong>
|
<i class="fa fa-sign-in"></i> Tautulli Login for <strong>
|
||||||
<span class="set-username">${data['friendly_name']}</span>
|
<span class="set-username">${data['friendly_name']}</span>
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -120,7 +120,7 @@ def swizzled_bundleIdentifier(self, original):
|
||||||
return 'ade.plexpy.osxnotify'
|
return 'ade.plexpy.osxnotify'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
notify('PlexPy', 'Test Subtitle', 'Test Body')
|
notify('Tautulli', 'Test Subtitle', 'Test Body')
|
||||||
""")
|
""")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
|
@ -170,7 +170,7 @@ def initialize(config_file):
|
||||||
notifiers.blacklist_logger()
|
notifiers.blacklist_logger()
|
||||||
mobile_app.blacklist_logger()
|
mobile_app.blacklist_logger()
|
||||||
|
|
||||||
# Check if PlexPy has a uuid
|
# Check if Tautulli has a uuid
|
||||||
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
|
if CONFIG.PMS_UUID == '' or not CONFIG.PMS_UUID:
|
||||||
my_uuid = generate_uuid()
|
my_uuid = generate_uuid()
|
||||||
CONFIG.__setattr__('PMS_UUID', my_uuid)
|
CONFIG.__setattr__('PMS_UUID', my_uuid)
|
||||||
|
@ -182,7 +182,7 @@ def initialize(config_file):
|
||||||
|
|
||||||
# Write current version to a file, so we know which version did work.
|
# Write current version to a file, so we know which version did work.
|
||||||
# This allowes one to restore to that version. The idea is that if we
|
# This allowes one to restore to that version. The idea is that if we
|
||||||
# arrive here, most parts of PlexPy seem to work.
|
# arrive here, most parts of Tautulli seem to work.
|
||||||
if CURRENT_VERSION:
|
if CURRENT_VERSION:
|
||||||
version_lock_file = os.path.join(DATA_DIR, "version.lock")
|
version_lock_file = os.path.join(DATA_DIR, "version.lock")
|
||||||
|
|
||||||
|
@ -309,9 +309,9 @@ def initialize_scheduler():
|
||||||
|
|
||||||
backup_hours = CONFIG.BACKUP_INTERVAL if 1 <= CONFIG.BACKUP_INTERVAL <= 24 else 6
|
backup_hours = CONFIG.BACKUP_INTERVAL if 1 <= CONFIG.BACKUP_INTERVAL <= 24 else 6
|
||||||
|
|
||||||
schedule_job(database.make_backup, 'Backup PlexPy database',
|
schedule_job(database.make_backup, 'Backup Tautulli database',
|
||||||
hours=backup_hours, minutes=0, seconds=0, args=(True, True))
|
hours=backup_hours, minutes=0, seconds=0, args=(True, True))
|
||||||
schedule_job(config.make_backup, 'Backup PlexPy config',
|
schedule_job(config.make_backup, 'Backup Tautulli config',
|
||||||
hours=backup_hours, minutes=0, seconds=0, args=(True, True))
|
hours=backup_hours, minutes=0, seconds=0, args=(True, True))
|
||||||
|
|
||||||
if WS_CONNECTED and CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
|
if WS_CONNECTED and CONFIG.PMS_IP and CONFIG.PMS_TOKEN:
|
||||||
|
@ -517,7 +517,7 @@ def dbcheck():
|
||||||
'deleted_section INTEGER DEFAULT 0, UNIQUE(server_id, section_id))'
|
'deleted_section INTEGER DEFAULT 0, UNIQUE(server_id, section_id))'
|
||||||
)
|
)
|
||||||
|
|
||||||
# user_login table :: This table keeps record of the PlexPy guest logins
|
# user_login table :: This table keeps record of the Tautulli guest logins
|
||||||
c_db.execute(
|
c_db.execute(
|
||||||
'CREATE TABLE IF NOT EXISTS user_login (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
'CREATE TABLE IF NOT EXISTS user_login (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||||
'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, '
|
'timestamp INTEGER, user_id INTEGER, user TEXT, user_group TEXT, '
|
||||||
|
@ -1439,28 +1439,28 @@ def shutdown(restart=False, update=False, checkout=False):
|
||||||
CONFIG.write()
|
CONFIG.write()
|
||||||
|
|
||||||
if not restart and not update and not checkout:
|
if not restart and not update and not checkout:
|
||||||
logger.info(u"PlexPy is shutting down...")
|
logger.info(u"Tautulli is shutting down...")
|
||||||
|
|
||||||
if update:
|
if update:
|
||||||
logger.info(u"PlexPy is updating...")
|
logger.info(u"Tautulli is updating...")
|
||||||
try:
|
try:
|
||||||
versioncheck.update()
|
versioncheck.update()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy failed to update: %s. Restarting." % e)
|
logger.warn(u"Tautulli failed to update: %s. Restarting." % e)
|
||||||
|
|
||||||
if checkout:
|
if checkout:
|
||||||
logger.info(u"PlexPy is switching the git branch...")
|
logger.info(u"Tautulli is switching the git branch...")
|
||||||
try:
|
try:
|
||||||
versioncheck.checkout_git_branch()
|
versioncheck.checkout_git_branch()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy failed to switch git branch: %s. Restarting." % e)
|
logger.warn(u"Tautulli failed to switch git branch: %s. Restarting." % e)
|
||||||
|
|
||||||
if CREATEPID:
|
if CREATEPID:
|
||||||
logger.info(u"Removing pidfile %s", PIDFILE)
|
logger.info(u"Removing pidfile %s", PIDFILE)
|
||||||
os.remove(PIDFILE)
|
os.remove(PIDFILE)
|
||||||
|
|
||||||
if restart:
|
if restart:
|
||||||
logger.info(u"PlexPy is restarting...")
|
logger.info(u"Tautulli is restarting...")
|
||||||
exe = sys.executable
|
exe = sys.executable
|
||||||
args = [exe, FULL_PATH]
|
args = [exe, FULL_PATH]
|
||||||
args += ARGS
|
args += ARGS
|
||||||
|
@ -1472,10 +1472,10 @@ def shutdown(restart=False, update=False, checkout=False):
|
||||||
if NOFORK:
|
if NOFORK:
|
||||||
logger.info('Running as service, not forking. Exiting...')
|
logger.info('Running as service, not forking. Exiting...')
|
||||||
elif os.name == 'nt':
|
elif os.name == 'nt':
|
||||||
logger.info('Restarting PlexPy with %s', args)
|
logger.info('Restarting Tautulli with %s', args)
|
||||||
subprocess.Popen(args, cwd=os.getcwd())
|
subprocess.Popen(args, cwd=os.getcwd())
|
||||||
else:
|
else:
|
||||||
logger.info('Restarting PlexPy with %s', args)
|
logger.info('Restarting Tautulli with %s', args)
|
||||||
os.execv(exe, args)
|
os.execv(exe, args)
|
||||||
|
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import threading
|
import threading
|
||||||
|
@ -86,7 +86,7 @@ class ActivityHandler(object):
|
||||||
if not session:
|
if not session:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s started by user %s (%s) with ratingKey %s (%s)."
|
logger.debug(u"Tautulli ActivityHandler :: Session %s started by user %s (%s) with ratingKey %s (%s)."
|
||||||
% (str(session['session_key']), str(session['user_id']), session['username'],
|
% (str(session['session_key']), str(session['user_id']), session['username'],
|
||||||
str(session['rating_key']), session['full_title']))
|
str(session['rating_key']), session['full_title']))
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
def on_stop(self, force_stop=False):
|
def on_stop(self, force_stop=False):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s stopped." % str(self.get_session_key()))
|
logger.debug(u"Tautulli ActivityHandler :: Session %s stopped." % str(self.get_session_key()))
|
||||||
|
|
||||||
# Set the session last_paused timestamp
|
# Set the session last_paused timestamp
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
|
@ -121,13 +121,13 @@ class ActivityHandler(object):
|
||||||
monitor_proc.write_session_history(session=db_session)
|
monitor_proc.write_session_history(session=db_session)
|
||||||
|
|
||||||
# Remove the session from our temp session table
|
# Remove the session from our temp session table
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Removing sessionKey %s ratingKey %s from session queue"
|
logger.debug(u"Tautulli ActivityHandler :: Removing sessionKey %s ratingKey %s from session queue"
|
||||||
% (str(self.get_session_key()), str(self.get_rating_key())))
|
% (str(self.get_session_key()), str(self.get_rating_key())))
|
||||||
ap.delete_session(session_key=self.get_session_key())
|
ap.delete_session(session_key=self.get_session_key())
|
||||||
|
|
||||||
def on_pause(self):
|
def on_pause(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s paused." % str(self.get_session_key()))
|
logger.debug(u"Tautulli ActivityHandler :: Session %s paused." % str(self.get_session_key()))
|
||||||
|
|
||||||
# Set the session last_paused timestamp
|
# Set the session last_paused timestamp
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
|
@ -146,7 +146,7 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
def on_resume(self):
|
def on_resume(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s resumed." % str(self.get_session_key()))
|
logger.debug(u"Tautulli ActivityHandler :: Session %s resumed." % str(self.get_session_key()))
|
||||||
|
|
||||||
# Set the session last_paused timestamp
|
# Set the session last_paused timestamp
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
|
@ -165,7 +165,7 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
def on_buffer(self):
|
def on_buffer(self):
|
||||||
if self.is_valid_session():
|
if self.is_valid_session():
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s is buffering." % self.get_session_key())
|
logger.debug(u"Tautulli ActivityHandler :: Session %s is buffering." % self.get_session_key())
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
db_stream = ap.get_session_by_key(session_key=self.get_session_key())
|
db_stream = ap.get_session_by_key(session_key=self.get_session_key())
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
# Get our current buffer count
|
# Get our current buffer count
|
||||||
current_buffer_count = ap.get_session_buffer_count(self.get_session_key())
|
current_buffer_count = ap.get_session_buffer_count(self.get_session_key())
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s buffer count is %s." %
|
logger.debug(u"Tautulli ActivityHandler :: Session %s buffer count is %s." %
|
||||||
(self.get_session_key(), current_buffer_count))
|
(self.get_session_key(), current_buffer_count))
|
||||||
|
|
||||||
# Get our last triggered time
|
# Get our last triggered time
|
||||||
|
@ -188,7 +188,7 @@ class ActivityHandler(object):
|
||||||
|
|
||||||
time_since_last_trigger = 0
|
time_since_last_trigger = 0
|
||||||
if buffer_last_triggered:
|
if buffer_last_triggered:
|
||||||
logger.debug(u"PlexPy ActivityHandler :: Session %s buffer last triggered at %s." %
|
logger.debug(u"Tautulli ActivityHandler :: Session %s buffer last triggered at %s." %
|
||||||
(self.get_session_key(), buffer_last_triggered))
|
(self.get_session_key(), buffer_last_triggered))
|
||||||
time_since_last_trigger = int(time.time()) - int(buffer_last_triggered)
|
time_since_last_trigger = int(time.time()) - int(buffer_last_triggered)
|
||||||
|
|
||||||
|
@ -341,7 +341,7 @@ class TimelineHandler(object):
|
||||||
|
|
||||||
RECENTLY_ADDED_QUEUE[rating_key] = set([grandparent_rating_key])
|
RECENTLY_ADDED_QUEUE[rating_key] = set([grandparent_rating_key])
|
||||||
|
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item '%s' (%s, grandparent %s) added to recently added queue."
|
logger.debug(u"Tautulli TimelineHandler :: Library item '%s' (%s, grandparent %s) added to recently added queue."
|
||||||
% (title, str(rating_key), str(grandparent_rating_key)))
|
% (title, str(rating_key), str(grandparent_rating_key)))
|
||||||
|
|
||||||
# Schedule a callback to clear the recently added queue
|
# Schedule a callback to clear the recently added queue
|
||||||
|
@ -357,7 +357,7 @@ class TimelineHandler(object):
|
||||||
parent_set.add(rating_key)
|
parent_set.add(rating_key)
|
||||||
RECENTLY_ADDED_QUEUE[parent_rating_key] = parent_set
|
RECENTLY_ADDED_QUEUE[parent_rating_key] = parent_set
|
||||||
|
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item '%s' (%s , parent %s) added to recently added queue."
|
logger.debug(u"Tautulli TimelineHandler :: Library item '%s' (%s , parent %s) added to recently added queue."
|
||||||
% (title, str(rating_key), str(parent_rating_key)))
|
% (title, str(rating_key), str(parent_rating_key)))
|
||||||
|
|
||||||
# Schedule a callback to clear the recently added queue
|
# Schedule a callback to clear the recently added queue
|
||||||
|
@ -368,7 +368,7 @@ class TimelineHandler(object):
|
||||||
queue_set = RECENTLY_ADDED_QUEUE.get(rating_key, set())
|
queue_set = RECENTLY_ADDED_QUEUE.get(rating_key, set())
|
||||||
RECENTLY_ADDED_QUEUE[rating_key] = queue_set
|
RECENTLY_ADDED_QUEUE[rating_key] = queue_set
|
||||||
|
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item '%s' (%s) added to recently added queue."
|
logger.debug(u"Tautulli TimelineHandler :: Library item '%s' (%s) added to recently added queue."
|
||||||
% (title, str(rating_key)))
|
% (title, str(rating_key)))
|
||||||
|
|
||||||
# Schedule a callback to clear the recently added queue
|
# Schedule a callback to clear the recently added queue
|
||||||
|
@ -380,13 +380,13 @@ class TimelineHandler(object):
|
||||||
state_type == 5 and metadata_state is None and queue_size is None and \
|
state_type == 5 and metadata_state is None and queue_size is None and \
|
||||||
rating_key in RECENTLY_ADDED_QUEUE:
|
rating_key in RECENTLY_ADDED_QUEUE:
|
||||||
|
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item '%s' (%s) done processing metadata."
|
logger.debug(u"Tautulli TimelineHandler :: Library item '%s' (%s) done processing metadata."
|
||||||
% (title, str(rating_key)))
|
% (title, str(rating_key)))
|
||||||
|
|
||||||
# An item was deleted, make sure it is removed from the queue
|
# An item was deleted, make sure it is removed from the queue
|
||||||
elif state_type == 9 and metadata_state == 'deleted':
|
elif state_type == 9 and metadata_state == 'deleted':
|
||||||
if rating_key in RECENTLY_ADDED_QUEUE and not RECENTLY_ADDED_QUEUE[rating_key]:
|
if rating_key in RECENTLY_ADDED_QUEUE and not RECENTLY_ADDED_QUEUE[rating_key]:
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item %s removed from recently added queue."
|
logger.debug(u"Tautulli TimelineHandler :: Library item %s removed from recently added queue."
|
||||||
% str(rating_key))
|
% str(rating_key))
|
||||||
del_keys(rating_key)
|
del_keys(rating_key)
|
||||||
|
|
||||||
|
@ -424,7 +424,7 @@ def force_stop_stream(session_key):
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
# If session is written to the databaase successfully, remove the session from the session table
|
# If session is written to the databaase successfully, remove the session from the session table
|
||||||
logger.info(u"PlexPy ActivityHandler :: Removing stale stream with sessionKey %s ratingKey %s from session queue"
|
logger.info(u"Tautulli ActivityHandler :: Removing stale stream with sessionKey %s ratingKey %s from session queue"
|
||||||
% (session['session_key'], session['rating_key']))
|
% (session['session_key'], session['rating_key']))
|
||||||
ap.delete_session(session_key=session_key)
|
ap.delete_session(session_key=session_key)
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ def force_stop_stream(session_key):
|
||||||
sessions['write_attempts'] += 1
|
sessions['write_attempts'] += 1
|
||||||
|
|
||||||
if sessions['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
|
if sessions['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
|
||||||
logger.warn(u"PlexPy ActivityHandler :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \
|
logger.warn(u"Tautulli ActivityHandler :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \
|
||||||
"Will try again in 30 seconds. Write attempt %s."
|
"Will try again in 30 seconds. Write attempt %s."
|
||||||
% (sessions['session_key'], sessions['rating_key'], str(sessions['write_attempts'])))
|
% (sessions['session_key'], sessions['rating_key'], str(sessions['write_attempts'])))
|
||||||
ap.increment_write_attempts(session_key=session_key)
|
ap.increment_write_attempts(session_key=session_key)
|
||||||
|
@ -442,10 +442,10 @@ def force_stop_stream(session_key):
|
||||||
args=[session_key], seconds=30)
|
args=[session_key], seconds=30)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Monitor :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \
|
logger.warn(u"Tautulli Monitor :: Failed to write stream with sessionKey %s ratingKey %s to the database. " \
|
||||||
"Removing session from the database. Write attempt %s."
|
"Removing session from the database. Write attempt %s."
|
||||||
% (sessions['session_key'], sessions['rating_key'], str(sessions['write_attempts'])))
|
% (sessions['session_key'], sessions['rating_key'], str(sessions['write_attempts'])))
|
||||||
logger.info(u"PlexPy Monitor :: Removing stale stream with sessionKey %s ratingKey %s from session queue"
|
logger.info(u"Tautulli Monitor :: Removing stale stream with sessionKey %s ratingKey %s from session queue"
|
||||||
% (sessions['session_key'], sessions['rating_key']))
|
% (sessions['session_key'], sessions['rating_key']))
|
||||||
ap.delete_session(session_key=session_key)
|
ap.delete_session(session_key=session_key)
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ def clear_recently_added_queue(rating_key):
|
||||||
|
|
||||||
|
|
||||||
def on_created(rating_key, **kwargs):
|
def on_created(rating_key, **kwargs):
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item %s added to Plex." % str(rating_key))
|
logger.debug(u"Tautulli TimelineHandler :: Library item %s added to Plex." % str(rating_key))
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
metadata = pms_connect.get_metadata_details(rating_key)
|
metadata = pms_connect.get_metadata_details(rating_key)
|
||||||
|
|
||||||
|
@ -488,7 +488,7 @@ def on_created(rating_key, **kwargs):
|
||||||
data_factory = datafactory.DataFactory()
|
data_factory = datafactory.DataFactory()
|
||||||
if 'child_keys' not in kwargs:
|
if 'child_keys' not in kwargs:
|
||||||
if data_factory.get_recently_added_item(rating_key):
|
if data_factory.get_recently_added_item(rating_key):
|
||||||
logger.debug(u"PlexPy TimelineHandler :: Library item %s added already. Not notifying again." % str(rating_key))
|
logger.debug(u"Tautulli TimelineHandler :: Library item %s added already. Not notifying again." % str(rating_key))
|
||||||
notify = False
|
notify = False
|
||||||
|
|
||||||
if notify:
|
if notify:
|
||||||
|
@ -506,4 +506,4 @@ def on_created(rating_key, **kwargs):
|
||||||
logger.debug(u"Added %s items to the recently_added database table." % str(len(all_keys)))
|
logger.debug(u"Added %s items to the recently_added database table." % str(len(all_keys)))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy TimelineHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
logger.error(u"Tautulli TimelineHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -41,7 +41,7 @@ def check_active_sessions(ws_request=False):
|
||||||
session_list = pms_connect.get_current_activity()
|
session_list = pms_connect.get_current_activity()
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
monitor_process = activity_processor.ActivityProcessor()
|
monitor_process = activity_processor.ActivityProcessor()
|
||||||
logger.debug(u"PlexPy Monitor :: Checking for active streams.")
|
logger.debug(u"Tautulli Monitor :: Checking for active streams.")
|
||||||
|
|
||||||
if session_list:
|
if session_list:
|
||||||
media_container = session_list['sessions']
|
media_container = session_list['sessions']
|
||||||
|
@ -59,12 +59,12 @@ def check_active_sessions(ws_request=False):
|
||||||
# Here we can check the play states
|
# Here we can check the play states
|
||||||
if session['state'] != stream['state']:
|
if session['state'] != stream['state']:
|
||||||
if session['state'] == 'paused':
|
if session['state'] == 'paused':
|
||||||
logger.debug(u"PlexPy Monitor :: Session %s paused." % stream['session_key'])
|
logger.debug(u"Tautulli Monitor :: Session %s paused." % stream['session_key'])
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_pause'})
|
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_pause'})
|
||||||
|
|
||||||
if session['state'] == 'playing' and stream['state'] == 'paused':
|
if session['state'] == 'playing' and stream['state'] == 'paused':
|
||||||
logger.debug(u"PlexPy Monitor :: Session %s resumed." % stream['session_key'])
|
logger.debug(u"Tautulli Monitor :: Session %s resumed." % stream['session_key'])
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_resume'})
|
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_resume'})
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ def check_active_sessions(ws_request=False):
|
||||||
# Push it on it's own thread so we don't hold up our db actions
|
# Push it on it's own thread so we don't hold up our db actions
|
||||||
# Our first buffer notification
|
# Our first buffer notification
|
||||||
if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
|
if buffer_values[0]['buffer_count'] == plexpy.CONFIG.BUFFER_THRESHOLD:
|
||||||
logger.info(u"PlexPy Monitor :: User '%s' has triggered a buffer warning."
|
logger.info(u"Tautulli Monitor :: User '%s' has triggered a buffer warning."
|
||||||
% stream['user'])
|
% stream['user'])
|
||||||
# Set the buffer trigger time
|
# Set the buffer trigger time
|
||||||
monitor_db.action('UPDATE sessions '
|
monitor_db.action('UPDATE sessions '
|
||||||
|
@ -110,7 +110,7 @@ def check_active_sessions(ws_request=False):
|
||||||
# Subsequent buffer notifications after wait time
|
# Subsequent buffer notifications after wait time
|
||||||
if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
|
if int(time.time()) > buffer_values[0]['buffer_last_triggered'] + \
|
||||||
plexpy.CONFIG.BUFFER_WAIT:
|
plexpy.CONFIG.BUFFER_WAIT:
|
||||||
logger.info(u"PlexPy Monitor :: User '%s' has triggered multiple buffer warnings."
|
logger.info(u"Tautulli Monitor :: User '%s' has triggered multiple buffer warnings."
|
||||||
% stream['user'])
|
% stream['user'])
|
||||||
# Set the buffer trigger time
|
# Set the buffer trigger time
|
||||||
monitor_db.action('UPDATE sessions '
|
monitor_db.action('UPDATE sessions '
|
||||||
|
@ -120,7 +120,7 @@ def check_active_sessions(ws_request=False):
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_buffer'})
|
plexpy.NOTIFY_QUEUE.put({'stream_data': stream, 'notify_action': 'on_buffer'})
|
||||||
|
|
||||||
logger.debug(u"PlexPy Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
|
logger.debug(u"Tautulli Monitor :: Session %s is buffering. Count is now %s. Last triggered %s."
|
||||||
% (stream['session_key'],
|
% (stream['session_key'],
|
||||||
buffer_values[0]['buffer_count'],
|
buffer_values[0]['buffer_count'],
|
||||||
buffer_values[0]['buffer_last_triggered']))
|
buffer_values[0]['buffer_last_triggered']))
|
||||||
|
@ -140,7 +140,7 @@ def check_active_sessions(ws_request=False):
|
||||||
else:
|
else:
|
||||||
# The user has stopped playing a stream
|
# The user has stopped playing a stream
|
||||||
if stream['state'] != 'stopped':
|
if stream['state'] != 'stopped':
|
||||||
logger.debug(u"PlexPy Monitor :: Session %s stopped." % stream['session_key'])
|
logger.debug(u"Tautulli Monitor :: Session %s stopped." % stream['session_key'])
|
||||||
|
|
||||||
if not stream['stopped']:
|
if not stream['stopped']:
|
||||||
# Set the stream stop time
|
# Set the stream stop time
|
||||||
|
@ -164,7 +164,7 @@ def check_active_sessions(ws_request=False):
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
# If session is written to the databaase successfully, remove the session from the session table
|
# If session is written to the databaase successfully, remove the session from the session table
|
||||||
logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
logger.debug(u"Tautulli Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
||||||
% (stream['session_key'], stream['rating_key']))
|
% (stream['session_key'], stream['rating_key']))
|
||||||
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
||||||
[stream['session_key'], stream['rating_key']])
|
[stream['session_key'], stream['rating_key']])
|
||||||
|
@ -172,17 +172,17 @@ def check_active_sessions(ws_request=False):
|
||||||
stream['write_attempts'] += 1
|
stream['write_attempts'] += 1
|
||||||
|
|
||||||
if stream['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
|
if stream['write_attempts'] < plexpy.CONFIG.SESSION_DB_WRITE_ATTEMPTS:
|
||||||
logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
|
logger.warn(u"Tautulli Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
|
||||||
"Will try again on the next pass. Write attempt %s."
|
"Will try again on the next pass. Write attempt %s."
|
||||||
% (stream['session_key'], stream['rating_key'], str(stream['write_attempts'])))
|
% (stream['session_key'], stream['rating_key'], str(stream['write_attempts'])))
|
||||||
monitor_db.action('UPDATE sessions SET write_attempts = ? '
|
monitor_db.action('UPDATE sessions SET write_attempts = ? '
|
||||||
'WHERE session_key = ? AND rating_key = ?',
|
'WHERE session_key = ? AND rating_key = ?',
|
||||||
[stream['write_attempts'], stream['session_key'], stream['rating_key']])
|
[stream['write_attempts'], stream['session_key'], stream['rating_key']])
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
|
logger.warn(u"Tautulli Monitor :: Failed to write sessionKey %s ratingKey %s to the database. " \
|
||||||
"Removing session from the database. Write attempt %s."
|
"Removing session from the database. Write attempt %s."
|
||||||
% (stream['session_key'], stream['rating_key'], str(stream['write_attempts'])))
|
% (stream['session_key'], stream['rating_key'], str(stream['write_attempts'])))
|
||||||
logger.debug(u"PlexPy Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
logger.debug(u"Tautulli Monitor :: Removing sessionKey %s ratingKey %s from session queue"
|
||||||
% (stream['session_key'], stream['rating_key']))
|
% (stream['session_key'], stream['rating_key']))
|
||||||
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
monitor_db.action('DELETE FROM sessions WHERE session_key = ? AND rating_key = ?',
|
||||||
[stream['session_key'], stream['rating_key']])
|
[stream['session_key'], stream['rating_key']])
|
||||||
|
@ -193,11 +193,11 @@ def check_active_sessions(ws_request=False):
|
||||||
new_session = monitor_process.write_session(session)
|
new_session = monitor_process.write_session(session)
|
||||||
|
|
||||||
if new_session:
|
if new_session:
|
||||||
logger.debug(u"PlexPy Monitor :: Session %s started by user %s with ratingKey %s."
|
logger.debug(u"Tautulli Monitor :: Session %s started by user %s with ratingKey %s."
|
||||||
% (session['session_key'], session['user_id'], session['rating_key']))
|
% (session['session_key'], session['user_id'], session['rating_key']))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Monitor :: Unable to read session list.")
|
logger.debug(u"Tautulli Monitor :: Unable to read session list.")
|
||||||
|
|
||||||
|
|
||||||
def check_recently_added():
|
def check_recently_added():
|
||||||
|
@ -229,13 +229,13 @@ def check_recently_added():
|
||||||
if metadata:
|
if metadata:
|
||||||
metadata = [metadata]
|
metadata = [metadata]
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Monitor :: Unable to retrieve metadata for rating_key %s" \
|
logger.error(u"Tautulli Monitor :: Unable to retrieve metadata for rating_key %s" \
|
||||||
% str(item['rating_key']))
|
% str(item['rating_key']))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
metadata = pms_connect.get_metadata_children_details(item['rating_key'])
|
metadata = pms_connect.get_metadata_children_details(item['rating_key'])
|
||||||
if not metadata:
|
if not metadata:
|
||||||
logger.error(u"PlexPy Monitor :: Unable to retrieve children metadata for rating_key %s" \
|
logger.error(u"Tautulli Monitor :: Unable to retrieve children metadata for rating_key %s" \
|
||||||
% str(item['rating_key']))
|
% str(item['rating_key']))
|
||||||
|
|
||||||
if metadata:
|
if metadata:
|
||||||
|
@ -246,7 +246,7 @@ def check_recently_added():
|
||||||
library_details = library_data.get_details(section_id=item['section_id'])
|
library_details = library_data.get_details(section_id=item['section_id'])
|
||||||
|
|
||||||
if 0 < time_threshold - int(item['added_at']) <= time_interval:
|
if 0 < time_threshold - int(item['added_at']) <= time_interval:
|
||||||
logger.debug(u"PlexPy Monitor :: Library item %s added to Plex." % str(item['rating_key']))
|
logger.debug(u"Tautulli Monitor :: Library item %s added to Plex." % str(item['rating_key']))
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'timeline_data': item, 'notify_action': 'on_created'})
|
plexpy.NOTIFY_QUEUE.put({'timeline_data': item, 'notify_action': 'on_created'})
|
||||||
|
|
||||||
|
@ -260,17 +260,17 @@ def check_recently_added():
|
||||||
if metadata:
|
if metadata:
|
||||||
item = metadata
|
item = metadata
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Monitor :: Unable to retrieve grandparent metadata for grandparent_rating_key %s" \
|
logger.error(u"Tautulli Monitor :: Unable to retrieve grandparent metadata for grandparent_rating_key %s" \
|
||||||
% str(item['rating_key']))
|
% str(item['rating_key']))
|
||||||
|
|
||||||
logger.debug(u"PlexPy Monitor :: Library item %s added to Plex." % str(item['rating_key']))
|
logger.debug(u"Tautulli Monitor :: Library item %s added to Plex." % str(item['rating_key']))
|
||||||
|
|
||||||
# Check if any notification agents have notifications enabled
|
# Check if any notification agents have notifications enabled
|
||||||
plexpy.NOTIFY_QUEUE.put({'timeline_data': item, 'notify_action': 'on_created'})
|
plexpy.NOTIFY_QUEUE.put({'timeline_data': item, 'notify_action': 'on_created'})
|
||||||
|
|
||||||
|
|
||||||
def check_server_response():
|
def check_server_response():
|
||||||
logger.info(u"PlexPy Monitor :: Attempting to reconnect Plex server...")
|
logger.info(u"Tautulli Monitor :: Attempting to reconnect Plex server...")
|
||||||
try:
|
try:
|
||||||
web_socket.start_thread()
|
web_socket.start_thread()
|
||||||
except:
|
except:
|
||||||
|
@ -294,17 +294,17 @@ def check_server_access():
|
||||||
# Check if the port is mapped
|
# Check if the port is mapped
|
||||||
if not mapping_state == 'mapped':
|
if not mapping_state == 'mapped':
|
||||||
ext_ping_count += 1
|
ext_ping_count += 1
|
||||||
logger.warn(u"PlexPy Monitor :: Plex remote access port not mapped, ping attempt %s." \
|
logger.warn(u"Tautulli Monitor :: Plex remote access port not mapped, ping attempt %s." \
|
||||||
% str(ext_ping_count))
|
% str(ext_ping_count))
|
||||||
# Check if the port is open
|
# Check if the port is open
|
||||||
elif mapping_error == 'unreachable':
|
elif mapping_error == 'unreachable':
|
||||||
ext_ping_count += 1
|
ext_ping_count += 1
|
||||||
logger.warn(u"PlexPy Monitor :: Plex remote access port mapped, but mapping failed, ping attempt %s." \
|
logger.warn(u"Tautulli Monitor :: Plex remote access port mapped, but mapping failed, ping attempt %s." \
|
||||||
% str(ext_ping_count))
|
% str(ext_ping_count))
|
||||||
# Reset external ping counter
|
# Reset external ping counter
|
||||||
else:
|
else:
|
||||||
if ext_ping_count >= plexpy.CONFIG.REMOTE_ACCESS_PING_THRESHOLD:
|
if ext_ping_count >= plexpy.CONFIG.REMOTE_ACCESS_PING_THRESHOLD:
|
||||||
logger.info(u"PlexPy Monitor :: Plex remote access is back up.")
|
logger.info(u"Tautulli Monitor :: Plex remote access is back up.")
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extup'})
|
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_extup'})
|
||||||
|
|
||||||
|
@ -317,18 +317,18 @@ def check_server_access():
|
||||||
def check_server_updates():
|
def check_server_updates():
|
||||||
|
|
||||||
with monitor_lock:
|
with monitor_lock:
|
||||||
logger.info(u"PlexPy Monitor :: Checking for PMS updates...")
|
logger.info(u"Tautulli Monitor :: Checking for PMS updates...")
|
||||||
|
|
||||||
plex_tv = plextv.PlexTV()
|
plex_tv = plextv.PlexTV()
|
||||||
download_info = plex_tv.get_plex_downloads()
|
download_info = plex_tv.get_plex_downloads()
|
||||||
|
|
||||||
if download_info:
|
if download_info:
|
||||||
logger.info(u"PlexPy Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION)
|
logger.info(u"Tautulli Monitor :: Current PMS version: %s", plexpy.CONFIG.PMS_VERSION)
|
||||||
|
|
||||||
if download_info['update_available']:
|
if download_info['update_available']:
|
||||||
logger.info(u"PlexPy Monitor :: PMS update available version: %s", download_info['version'])
|
logger.info(u"Tautulli Monitor :: PMS update available version: %s", download_info['version'])
|
||||||
|
|
||||||
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
|
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_pmsupdate', 'pms_download_info': download_info})
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.info(u"PlexPy Monitor :: No PMS update available.")
|
logger.info(u"Tautulli Monitor :: No PMS update available.")
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
|
@ -172,7 +172,7 @@ class ActivityProcessor(object):
|
||||||
if str(session['rating_key']).isdigit() and session['media_type'] in ('movie', 'episode', 'track'):
|
if str(session['rating_key']).isdigit() and session['media_type'] in ('movie', 'episode', 'track'):
|
||||||
logging_enabled = True
|
logging_enabled = True
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: ratingKey %s not logged. Does not meet logging criteria. "
|
logger.debug(u"Tautulli ActivityProcessor :: ratingKey %s not logged. Does not meet logging criteria. "
|
||||||
u"Media type is '%s'" % (session['rating_key'], session['media_type']))
|
u"Media type is '%s'" % (session['rating_key'], session['media_type']))
|
||||||
|
|
||||||
if str(session['paused_counter']).isdigit():
|
if str(session['paused_counter']).isdigit():
|
||||||
|
@ -184,35 +184,35 @@ class ActivityProcessor(object):
|
||||||
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
||||||
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
|
(real_play_time < int(plexpy.CONFIG.LOGGING_IGNORE_INTERVAL)):
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
logger.debug(u"Tautulli ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
||||||
u"seconds, so we're not logging it." %
|
u"seconds, so we're not logging it." %
|
||||||
(session['rating_key'], str(real_play_time), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
|
(session['rating_key'], str(real_play_time), plexpy.CONFIG.LOGGING_IGNORE_INTERVAL))
|
||||||
if not is_import and session['media_type'] == 'track':
|
if not is_import and session['media_type'] == 'track':
|
||||||
if real_play_time < 15 and session['duration'] >= 30:
|
if real_play_time < 15 and session['duration'] >= 30:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs, "
|
logger.debug(u"Tautulli ActivityProcessor :: Play duration for ratingKey %s is %s secs, "
|
||||||
u"looks like it was skipped so we're not logging it" %
|
u"looks like it was skipped so we're not logging it" %
|
||||||
(session['rating_key'], str(real_play_time)))
|
(session['rating_key'], str(real_play_time)))
|
||||||
elif is_import and import_ignore_interval:
|
elif is_import and import_ignore_interval:
|
||||||
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
if (session['media_type'] == 'movie' or session['media_type'] == 'episode') and \
|
||||||
(real_play_time < int(import_ignore_interval)):
|
(real_play_time < int(import_ignore_interval)):
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
logger.debug(u"Tautulli ActivityProcessor :: Play duration for ratingKey %s is %s secs which is less than %s "
|
||||||
u"seconds, so we're not logging it." %
|
u"seconds, so we're not logging it." %
|
||||||
(session['rating_key'], str(real_play_time), import_ignore_interval))
|
(session['rating_key'], str(real_play_time), import_ignore_interval))
|
||||||
|
|
||||||
if not is_import and not user_details['keep_history']:
|
if not is_import and not user_details['keep_history']:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: History logging for user '%s' is disabled." % user_details['username'])
|
logger.debug(u"Tautulli ActivityProcessor :: History logging for user '%s' is disabled." % user_details['username'])
|
||||||
elif not is_import and not library_details['keep_history']:
|
elif not is_import and not library_details['keep_history']:
|
||||||
logging_enabled = False
|
logging_enabled = False
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: History logging for library '%s' is disabled." % library_details['section_name'])
|
logger.debug(u"Tautulli ActivityProcessor :: History logging for library '%s' is disabled." % library_details['section_name'])
|
||||||
|
|
||||||
if logging_enabled:
|
if logging_enabled:
|
||||||
|
|
||||||
# Fetch metadata first so we can return false if it fails
|
# Fetch metadata first so we can return false if it fails
|
||||||
if not is_import:
|
if not is_import:
|
||||||
logger.debug(u"PlexPy ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
logger.debug(u"Tautulli ActivityProcessor :: Fetching metadata for item ratingKey %s" % session['rating_key'])
|
||||||
pms_connect = pmsconnect.PmsConnect()
|
pms_connect = pmsconnect.PmsConnect()
|
||||||
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
metadata = pms_connect.get_metadata_details(rating_key=str(session['rating_key']))
|
||||||
if not metadata:
|
if not metadata:
|
||||||
|
@ -226,7 +226,7 @@ class ActivityProcessor(object):
|
||||||
## TODO: Fix media info from imports. Temporary media info from import session.
|
## TODO: Fix media info from imports. Temporary media info from import session.
|
||||||
media_info = session
|
media_info = session
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history table...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Attempting to write to session_history table...")
|
||||||
keys = {'id': None}
|
keys = {'id': None}
|
||||||
values = {'started': session['started'],
|
values = {'started': session['started'],
|
||||||
'stopped': stopped,
|
'stopped': stopped,
|
||||||
|
@ -251,7 +251,7 @@ class ActivityProcessor(object):
|
||||||
'view_offset': session['view_offset']
|
'view_offset': session['view_offset']
|
||||||
}
|
}
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history transaction...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Writing session_history transaction...")
|
||||||
self.db.upsert(table_name='session_history', key_dict=keys, value_dict=values)
|
self.db.upsert(table_name='session_history', key_dict=keys, value_dict=values)
|
||||||
|
|
||||||
# Check if we should group the session, select the last two rows from the user
|
# Check if we should group the session, select the last two rows from the user
|
||||||
|
@ -290,12 +290,12 @@ class ActivityProcessor(object):
|
||||||
|
|
||||||
self.db.action(query=query, args=args)
|
self.db.action(query=query, args=args)
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Successfully written history item, last id for session_history is %s"
|
# logger.debug(u"Tautulli ActivityProcessor :: Successfully written history item, last id for session_history is %s"
|
||||||
# % last_id)
|
# % last_id)
|
||||||
|
|
||||||
# Write the session_history_media_info table
|
# Write the session_history_media_info table
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history_media_info table...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Attempting to write to session_history_media_info table...")
|
||||||
keys = {'id': last_id}
|
keys = {'id': last_id}
|
||||||
values = {'rating_key': session['rating_key'],
|
values = {'rating_key': session['rating_key'],
|
||||||
'video_decision': session['video_decision'],
|
'video_decision': session['video_decision'],
|
||||||
|
@ -357,7 +357,7 @@ class ActivityProcessor(object):
|
||||||
'optimized_version_profile': session['optimized_version_profile']
|
'optimized_version_profile': session['optimized_version_profile']
|
||||||
}
|
}
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_media_info transaction...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Writing session_history_media_info transaction...")
|
||||||
self.db.upsert(table_name='session_history_media_info', key_dict=keys, value_dict=values)
|
self.db.upsert(table_name='session_history_media_info', key_dict=keys, value_dict=values)
|
||||||
|
|
||||||
# Write the session_history_metadata table
|
# Write the session_history_metadata table
|
||||||
|
@ -367,7 +367,7 @@ class ActivityProcessor(object):
|
||||||
genres = ";".join(metadata['genres'])
|
genres = ";".join(metadata['genres'])
|
||||||
labels = ";".join(metadata['labels'])
|
labels = ";".join(metadata['labels'])
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Attempting to write to session_history_metadata table...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Attempting to write to session_history_metadata table...")
|
||||||
keys = {'id': last_id}
|
keys = {'id': last_id}
|
||||||
values = {'rating_key': session['rating_key'],
|
values = {'rating_key': session['rating_key'],
|
||||||
'parent_rating_key': session['parent_rating_key'],
|
'parent_rating_key': session['parent_rating_key'],
|
||||||
|
@ -403,7 +403,7 @@ class ActivityProcessor(object):
|
||||||
'labels': labels
|
'labels': labels
|
||||||
}
|
}
|
||||||
|
|
||||||
# logger.debug(u"PlexPy ActivityProcessor :: Writing session_history_metadata transaction...")
|
# logger.debug(u"Tautulli ActivityProcessor :: Writing session_history_metadata transaction...")
|
||||||
self.db.upsert(table_name='session_history_metadata', key_dict=keys, value_dict=values)
|
self.db.upsert(table_name='session_history_metadata', key_dict=keys, value_dict=values)
|
||||||
|
|
||||||
# Return true when the session is successfully written to the database
|
# Return true when the session is successfully written to the database
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
|
@ -129,15 +129,15 @@ class API2:
|
||||||
self._api_kwargs = kwargs
|
self._api_kwargs = kwargs
|
||||||
|
|
||||||
if self._api_msg:
|
if self._api_msg:
|
||||||
logger.api_debug(u'PlexPy APIv2 :: %s.' % self._api_msg)
|
logger.api_debug(u'Tautulli APIv2 :: %s.' % self._api_msg)
|
||||||
|
|
||||||
logger.api_debug(u'PlexPy APIv2 :: Cleaned kwargs: %s' % self._api_kwargs)
|
logger.api_debug(u'Tautulli APIv2 :: Cleaned kwargs: %s' % self._api_kwargs)
|
||||||
|
|
||||||
return self._api_kwargs
|
return self._api_kwargs
|
||||||
|
|
||||||
def get_logs(self, sort='', search='', order='desc', regex='', start=0, end=0, **kwargs):
|
def get_logs(self, sort='', search='', order='desc', regex='', start=0, end=0, **kwargs):
|
||||||
"""
|
"""
|
||||||
Get the PlexPy logs.
|
Get the Tautulli logs.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -169,7 +169,7 @@ class API2:
|
||||||
end = int(kwargs.get('end', 0))
|
end = int(kwargs.get('end', 0))
|
||||||
|
|
||||||
if regex:
|
if regex:
|
||||||
logger.api_debug(u'PlexPy APIv2 :: Filtering log using regex %s' % regex)
|
logger.api_debug(u'Tautulli APIv2 :: Filtering log using regex %s' % regex)
|
||||||
reg = re.compile('u' + regex, flags=re.I)
|
reg = re.compile('u' + regex, flags=re.I)
|
||||||
|
|
||||||
for line in open(logfile, 'r').readlines():
|
for line in open(logfile, 'r').readlines():
|
||||||
|
@ -201,15 +201,15 @@ class API2:
|
||||||
templog.append(d)
|
templog.append(d)
|
||||||
|
|
||||||
if end > 0 or start > 0:
|
if end > 0 or start > 0:
|
||||||
logger.api_debug(u'PlexPy APIv2 :: Slicing the log from %s to %s' % (start, end))
|
logger.api_debug(u'Tautulli APIv2 :: Slicing the log from %s to %s' % (start, end))
|
||||||
templog = templog[start:end]
|
templog = templog[start:end]
|
||||||
|
|
||||||
if sort:
|
if sort:
|
||||||
logger.api_debug(u'PlexPy APIv2 :: Sorting log based on %s' % sort)
|
logger.api_debug(u'Tautulli APIv2 :: Sorting log based on %s' % sort)
|
||||||
templog = sorted(templog, key=lambda k: k[sort])
|
templog = sorted(templog, key=lambda k: k[sort])
|
||||||
|
|
||||||
if search:
|
if search:
|
||||||
logger.api_debug(u'PlexPy APIv2 :: Searching log values for %s' % search)
|
logger.api_debug(u'Tautulli APIv2 :: Searching log values for %s' % search)
|
||||||
tt = [d for d in templog for k, v in d.items() if search.lower() in v.lower()]
|
tt = [d for d in templog for k, v in d.items() if search.lower() in v.lower()]
|
||||||
|
|
||||||
if len(tt):
|
if len(tt):
|
||||||
|
@ -276,7 +276,7 @@ class API2:
|
||||||
return config
|
return config
|
||||||
|
|
||||||
def sql(self, query=''):
|
def sql(self, query=''):
|
||||||
""" Query the PlexPy database with raw SQL. Automatically makes a backup of
|
""" Query the Tautulli database with raw SQL. Automatically makes a backup of
|
||||||
the database if the latest backup is older then 24h. `api_sql` must be
|
the database if the latest backup is older then 24h. `api_sql` must be
|
||||||
manually enabled in the config file.
|
manually enabled in the config file.
|
||||||
|
|
||||||
|
@ -330,40 +330,40 @@ class API2:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def restart(self, **kwargs):
|
def restart(self, **kwargs):
|
||||||
""" Restart PlexPy."""
|
""" Restart Tautulli."""
|
||||||
|
|
||||||
plexpy.SIGNAL = 'restart'
|
plexpy.SIGNAL = 'restart'
|
||||||
self._api_msg = 'Restarting plexpy'
|
self._api_msg = 'Restarting plexpy'
|
||||||
self._api_result_type = 'success'
|
self._api_result_type = 'success'
|
||||||
|
|
||||||
def update(self, **kwargs):
|
def update(self, **kwargs):
|
||||||
""" Check for PlexPy updates on Github."""
|
""" Check for Tautulli updates on Github."""
|
||||||
|
|
||||||
plexpy.SIGNAL = 'update'
|
plexpy.SIGNAL = 'update'
|
||||||
self._api_msg = 'Updating plexpy'
|
self._api_msg = 'Updating plexpy'
|
||||||
self._api_result_type = 'success'
|
self._api_result_type = 'success'
|
||||||
|
|
||||||
def refresh_libraries_list(self, **kwargs):
|
def refresh_libraries_list(self, **kwargs):
|
||||||
""" Refresh the PlexPy libraries list."""
|
""" Refresh the Tautulli libraries list."""
|
||||||
data = pmsconnect.refresh_libraries()
|
data = pmsconnect.refresh_libraries()
|
||||||
self._api_result_type = 'success' if data else 'error'
|
self._api_result_type = 'success' if data else 'error'
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def refresh_users_list(self, **kwargs):
|
def refresh_users_list(self, **kwargs):
|
||||||
""" Refresh the PlexPy users list."""
|
""" Refresh the Tautulli users list."""
|
||||||
data = plextv.refresh_users()
|
data = plextv.refresh_users()
|
||||||
self._api_result_type = 'success' if data else 'error'
|
self._api_result_type = 'success' if data else 'error'
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def register_device(self, device_id='', device_name='', friendly_name='', **kwargs):
|
def register_device(self, device_id='', device_name='', friendly_name='', **kwargs):
|
||||||
""" Registers the PlexPy Android App for notifications.
|
""" Registers the Tautulli Android App for notifications.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
device_name (str): The device name of the PlexPy Android App
|
device_name (str): The device name of the Tautulli Android App
|
||||||
device_id (str): The OneSignal device id of the PlexPy Android App
|
device_id (str): The OneSignal device id of the Tautulli Android App
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
friendly_name (str): A friendly name to identify the mobile device
|
friendly_name (str): A friendly name to identify the mobile device
|
||||||
|
@ -453,8 +453,8 @@ General optional parameters:
|
||||||
None
|
None
|
||||||
|
|
||||||
Optional parameters:
|
Optional parameters:
|
||||||
username (str): Your PlexPy username
|
username (str): Your Tautulli username
|
||||||
password (str): Your PlexPy password
|
password (str): Your Tautulli password
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
string: "apikey"
|
string: "apikey"
|
||||||
|
@ -517,7 +517,7 @@ General optional parameters:
|
||||||
out = self._api_callback + '(' + out + ');'
|
out = self._api_callback + '(' + out + ');'
|
||||||
# if we fail to generate the output fake an error
|
# if we fail to generate the output fake an error
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.api_exception(u'PlexPy APIv2 :: ' + traceback.format_exc())
|
logger.api_exception(u'Tautulli APIv2 :: ' + traceback.format_exc())
|
||||||
out['message'] = traceback.format_exc()
|
out['message'] = traceback.format_exc()
|
||||||
out['result'] = 'error'
|
out['result'] = 'error'
|
||||||
|
|
||||||
|
@ -526,14 +526,14 @@ General optional parameters:
|
||||||
try:
|
try:
|
||||||
out = xmltodict.unparse(out, pretty=True)
|
out = xmltodict.unparse(out, pretty=True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.api_error(u'PlexPy APIv2 :: Failed to parse xml result')
|
logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result')
|
||||||
try:
|
try:
|
||||||
out['message'] = e
|
out['message'] = e
|
||||||
out['result'] = 'error'
|
out['result'] = 'error'
|
||||||
out = xmltodict.unparse(out, pretty=True)
|
out = xmltodict.unparse(out, pretty=True)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.api_error(u'PlexPy APIv2 :: Failed to parse xml result error message %s' % e)
|
logger.api_error(u'Tautulli APIv2 :: Failed to parse xml result error message %s' % e)
|
||||||
out = '''<?xml version="1.0" encoding="utf-8"?>
|
out = '''<?xml version="1.0" encoding="utf-8"?>
|
||||||
<response>
|
<response>
|
||||||
<message>%s</message>
|
<message>%s</message>
|
||||||
|
@ -548,7 +548,7 @@ General optional parameters:
|
||||||
""" handles the stuff from the handler """
|
""" handles the stuff from the handler """
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
logger.api_debug(u'PlexPy APIv2 :: API called with kwargs: %s' % kwargs)
|
logger.api_debug(u'Tautulli APIv2 :: API called with kwargs: %s' % kwargs)
|
||||||
|
|
||||||
self._api_validate(**kwargs)
|
self._api_validate(**kwargs)
|
||||||
|
|
||||||
|
@ -566,7 +566,7 @@ General optional parameters:
|
||||||
|
|
||||||
result = call(**self._api_kwargs)
|
result = call(**self._api_kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.api_error(u'PlexPy APIv2 :: Failed to run %s with %s: %s' % (self._api_cmd, self._api_kwargs, e))
|
logger.api_error(u'Tautulli APIv2 :: Failed to run %s with %s: %s' % (self._api_cmd, self._api_kwargs, e))
|
||||||
if self._api_debug:
|
if self._api_debug:
|
||||||
cherrypy.request.show_tracebacks = True
|
cherrypy.request.show_tracebacks = True
|
||||||
# Reraise the exception so the traceback hits the browser
|
# Reraise the exception so the traceback hits the browser
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
## Stolen from Sick-Beard's classes.py ##
|
## Stolen from Sick-Beard's classes.py ##
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Created on Aug 1, 2011
|
Created on Aug 1, 2011
|
||||||
|
@ -24,7 +24,7 @@ from collections import OrderedDict
|
||||||
import version
|
import version
|
||||||
|
|
||||||
# Identify Our Application
|
# Identify Our Application
|
||||||
USER_AGENT = 'PlexPy/-' + version.PLEXPY_BRANCH + ' v' + version.PLEXPY_RELEASE_VERSION + ' (' + platform.system() + \
|
USER_AGENT = 'Tautulli/-' + version.PLEXPY_BRANCH + ' v' + version.PLEXPY_RELEASE_VERSION + ' (' + platform.system() + \
|
||||||
' ' + platform.release() + ')'
|
' ' + platform.release() + ')'
|
||||||
|
|
||||||
PLATFORM = platform.system()
|
PLATFORM = platform.system()
|
||||||
|
@ -148,8 +148,8 @@ SCHEDULER_LIST = ['Check GitHub for updates',
|
||||||
'Refresh libraries list',
|
'Refresh libraries list',
|
||||||
'Refresh Plex server URLs',
|
'Refresh Plex server URLs',
|
||||||
'Refresh Plex server name',
|
'Refresh Plex server name',
|
||||||
'Backup PlexPy database',
|
'Backup Tautulli database',
|
||||||
'Backup PlexPy config'
|
'Backup Tautulli config'
|
||||||
]
|
]
|
||||||
|
|
||||||
DATE_TIME_FORMATS = [
|
DATE_TIME_FORMATS = [
|
||||||
|
@ -234,9 +234,9 @@ NOTIFICATION_PARAMETERS = [
|
||||||
{
|
{
|
||||||
'category': 'Global',
|
'category': 'Global',
|
||||||
'parameters': [
|
'parameters': [
|
||||||
{'name': 'PlexPy Version', 'type': 'str', 'value': 'plexpy_version', 'description': 'The current version of PlexPy.'},
|
{'name': 'Tautulli Version', 'type': 'str', 'value': 'plexpy_version', 'description': 'The current version of Tautulli.'},
|
||||||
{'name': 'PlexPy Branch', 'type': 'str', 'value': 'plexpy_branch', 'description': 'The current git branch of PlexPy.'},
|
{'name': 'Tautulli Branch', 'type': 'str', 'value': 'plexpy_branch', 'description': 'The current git branch of Tautulli.'},
|
||||||
{'name': 'PlexPy Commit', 'type': 'str', 'value': 'plexpy_commit', 'description': 'The current git commit hash of PlexPy.'},
|
{'name': 'Tautulli Commit', 'type': 'str', 'value': 'plexpy_commit', 'description': 'The current git commit hash of Tautulli.'},
|
||||||
{'name': 'Server Name', 'type': 'str', 'value': 'server_name', 'description': 'The name of your Plex Server.'},
|
{'name': 'Server Name', 'type': 'str', 'value': 'server_name', 'description': 'The name of your Plex Server.'},
|
||||||
{'name': 'Server Uptime', 'type': 'str', 'value': 'server_uptime', 'description': 'The uptime (in days, hours, mins, secs) of your Plex Server.'},
|
{'name': 'Server Uptime', 'type': 'str', 'value': 'server_uptime', 'description': 'The uptime (in days, hours, mins, secs) of your Plex Server.'},
|
||||||
{'name': 'Server Version', 'type': 'str', 'value': 'server_version', 'description': 'The current version of your Plex Server.'},
|
{'name': 'Server Version', 'type': 'str', 'value': 'server_version', 'description': 'The current version of your Plex Server.'},
|
||||||
|
@ -424,9 +424,9 @@ NOTIFICATION_PARAMETERS = [
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'category': 'PlexPy Update Available',
|
'category': 'Tautulli Update Available',
|
||||||
'parameters': [
|
'parameters': [
|
||||||
{'name': 'Plexpy Update Version', 'type': 'int', 'value': 'plexpy_update_version', 'description': 'The available update version for PlexPy.'},
|
{'name': 'Plexpy Update Version', 'type': 'int', 'value': 'plexpy_update_version', 'description': 'The available update version for Tautulli.'},
|
||||||
{'name': 'Plexpy Update Tar', 'type': 'int', 'value': 'plexpy_update_tar', 'description': 'The tar download URL for the available update.'},
|
{'name': 'Plexpy Update Tar', 'type': 'int', 'value': 'plexpy_update_tar', 'description': 'The tar download URL for the available update.'},
|
||||||
{'name': 'Plexpy Update Zip', 'type': 'int', 'value': 'plexpy_update_zip', 'description': 'The zip download URL for the available update.'},
|
{'name': 'Plexpy Update Zip', 'type': 'int', 'value': 'plexpy_update_zip', 'description': 'The zip download URL for the available update.'},
|
||||||
{'name': 'Plexpy Update Commit', 'type': 'int', 'value': 'plexpy_update_commit', 'description': 'The commit hash for the available update.'},
|
{'name': 'Plexpy Update Commit', 'type': 'int', 'value': 'plexpy_update_commit', 'description': 'The commit hash for the available update.'},
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import os
|
import os
|
||||||
|
@ -117,7 +117,7 @@ _CONFIG_DEFINITIONS = {
|
||||||
'CONFIG_VERSION': (int, 'Advanced', 0),
|
'CONFIG_VERSION': (int, 'Advanced', 0),
|
||||||
'DO_NOT_OVERRIDE_GIT_BRANCH': (int, 'General', 0),
|
'DO_NOT_OVERRIDE_GIT_BRANCH': (int, 'General', 0),
|
||||||
'EMAIL_ENABLED': (int, 'Email', 0),
|
'EMAIL_ENABLED': (int, 'Email', 0),
|
||||||
'EMAIL_FROM_NAME': (str, 'Email', 'PlexPy'),
|
'EMAIL_FROM_NAME': (str, 'Email', 'Tautulli'),
|
||||||
'EMAIL_FROM': (str, 'Email', ''),
|
'EMAIL_FROM': (str, 'Email', ''),
|
||||||
'EMAIL_TO': (str, 'Email', ''),
|
'EMAIL_TO': (str, 'Email', ''),
|
||||||
'EMAIL_CC': (str, 'Email', ''),
|
'EMAIL_CC': (str, 'Email', ''),
|
||||||
|
@ -333,36 +333,36 @@ _CONFIG_DEFINITIONS = {
|
||||||
'NOTIFY_CONCURRENT_BY_IP': (int, 'Monitoring', 0),
|
'NOTIFY_CONCURRENT_BY_IP': (int, 'Monitoring', 0),
|
||||||
'NOTIFY_CONCURRENT_THRESHOLD': (int, 'Monitoring', 2),
|
'NOTIFY_CONCURRENT_THRESHOLD': (int, 'Monitoring', 2),
|
||||||
'NOTIFY_WATCHED_PERCENT': (int, 'Monitoring', 85),
|
'NOTIFY_WATCHED_PERCENT': (int, 'Monitoring', 85),
|
||||||
'NOTIFY_ON_START_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_START_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_START_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) started playing {title}.'),
|
'NOTIFY_ON_START_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) started playing {title}.'),
|
||||||
'NOTIFY_ON_STOP_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_STOP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_STOP_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has stopped {title}.'),
|
'NOTIFY_ON_STOP_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has stopped {title}.'),
|
||||||
'NOTIFY_ON_PAUSE_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_PAUSE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_PAUSE_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has paused {title}.'),
|
'NOTIFY_ON_PAUSE_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has paused {title}.'),
|
||||||
'NOTIFY_ON_RESUME_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_RESUME_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_RESUME_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has resumed {title}.'),
|
'NOTIFY_ON_RESUME_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has resumed {title}.'),
|
||||||
'NOTIFY_ON_BUFFER_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_BUFFER_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_BUFFER_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) is buffering {title}.'),
|
'NOTIFY_ON_BUFFER_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) is buffering {title}.'),
|
||||||
'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_WATCHED_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has watched {title}.'),
|
'NOTIFY_ON_WATCHED_BODY_TEXT': (unicode, 'Monitoring', '{user} ({player}) has watched {title}.'),
|
||||||
'NOTIFY_ON_CREATED_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_CREATED_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_CREATED_BODY_TEXT': (unicode, 'Monitoring', '{title} was recently added to Plex.'),
|
'NOTIFY_ON_CREATED_BODY_TEXT': (unicode, 'Monitoring', '{title} was recently added to Plex.'),
|
||||||
'NOTIFY_ON_EXTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_EXTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_EXTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is down.'),
|
'NOTIFY_ON_EXTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is down.'),
|
||||||
'NOTIFY_ON_INTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_INTDOWN_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_INTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is down.'),
|
'NOTIFY_ON_INTDOWN_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is down.'),
|
||||||
'NOTIFY_ON_EXTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_EXTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_EXTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is back up.'),
|
'NOTIFY_ON_EXTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server remote access is back up.'),
|
||||||
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_INTUP_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_INTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is back up.'),
|
'NOTIFY_ON_INTUP_BODY_TEXT': (unicode, 'Monitoring', 'The Plex Media Server is back up.'),
|
||||||
'NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_PMSUPDATE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_PMSUPDATE_BODY_TEXT': (unicode, 'Monitoring', 'An update is available for the Plex Media Server (version {update_version}).'),
|
'NOTIFY_ON_PMSUPDATE_BODY_TEXT': (unicode, 'Monitoring', 'An update is available for the Plex Media Server (version {update_version}).'),
|
||||||
'NOTIFY_ON_CONCURRENT_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_CONCURRENT_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_CONCURRENT_BODY_TEXT': (unicode, 'Monitoring', '{user} has {user_streams} concurrent streams.'),
|
'NOTIFY_ON_CONCURRENT_BODY_TEXT': (unicode, 'Monitoring', '{user} has {user_streams} concurrent streams.'),
|
||||||
'NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT': (unicode, 'Monitoring', 'PlexPy ({server_name})'),
|
'NOTIFY_ON_NEWDEVICE_SUBJECT_TEXT': (unicode, 'Monitoring', 'Tautulli ({server_name})'),
|
||||||
'NOTIFY_ON_NEWDEVICE_BODY_TEXT': (unicode, 'Monitoring', '{user} is streaming from a new device: {player}.'),
|
'NOTIFY_ON_NEWDEVICE_BODY_TEXT': (unicode, 'Monitoring', '{user} is streaming from a new device: {player}.'),
|
||||||
'NOTIFY_SCRIPTS_ARGS_TEXT': (unicode, 'Monitoring', ''),
|
'NOTIFY_SCRIPTS_ARGS_TEXT': (unicode, 'Monitoring', ''),
|
||||||
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/PlexPy'),
|
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/Tautulli'),
|
||||||
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
||||||
'OSX_NOTIFY_ON_PLAY': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ON_PLAY': (int, 'OSX_Notify', 0),
|
||||||
'OSX_NOTIFY_ON_STOP': (int, 'OSX_Notify', 0),
|
'OSX_NOTIFY_ON_STOP': (int, 'OSX_Notify', 0),
|
||||||
|
@ -642,13 +642,13 @@ def make_backup(cleanup=False, scheduler=False):
|
||||||
try:
|
try:
|
||||||
os.remove(file_)
|
os.remove(file_)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error(u"PlexPy Config :: Failed to delete %s from the backup folder: %s" % (file_, e))
|
logger.error(u"Tautulli Config :: Failed to delete %s from the backup folder: %s" % (file_, e))
|
||||||
|
|
||||||
if backup_file in os.listdir(backup_folder):
|
if backup_file in os.listdir(backup_folder):
|
||||||
logger.debug(u"PlexPy Config :: Successfully backed up %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
logger.debug(u"Tautulli Config :: Successfully backed up %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
logger.warn(u"Tautulli Config :: Failed to backup %s to %s" % (plexpy.CONFIG_FILE, backup_file))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -729,12 +729,12 @@ class Config(object):
|
||||||
new_config[section][ini_key] = self._config[section][ini_key]
|
new_config[section][ini_key] = self._config[section][ini_key]
|
||||||
|
|
||||||
# Write it to file
|
# Write it to file
|
||||||
logger.info(u"PlexPy Config :: Writing configuration to file")
|
logger.info(u"Tautulli Config :: Writing configuration to file")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_config.write()
|
new_config.write()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error(u"PlexPy Config :: Error writing configuration file: %s", e)
|
logger.error(u"Tautulli Config :: Error writing configuration file: %s", e)
|
||||||
|
|
||||||
self._blacklist()
|
self._blacklist()
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import os
|
import os
|
||||||
|
@ -33,7 +33,7 @@ def drop_session_db():
|
||||||
|
|
||||||
|
|
||||||
def clear_history_tables():
|
def clear_history_tables():
|
||||||
logger.debug(u"PlexPy Database :: Deleting all session_history records... No turning back now bub.")
|
logger.debug(u"Tautulli Database :: Deleting all session_history records... No turning back now bub.")
|
||||||
monitor_db = MonitorDatabase()
|
monitor_db = MonitorDatabase()
|
||||||
monitor_db.action('DELETE FROM session_history')
|
monitor_db.action('DELETE FROM session_history')
|
||||||
monitor_db.action('DELETE FROM session_history_media_info')
|
monitor_db.action('DELETE FROM session_history_media_info')
|
||||||
|
@ -42,7 +42,7 @@ def clear_history_tables():
|
||||||
|
|
||||||
|
|
||||||
def delete_sessions():
|
def delete_sessions():
|
||||||
logger.debug(u"PlexPy Database :: Clearing temporary sessions from database.")
|
logger.debug(u"Tautulli Database :: Clearing temporary sessions from database.")
|
||||||
monitor_db = MonitorDatabase()
|
monitor_db = MonitorDatabase()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -50,7 +50,7 @@ def delete_sessions():
|
||||||
monitor_db.action('VACUUM')
|
monitor_db.action('VACUUM')
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Database :: Unable to clear temporary sessions from database: %s." % e)
|
logger.warn(u"Tautulli Database :: Unable to clear temporary sessions from database: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def db_filename(filename=FILENAME):
|
def db_filename(filename=FILENAME):
|
||||||
|
@ -88,13 +88,13 @@ def make_backup(cleanup=False, scheduler=False):
|
||||||
try:
|
try:
|
||||||
os.remove(file_)
|
os.remove(file_)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error(u"PlexPy Database :: Failed to delete %s from the backup folder: %s" % (file_, e))
|
logger.error(u"Tautulli Database :: Failed to delete %s from the backup folder: %s" % (file_, e))
|
||||||
|
|
||||||
if backup_file in os.listdir(backup_folder):
|
if backup_file in os.listdir(backup_folder):
|
||||||
logger.debug(u"PlexPy Database :: Successfully backed up %s to %s" % (db_filename(), backup_file))
|
logger.debug(u"Tautulli Database :: Successfully backed up %s to %s" % (db_filename(), backup_file))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Database :: Failed to backup %s to %s" % (db_filename(), backup_file))
|
logger.warn(u"Tautulli Database :: Failed to backup %s to %s" % (db_filename(), backup_file))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -147,15 +147,15 @@ class MonitorDatabase(object):
|
||||||
|
|
||||||
except sqlite3.OperationalError as e:
|
except sqlite3.OperationalError as e:
|
||||||
if "unable to open database file" in e or "database is locked" in e:
|
if "unable to open database file" in e or "database is locked" in e:
|
||||||
logger.warn(u"PlexPy Database :: Database Error: %s", e)
|
logger.warn(u"Tautulli Database :: Database Error: %s", e)
|
||||||
attempts += 1
|
attempts += 1
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Database :: Database error: %s", e)
|
logger.error(u"Tautulli Database :: Database error: %s", e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
except sqlite3.DatabaseError as e:
|
except sqlite3.DatabaseError as e:
|
||||||
logger.error(u"PlexPy Database :: Fatal Error executing %s :: %s", query, e)
|
logger.error(u"Tautulli Database :: Fatal Error executing %s :: %s", query, e)
|
||||||
raise
|
raise
|
||||||
|
|
||||||
return sql_result
|
return sql_result
|
||||||
|
@ -199,7 +199,7 @@ class MonitorDatabase(object):
|
||||||
try:
|
try:
|
||||||
self.action(insert_query, value_dict.values() + key_dict.values())
|
self.action(insert_query, value_dict.values() + key_dict.values())
|
||||||
except sqlite3.IntegrityError:
|
except sqlite3.IntegrityError:
|
||||||
logger.info(u"PlexPy Database :: Queries failed: %s and %s", update_query, insert_query)
|
logger.info(u"Tautulli Database :: Queries failed: %s and %s", update_query, insert_query)
|
||||||
|
|
||||||
# We want to know if it was an update or insert
|
# We want to know if it was an update or insert
|
||||||
return trans_type
|
return trans_type
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
@ -172,7 +172,7 @@ class DataFactory(object):
|
||||||
['session_history.id', 'session_history_media_info.id']],
|
['session_history.id', 'session_history_media_info.id']],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_history: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_history: %s." % e)
|
||||||
return {'recordsFiltered': 0,
|
return {'recordsFiltered': 0,
|
||||||
'recordsTotal': 0,
|
'recordsTotal': 0,
|
||||||
'draw': 0,
|
'draw': 0,
|
||||||
|
@ -302,7 +302,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_movies: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: top_movies: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -353,7 +353,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_movies: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: popular_movies: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -400,7 +400,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_tv: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: top_tv: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -450,7 +450,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_tv: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: popular_tv: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -497,7 +497,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_music: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: top_music: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -547,7 +547,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_music: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: popular_music: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -595,7 +595,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_users: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: top_users: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -648,7 +648,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_platforms: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: top_platforms: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -706,7 +706,7 @@ class DataFactory(object):
|
||||||
'LIMIT %s' % (time_range, group_by, movie_watched_percent, tv_watched_percent, stats_count)
|
'LIMIT %s' % (time_range, group_by, movie_watched_percent, tv_watched_percent, stats_count)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: last_watched: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: last_watched: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -812,7 +812,7 @@ class DataFactory(object):
|
||||||
if result:
|
if result:
|
||||||
most_concurrent.append(calc_most_concurrent(title, result))
|
most_concurrent.append(calc_most_concurrent(title, result))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: most_concurrent: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_home_stats: most_concurrent: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
home_stats.append({'stat_id': stat,
|
home_stats.append({'stat_id': stat,
|
||||||
|
@ -837,7 +837,7 @@ class DataFactory(object):
|
||||||
'ORDER BY section_type, count DESC, parent_count DESC, child_count DESC ' % ','.join(library_cards)
|
'ORDER BY section_type, count DESC, parent_count DESC, child_count DESC ' % ','.join(library_cards)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_library_stats: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_library_stats: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -1033,7 +1033,7 @@ class DataFactory(object):
|
||||||
'%s ' % where
|
'%s ' % where
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_total_duration: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_total_duration: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
total_duration = 0
|
total_duration = 0
|
||||||
|
@ -1056,7 +1056,7 @@ class DataFactory(object):
|
||||||
query = 'SELECT ip_address FROM sessions WHERE session_key = %d %s' % (int(session_key), user_cond)
|
query = 'SELECT ip_address FROM sessions WHERE session_key = %d %s' % (int(session_key), user_cond)
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_session_ip: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_session_ip: %s." % e)
|
||||||
return ip_address
|
return ip_address
|
||||||
else:
|
else:
|
||||||
return ip_address
|
return ip_address
|
||||||
|
@ -1086,7 +1086,7 @@ class DataFactory(object):
|
||||||
'WHERE rating_key = ?'
|
'WHERE rating_key = ?'
|
||||||
poster_info = monitor_db.select_single(query, args=[poster_key])
|
poster_info = monitor_db.select_single(query, args=[poster_key])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_poster_url: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_poster_url: %s." % e)
|
||||||
|
|
||||||
return poster_info
|
return poster_info
|
||||||
|
|
||||||
|
@ -1105,7 +1105,7 @@ class DataFactory(object):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
if rating_key:
|
if rating_key:
|
||||||
logger.info(u"PlexPy DataFactory :: Deleting poster_url for rating_key %s from the database." % rating_key)
|
logger.info(u"Tautulli DataFactory :: Deleting poster_url for rating_key %s from the database." % rating_key)
|
||||||
result = monitor_db.action('DELETE FROM poster_urls WHERE rating_key = ?', [rating_key])
|
result = monitor_db.action('DELETE FROM poster_urls WHERE rating_key = ?', [rating_key])
|
||||||
return True if result else False
|
return True if result else False
|
||||||
|
|
||||||
|
@ -1197,7 +1197,7 @@ class DataFactory(object):
|
||||||
grandparent_rating_key = result[0]['grandparent_rating_key']
|
grandparent_rating_key = result[0]['grandparent_rating_key']
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_rating_keys_list: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_rating_keys_list: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
query = 'SELECT rating_key, parent_rating_key, grandparent_rating_key, title, parent_title, grandparent_title, ' \
|
query = 'SELECT rating_key, parent_rating_key, grandparent_rating_key, title, parent_title, grandparent_title, ' \
|
||||||
|
@ -1244,7 +1244,7 @@ class DataFactory(object):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
if row_id.isdigit():
|
if row_id.isdigit():
|
||||||
logger.info(u"PlexPy DataFactory :: Deleting row id %s from the session history database." % row_id)
|
logger.info(u"Tautulli DataFactory :: Deleting row id %s from the session history database." % row_id)
|
||||||
session_history_del = \
|
session_history_del = \
|
||||||
monitor_db.action('DELETE FROM session_history WHERE id = ?', [row_id])
|
monitor_db.action('DELETE FROM session_history WHERE id = ?', [row_id])
|
||||||
session_history_media_info_del = \
|
session_history_media_info_del = \
|
||||||
|
@ -1277,7 +1277,7 @@ class DataFactory(object):
|
||||||
mapping = get_pairs(old_key_list, new_key_list)
|
mapping = get_pairs(old_key_list, new_key_list)
|
||||||
|
|
||||||
if mapping:
|
if mapping:
|
||||||
logger.info(u"PlexPy DataFactory :: Updating metadata in the database.")
|
logger.info(u"Tautulli DataFactory :: Updating metadata in the database.")
|
||||||
for old_key, new_key in mapping.iteritems():
|
for old_key, new_key in mapping.iteritems():
|
||||||
metadata = pms_connect.get_metadata_details(new_key)
|
metadata = pms_connect.get_metadata_details(new_key)
|
||||||
|
|
||||||
|
@ -1323,7 +1323,7 @@ class DataFactory(object):
|
||||||
genres = ";".join(metadata['genres'])
|
genres = ";".join(metadata['genres'])
|
||||||
labels = ";".join(metadata['labels'])
|
labels = ";".join(metadata['labels'])
|
||||||
|
|
||||||
#logger.info(u"PlexPy DataFactory :: Updating metadata in the database for rating key: %s." % new_rating_key)
|
#logger.info(u"Tautulli DataFactory :: Updating metadata in the database for rating key: %s." % new_rating_key)
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
# Update the session_history_metadata table
|
# Update the session_history_metadata table
|
||||||
|
@ -1375,7 +1375,7 @@ class DataFactory(object):
|
||||||
join_evals=[],
|
join_evals=[],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_notification_log: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_notification_log: %s." % e)
|
||||||
return {'recordsFiltered': 0,
|
return {'recordsFiltered': 0,
|
||||||
'recordsTotal': 0,
|
'recordsTotal': 0,
|
||||||
'draw': 0,
|
'draw': 0,
|
||||||
|
@ -1420,12 +1420,12 @@ class DataFactory(object):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(u"PlexPy DataFactory :: Clearing notification logs from database.")
|
logger.info(u"Tautulli DataFactory :: Clearing notification logs from database.")
|
||||||
monitor_db.action('DELETE FROM notify_log')
|
monitor_db.action('DELETE FROM notify_log')
|
||||||
monitor_db.action('VACUUM')
|
monitor_db.action('VACUUM')
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for delete_notification_log: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for delete_notification_log: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_user_devices(self, user_id=''):
|
def get_user_devices(self, user_id=''):
|
||||||
|
@ -1436,7 +1436,7 @@ class DataFactory(object):
|
||||||
query = 'SELECT machine_id FROM session_history WHERE user_id = ? GROUP BY machine_id'
|
query = 'SELECT machine_id FROM session_history WHERE user_id = ? GROUP BY machine_id'
|
||||||
result = monitor_db.select(query=query, args=[user_id])
|
result = monitor_db.select(query=query, args=[user_id])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_user_devices: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_user_devices: %s." % e)
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
@ -1451,7 +1451,7 @@ class DataFactory(object):
|
||||||
query = 'SELECT * FROM recently_added WHERE rating_key = ?'
|
query = 'SELECT * FROM recently_added WHERE rating_key = ?'
|
||||||
result = monitor_db.select(query=query, args=[rating_key])
|
result = monitor_db.select(query=query, args=[rating_key])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_recently_added_item: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for get_recently_added_item: %s." % e)
|
||||||
return []
|
return []
|
||||||
else:
|
else:
|
||||||
return []
|
return []
|
||||||
|
@ -1477,7 +1477,7 @@ class DataFactory(object):
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert(table_name='recently_added', key_dict=keys, value_dict=values)
|
monitor_db.upsert(table_name='recently_added', key_dict=keys, value_dict=values)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for set_recently_added_item: %s." % e)
|
logger.warn(u"Tautulli DataFactory :: Unable to execute database query for set_recently_added_item: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -43,14 +43,14 @@ class DataTables(object):
|
||||||
kwargs=None):
|
kwargs=None):
|
||||||
|
|
||||||
if not table_name:
|
if not table_name:
|
||||||
logger.error('PlexPy DataTables :: No table name received.')
|
logger.error('Tautulli DataTables :: No table name received.')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Fetch all our parameters
|
# Fetch all our parameters
|
||||||
if kwargs.get('json_data'):
|
if kwargs.get('json_data'):
|
||||||
parameters = helpers.process_json_kwargs(json_kwargs=kwargs.get('json_data'))
|
parameters = helpers.process_json_kwargs(json_kwargs=kwargs.get('json_data'))
|
||||||
else:
|
else:
|
||||||
logger.error('PlexPy DataTables :: Parameters for Datatables must be sent as a serialised json object '
|
logger.error('Tautulli DataTables :: Parameters for Datatables must be sent as a serialised json object '
|
||||||
'named json_data.')
|
'named json_data.')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
class PlexPyException(Exception):
|
class PlexPyException(Exception):
|
||||||
"""
|
"""
|
||||||
Generic PlexPy Exception - should never be thrown, only subclassed
|
Generic Tautulli Exception - should never be thrown, only subclassed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_day: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_day: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# create our date range as some days may not have any data
|
# create our date range as some days may not have any data
|
||||||
|
@ -166,7 +166,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_dayofweek: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_dayofweek: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if plexpy.CONFIG.WEEK_START_MONDAY:
|
if plexpy.CONFIG.WEEK_START_MONDAY:
|
||||||
|
@ -251,7 +251,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_hourofday: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_hourofday: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
hours_list = ['00','01','02','03','04','05',
|
hours_list = ['00','01','02','03','04','05',
|
||||||
|
@ -336,7 +336,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_month: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_month: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# create our date range as some months may not have any data
|
# create our date range as some months may not have any data
|
||||||
|
@ -428,7 +428,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_by_top_10_platforms: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_by_top_10_platforms: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
@ -505,7 +505,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_by_top_10_users: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_by_top_10_users: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
@ -588,7 +588,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_per_stream_type: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_per_stream_type: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# create our date range as some days may not have any data
|
# create our date range as some days may not have any data
|
||||||
|
@ -689,7 +689,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_by_source_resolution: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_by_source_resolution: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
@ -790,7 +790,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_total_plays_by_stream_resolution: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_total_plays_by_stream_resolution: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
@ -870,7 +870,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_stream_type_by_top_10_platforms: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_stream_type_by_top_10_platforms: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
@ -959,7 +959,7 @@ class Graphs(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Graphs :: Unable to execute database query for get_stream_type_by_top_10_users: %s." % e)
|
logger.warn(u"Tautulli Graphs :: Unable to execute database query for get_stream_type_by_top_10_users: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
categories = []
|
categories = []
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import datetime
|
import datetime
|
||||||
|
@ -399,10 +399,10 @@ def create_https_certificates(ssl_cert, ssl_key):
|
||||||
ips = ['IP:' + d.strip() for d in plexpy.CONFIG.HTTPS_IP.split(',') if d]
|
ips = ['IP:' + d.strip() for d in plexpy.CONFIG.HTTPS_IP.split(',') if d]
|
||||||
altNames = ','.join(domains + ips)
|
altNames = ','.join(domains + ips)
|
||||||
|
|
||||||
# Create the self-signed PlexPy certificate
|
# Create the self-signed Tautulli certificate
|
||||||
logger.debug(u"Generating self-signed SSL certificate.")
|
logger.debug(u"Generating self-signed SSL certificate.")
|
||||||
pkey = createKeyPair(TYPE_RSA, 2048)
|
pkey = createKeyPair(TYPE_RSA, 2048)
|
||||||
cert = createSelfSignedCertificate(("PlexPy", pkey), serial, (0, 60 * 60 * 24 * 365 * 10), altNames) # ten years
|
cert = createSelfSignedCertificate(("Tautulli", pkey), serial, (0, 60 * 60 * 24 * 365 * 10), altNames) # ten years
|
||||||
|
|
||||||
# Save the key and certificate to disk
|
# Save the key and certificate to disk
|
||||||
try:
|
try:
|
||||||
|
@ -537,27 +537,27 @@ def install_geoip_db():
|
||||||
geolite2_db = plexpy.CONFIG.GEOIP_DB or os.path.join(plexpy.DATA_DIR, geolite2_db)
|
geolite2_db = plexpy.CONFIG.GEOIP_DB or os.path.join(plexpy.DATA_DIR, geolite2_db)
|
||||||
|
|
||||||
# Retrieve the GeoLite2 gzip file
|
# Retrieve the GeoLite2 gzip file
|
||||||
logger.debug(u"PlexPy Helpers :: Downloading GeoLite2 gzip file from MaxMind...")
|
logger.debug(u"Tautulli Helpers :: Downloading GeoLite2 gzip file from MaxMind...")
|
||||||
try:
|
try:
|
||||||
maxmind = urllib.URLopener()
|
maxmind = urllib.URLopener()
|
||||||
maxmind.retrieve(maxmind_url + geolite2_gz, temp_gz)
|
maxmind.retrieve(maxmind_url + geolite2_gz, temp_gz)
|
||||||
md5_checksum = urllib2.urlopen(maxmind_url + geolite2_md5).read()
|
md5_checksum = urllib2.urlopen(maxmind_url + geolite2_md5).read()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Helpers :: Failed to download GeoLite2 gzip file from MaxMind: %s" % e)
|
logger.error(u"Tautulli Helpers :: Failed to download GeoLite2 gzip file from MaxMind: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Extract the GeoLite2 database file
|
# Extract the GeoLite2 database file
|
||||||
logger.debug(u"PlexPy Helpers :: Extracting GeoLite2 database...")
|
logger.debug(u"Tautulli Helpers :: Extracting GeoLite2 database...")
|
||||||
try:
|
try:
|
||||||
with gzip.open(temp_gz, 'rb') as gz:
|
with gzip.open(temp_gz, 'rb') as gz:
|
||||||
with open(geolite2_db, 'wb') as db:
|
with open(geolite2_db, 'wb') as db:
|
||||||
db.write(gz.read())
|
db.write(gz.read())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Helpers :: Failed to extract the GeoLite2 database: %s" % e)
|
logger.error(u"Tautulli Helpers :: Failed to extract the GeoLite2 database: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Check MD5 hash for GeoLite2 database file
|
# Check MD5 hash for GeoLite2 database file
|
||||||
logger.debug(u"PlexPy Helpers :: Checking MD5 checksum for GeoLite2 database...")
|
logger.debug(u"Tautulli Helpers :: Checking MD5 checksum for GeoLite2 database...")
|
||||||
try:
|
try:
|
||||||
hash_md5 = hashlib.md5()
|
hash_md5 = hashlib.md5()
|
||||||
with open(geolite2_db, 'rb') as f:
|
with open(geolite2_db, 'rb') as f:
|
||||||
|
@ -566,37 +566,37 @@ def install_geoip_db():
|
||||||
md5_hash = hash_md5.hexdigest()
|
md5_hash = hash_md5.hexdigest()
|
||||||
|
|
||||||
if md5_hash != md5_checksum:
|
if md5_hash != md5_checksum:
|
||||||
logger.error(u"PlexPy Helpers :: MD5 checksum doesn't match for GeoLite2 database. "
|
logger.error(u"Tautulli Helpers :: MD5 checksum doesn't match for GeoLite2 database. "
|
||||||
"Checksum: %s, file hash: %s" % (md5_checksum, md5_hash))
|
"Checksum: %s, file hash: %s" % (md5_checksum, md5_hash))
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Helpers :: Failed to generate MD5 checksum for GeoLite2 database: %s" % e)
|
logger.error(u"Tautulli Helpers :: Failed to generate MD5 checksum for GeoLite2 database: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Delete temportary GeoLite2 gzip file
|
# Delete temportary GeoLite2 gzip file
|
||||||
logger.debug(u"PlexPy Helpers :: Deleting temporary GeoLite2 gzip file...")
|
logger.debug(u"Tautulli Helpers :: Deleting temporary GeoLite2 gzip file...")
|
||||||
try:
|
try:
|
||||||
os.remove(temp_gz)
|
os.remove(temp_gz)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Helpers :: Failed to remove temporary GeoLite2 gzip file: %s" % e)
|
logger.warn(u"Tautulli Helpers :: Failed to remove temporary GeoLite2 gzip file: %s" % e)
|
||||||
|
|
||||||
logger.debug(u"PlexPy Helpers :: GeoLite2 database installed successfully.")
|
logger.debug(u"Tautulli Helpers :: GeoLite2 database installed successfully.")
|
||||||
plexpy.CONFIG.__setattr__('GEOIP_DB', geolite2_db)
|
plexpy.CONFIG.__setattr__('GEOIP_DB', geolite2_db)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def uninstall_geoip_db():
|
def uninstall_geoip_db():
|
||||||
logger.debug(u"PlexPy Helpers :: Uninstalling the GeoLite2 database...")
|
logger.debug(u"Tautulli Helpers :: Uninstalling the GeoLite2 database...")
|
||||||
try:
|
try:
|
||||||
os.remove(plexpy.CONFIG.GEOIP_DB)
|
os.remove(plexpy.CONFIG.GEOIP_DB)
|
||||||
plexpy.CONFIG.__setattr__('GEOIP_DB', '')
|
plexpy.CONFIG.__setattr__('GEOIP_DB', '')
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Helpers :: Failed to uninstall the GeoLite2 database: %s" % e)
|
logger.error(u"Tautulli Helpers :: Failed to uninstall the GeoLite2 database: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.debug(u"PlexPy Helpers :: GeoLite2 database uninstalled successfully.")
|
logger.debug(u"Tautulli Helpers :: GeoLite2 database uninstalled successfully.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def geoip_lookup(ip_address):
|
def geoip_lookup(ip_address):
|
||||||
|
@ -686,14 +686,14 @@ def uploadToImgur(imgPath, imgTitle=''):
|
||||||
img_url = ''
|
img_url = ''
|
||||||
|
|
||||||
if not client_id:
|
if not client_id:
|
||||||
logger.error(u"PlexPy Helpers :: Cannot upload poster to Imgur. No Imgur client id specified in the settings.")
|
logger.error(u"Tautulli Helpers :: Cannot upload poster to Imgur. No Imgur client id specified in the settings.")
|
||||||
return img_url
|
return img_url
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(imgPath, 'rb') as imgFile:
|
with open(imgPath, 'rb') as imgFile:
|
||||||
img = imgFile.read()
|
img = imgFile.read()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error(u"PlexPy Helpers :: Unable to read image file for Imgur: %s" % e)
|
logger.error(u"Tautulli Helpers :: Unable to read image file for Imgur: %s" % e)
|
||||||
return img_url
|
return img_url
|
||||||
|
|
||||||
headers = {'Authorization': 'Client-ID %s' % client_id}
|
headers = {'Authorization': 'Client-ID %s' % client_id}
|
||||||
|
@ -707,17 +707,17 @@ def uploadToImgur(imgPath, imgTitle=''):
|
||||||
|
|
||||||
if response and not err_msg:
|
if response and not err_msg:
|
||||||
t = '\'' + imgTitle + '\' ' if imgTitle else ''
|
t = '\'' + imgTitle + '\' ' if imgTitle else ''
|
||||||
logger.debug(u"PlexPy Helpers :: Image {}uploaded to Imgur.".format(t))
|
logger.debug(u"Tautulli Helpers :: Image {}uploaded to Imgur.".format(t))
|
||||||
img_url = response.json().get('data').get('link', '').replace('http://', 'https://')
|
img_url = response.json().get('data').get('link', '').replace('http://', 'https://')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if err_msg:
|
if err_msg:
|
||||||
logger.error(u"PlexPy Helpers :: Unable to upload image to Imgur: {}".format(err_msg))
|
logger.error(u"Tautulli Helpers :: Unable to upload image to Imgur: {}".format(err_msg))
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Helpers :: Unable to upload image to Imgur.")
|
logger.error(u"Tautulli Helpers :: Unable to upload image to Imgur.")
|
||||||
|
|
||||||
if req_msg:
|
if req_msg:
|
||||||
logger.debug(u"PlexPy Helpers :: Request response: {}".format(req_msg))
|
logger.debug(u"Tautulli Helpers :: Request response: {}".format(req_msg))
|
||||||
|
|
||||||
return img_url
|
return img_url
|
||||||
|
|
||||||
|
@ -729,7 +729,7 @@ def cache_image(url, image=None):
|
||||||
# Create image directory if it doesn't exist
|
# Create image directory if it doesn't exist
|
||||||
imgdir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images/')
|
imgdir = os.path.join(plexpy.CONFIG.CACHE_DIR, 'images/')
|
||||||
if not os.path.exists(imgdir):
|
if not os.path.exists(imgdir):
|
||||||
logger.debug(u"PlexPy Helpers :: Creating image cache directory at %s" % imgdir)
|
logger.debug(u"Tautulli Helpers :: Creating image cache directory at %s" % imgdir)
|
||||||
os.makedirs(imgdir)
|
os.makedirs(imgdir)
|
||||||
|
|
||||||
# Create a hash of the url to use as the filename
|
# Create a hash of the url to use as the filename
|
||||||
|
@ -742,7 +742,7 @@ def cache_image(url, image=None):
|
||||||
with open(imagefile, 'wb') as cache_file:
|
with open(imagefile, 'wb') as cache_file:
|
||||||
cache_file.write(image)
|
cache_file.write(image)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error(u"PlexPy Helpers :: Failed to cache image %s: %s" % (imagefile, e))
|
logger.error(u"Tautulli Helpers :: Failed to cache image %s: %s" % (imagefile, e))
|
||||||
|
|
||||||
# Try to return the image from the cache directory
|
# Try to return the image from the cache directory
|
||||||
if os.path.isfile(imagefile):
|
if os.path.isfile(imagefile):
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from httplib import HTTPSConnection
|
from httplib import HTTPSConnection
|
||||||
from httplib import HTTPConnection
|
from httplib import HTTPConnection
|
||||||
|
@ -64,7 +64,7 @@ class HTTPHandler(object):
|
||||||
if not self.ssl_verify and hasattr(ssl, '_create_unverified_context'):
|
if not self.ssl_verify and hasattr(ssl, '_create_unverified_context'):
|
||||||
context = ssl._create_unverified_context()
|
context = ssl._create_unverified_context()
|
||||||
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout, context=context)
|
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout, context=context)
|
||||||
logger.warn(u"PlexPy HTTP Handler :: Unverified HTTPS request made. This connection is not secure.")
|
logger.warn(u"Tautulli HTTP Handler :: Unverified HTTPS request made. This connection is not secure.")
|
||||||
else:
|
else:
|
||||||
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout)
|
handler = HTTPSConnection(host=self.host, port=self.port, timeout=timeout)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
@ -39,9 +39,9 @@ def update_section_ids():
|
||||||
query = 'SELECT section_id, section_type FROM library_sections'
|
query = 'SELECT section_id, section_type FROM library_sections'
|
||||||
library_results = monitor_db.select(query=query)
|
library_results = monitor_db.select(query=query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for update_section_ids: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for update_section_ids: %s." % e)
|
||||||
|
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to update section_id's in database.")
|
logger.warn(u"Tautulli Libraries :: Unable to update section_id's in database.")
|
||||||
plexpy.CONFIG.UPDATE_SECTION_IDS = 1
|
plexpy.CONFIG.UPDATE_SECTION_IDS = 1
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return None
|
return None
|
||||||
|
@ -51,7 +51,7 @@ def update_section_ids():
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.debug(u"PlexPy Libraries :: Updating section_id's in database.")
|
logger.debug(u"Tautulli Libraries :: Updating section_id's in database.")
|
||||||
|
|
||||||
# Get rating_key: section_id mapping pairs
|
# Get rating_key: section_id mapping pairs
|
||||||
key_mappings = {}
|
key_mappings = {}
|
||||||
|
@ -68,7 +68,7 @@ def update_section_ids():
|
||||||
children_list = library_children['childern_list']
|
children_list = library_children['childern_list']
|
||||||
key_mappings.update({child['rating_key']:child['section_id'] for child in children_list})
|
key_mappings.update({child['rating_key']:child['section_id'] for child in children_list})
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to get a list of library items for section_id %s." % section_id)
|
logger.warn(u"Tautulli Libraries :: Unable to get a list of library items for section_id %s." % section_id)
|
||||||
|
|
||||||
error_keys = set()
|
error_keys = set()
|
||||||
for item in history_results:
|
for item in history_results:
|
||||||
|
@ -86,10 +86,10 @@ def update_section_ids():
|
||||||
error_keys.add(item['rating_key'])
|
error_keys.add(item['rating_key'])
|
||||||
|
|
||||||
if error_keys:
|
if error_keys:
|
||||||
logger.info(u"PlexPy Libraries :: Updated all section_id's in database except for rating_keys: %s." %
|
logger.info(u"Tautulli Libraries :: Updated all section_id's in database except for rating_keys: %s." %
|
||||||
', '.join(str(key) for key in error_keys))
|
', '.join(str(key) for key in error_keys))
|
||||||
else:
|
else:
|
||||||
logger.info(u"PlexPy Libraries :: Updated all section_id's in database.")
|
logger.info(u"Tautulli Libraries :: Updated all section_id's in database.")
|
||||||
|
|
||||||
plexpy.CONFIG.UPDATE_SECTION_IDS = 0
|
plexpy.CONFIG.UPDATE_SECTION_IDS = 0
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
@ -105,9 +105,9 @@ def update_labels():
|
||||||
query = 'SELECT section_id, section_type FROM library_sections'
|
query = 'SELECT section_id, section_type FROM library_sections'
|
||||||
library_results = monitor_db.select(query=query)
|
library_results = monitor_db.select(query=query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for update_labels: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for update_labels: %s." % e)
|
||||||
|
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to update labels in database.")
|
logger.warn(u"Tautulli Libraries :: Unable to update labels in database.")
|
||||||
plexpy.CONFIG.UPDATE_LABELS = 1
|
plexpy.CONFIG.UPDATE_LABELS = 1
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return None
|
return None
|
||||||
|
@ -117,7 +117,7 @@ def update_labels():
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.debug(u"PlexPy Libraries :: Updating labels in database.")
|
logger.debug(u"Tautulli Libraries :: Updating labels in database.")
|
||||||
|
|
||||||
# Get rating_key: section_id mapping pairs
|
# Get rating_key: section_id mapping pairs
|
||||||
key_mappings = {}
|
key_mappings = {}
|
||||||
|
@ -148,7 +148,7 @@ def update_labels():
|
||||||
key_mappings[rating_key] = [label['label_title']]
|
key_mappings[rating_key] = [label['label_title']]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to get a list of library items for section_id %s."
|
logger.warn(u"Tautulli Libraries :: Unable to get a list of library items for section_id %s."
|
||||||
% section_id)
|
% section_id)
|
||||||
|
|
||||||
error_keys = set()
|
error_keys = set()
|
||||||
|
@ -162,10 +162,10 @@ def update_labels():
|
||||||
error_keys.add(rating_key)
|
error_keys.add(rating_key)
|
||||||
|
|
||||||
if error_keys:
|
if error_keys:
|
||||||
logger.info(u"PlexPy Libraries :: Updated all labels in database except for rating_keys: %s." %
|
logger.info(u"Tautulli Libraries :: Updated all labels in database except for rating_keys: %s." %
|
||||||
', '.join(str(key) for key in error_keys))
|
', '.join(str(key) for key in error_keys))
|
||||||
else:
|
else:
|
||||||
logger.info(u"PlexPy Libraries :: Updated all labels in database.")
|
logger.info(u"Tautulli Libraries :: Updated all labels in database.")
|
||||||
|
|
||||||
plexpy.CONFIG.UPDATE_LABELS = 0
|
plexpy.CONFIG.UPDATE_LABELS = 0
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
@ -239,7 +239,7 @@ class Libraries(object):
|
||||||
['session_history_metadata.id', 'session_history_media_info.id']],
|
['session_history_metadata.id', 'session_history_media_info.id']],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_list: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_list: %s." % e)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
result = query['result']
|
result = query['result']
|
||||||
|
@ -308,19 +308,19 @@ class Libraries(object):
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
if section_id and not str(section_id).isdigit():
|
if section_id and not str(section_id).isdigit():
|
||||||
logger.warn(u"PlexPy Libraries :: Datatable media info called but invalid section_id provided.")
|
logger.warn(u"Tautulli Libraries :: Datatable media info called but invalid section_id provided.")
|
||||||
return default_return
|
return default_return
|
||||||
elif rating_key and not str(rating_key).isdigit():
|
elif rating_key and not str(rating_key).isdigit():
|
||||||
logger.warn(u"PlexPy Libraries :: Datatable media info called but invalid rating_key provided.")
|
logger.warn(u"Tautulli Libraries :: Datatable media info called but invalid rating_key provided.")
|
||||||
return default_return
|
return default_return
|
||||||
elif not section_id and not rating_key:
|
elif not section_id and not rating_key:
|
||||||
logger.warn(u"PlexPy Libraries :: Datatable media info called but no input provided.")
|
logger.warn(u"Tautulli Libraries :: Datatable media info called but no input provided.")
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
# Get the library details
|
# Get the library details
|
||||||
library_details = self.get_details(section_id=section_id)
|
library_details = self.get_details(section_id=section_id)
|
||||||
if library_details['section_id'] == None:
|
if library_details['section_id'] == None:
|
||||||
logger.debug(u"PlexPy Libraries :: Library section_id %s not found." % section_id)
|
logger.debug(u"Tautulli Libraries :: Library section_id %s not found." % section_id)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
if not section_type:
|
if not section_type:
|
||||||
|
@ -350,7 +350,7 @@ class Libraries(object):
|
||||||
'GROUP BY session_history.%s ' % (count_by, group_by)
|
'GROUP BY session_history.%s ' % (count_by, group_by)
|
||||||
result = monitor_db.select(query, args=[section_id])
|
result = monitor_db.select(query, args=[section_id])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_datatables_media_info2: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_datatables_media_info2: %s." % e)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
watched_list = {}
|
watched_list = {}
|
||||||
|
@ -367,8 +367,8 @@ class Libraries(object):
|
||||||
rows = json.load(inFile)
|
rows = json.load(inFile)
|
||||||
library_count = len(rows)
|
library_count = len(rows)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
#logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: No JSON file for rating_key %s." % rating_key)
|
||||||
#logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key)
|
||||||
pass
|
pass
|
||||||
elif section_id:
|
elif section_id:
|
||||||
try:
|
try:
|
||||||
|
@ -377,8 +377,8 @@ class Libraries(object):
|
||||||
rows = json.load(inFile)
|
rows = json.load(inFile)
|
||||||
library_count = len(rows)
|
library_count = len(rows)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
#logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id)
|
#logger.debug(u"Tautulli Libraries :: No JSON file for library section_id %s." % section_id)
|
||||||
#logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id)
|
#logger.debug(u"Tautulli Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# If no cache was imported, get all library children items
|
# If no cache was imported, get all library children items
|
||||||
|
@ -398,7 +398,7 @@ class Libraries(object):
|
||||||
library_count = library_children['library_count']
|
library_count = library_children['library_count']
|
||||||
children_list = library_children['childern_list']
|
children_list = library_children['childern_list']
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to get a list of library items.")
|
logger.warn(u"Tautulli Libraries :: Unable to get a list of library items.")
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
new_rows = []
|
new_rows = []
|
||||||
|
@ -442,14 +442,14 @@ class Libraries(object):
|
||||||
with open(outFilePath, 'w') as outFile:
|
with open(outFilePath, 'w') as outFile:
|
||||||
json.dump(rows, outFile)
|
json.dump(rows, outFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.debug(u"PlexPy Libraries :: Unable to create cache file for rating_key %s." % rating_key)
|
logger.debug(u"Tautulli Libraries :: Unable to create cache file for rating_key %s." % rating_key)
|
||||||
elif section_id:
|
elif section_id:
|
||||||
try:
|
try:
|
||||||
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
||||||
with open(outFilePath, 'w') as outFile:
|
with open(outFilePath, 'w') as outFile:
|
||||||
json.dump(rows, outFile)
|
json.dump(rows, outFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.debug(u"PlexPy Libraries :: Unable to create cache file for section_id %s." % section_id)
|
logger.debug(u"Tautulli Libraries :: Unable to create cache file for section_id %s." % section_id)
|
||||||
|
|
||||||
# Update the last_played and play_count
|
# Update the last_played and play_count
|
||||||
for item in rows:
|
for item in rows:
|
||||||
|
@ -519,16 +519,16 @@ class Libraries(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if section_id and not str(section_id).isdigit():
|
if section_id and not str(section_id).isdigit():
|
||||||
logger.warn(u"PlexPy Libraries :: Datatable media info file size called but invalid section_id provided.")
|
logger.warn(u"Tautulli Libraries :: Datatable media info file size called but invalid section_id provided.")
|
||||||
return False
|
return False
|
||||||
elif rating_key and not str(rating_key).isdigit():
|
elif rating_key and not str(rating_key).isdigit():
|
||||||
logger.warn(u"PlexPy Libraries :: Datatable media info file size called but invalid rating_key provided.")
|
logger.warn(u"Tautulli Libraries :: Datatable media info file size called but invalid rating_key provided.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Get the library details
|
# Get the library details
|
||||||
library_details = self.get_details(section_id=section_id)
|
library_details = self.get_details(section_id=section_id)
|
||||||
if library_details['section_id'] == None:
|
if library_details['section_id'] == None:
|
||||||
logger.debug(u"PlexPy Libraries :: Library section_id %s not found." % section_id)
|
logger.debug(u"Tautulli Libraries :: Library section_id %s not found." % section_id)
|
||||||
return False
|
return False
|
||||||
if library_details['section_type'] == 'photo':
|
if library_details['section_type'] == 'photo':
|
||||||
return False
|
return False
|
||||||
|
@ -536,24 +536,24 @@ class Libraries(object):
|
||||||
rows = []
|
rows = []
|
||||||
# Import media info cache from json file
|
# Import media info cache from json file
|
||||||
if rating_key:
|
if rating_key:
|
||||||
#logger.debug(u"PlexPy Libraries :: Getting file sizes for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: Getting file sizes for rating_key %s." % rating_key)
|
||||||
try:
|
try:
|
||||||
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
|
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s-%s.json' % (section_id, rating_key))
|
||||||
with open(inFilePath, 'r') as inFile:
|
with open(inFilePath, 'r') as inFile:
|
||||||
rows = json.load(inFile)
|
rows = json.load(inFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
#logger.debug(u"PlexPy Libraries :: No JSON file for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: No JSON file for rating_key %s." % rating_key)
|
||||||
#logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: Refreshing data and creating new JSON file for rating_key %s." % rating_key)
|
||||||
pass
|
pass
|
||||||
elif section_id:
|
elif section_id:
|
||||||
logger.debug(u"PlexPy Libraries :: Getting file sizes for section_id %s." % section_id)
|
logger.debug(u"Tautulli Libraries :: Getting file sizes for section_id %s." % section_id)
|
||||||
try:
|
try:
|
||||||
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
inFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
||||||
with open(inFilePath, 'r') as inFile:
|
with open(inFilePath, 'r') as inFile:
|
||||||
rows = json.load(inFile)
|
rows = json.load(inFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
#logger.debug(u"PlexPy Libraries :: No JSON file for library section_id %s." % section_id)
|
#logger.debug(u"Tautulli Libraries :: No JSON file for library section_id %s." % section_id)
|
||||||
#logger.debug(u"PlexPy Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id)
|
#logger.debug(u"Tautulli Libraries :: Refreshing data and creating new JSON file for section_id %s." % section_id)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Get the total file size for each item
|
# Get the total file size for each item
|
||||||
|
@ -585,20 +585,20 @@ class Libraries(object):
|
||||||
with open(outFilePath, 'w') as outFile:
|
with open(outFilePath, 'w') as outFile:
|
||||||
json.dump(rows, outFile)
|
json.dump(rows, outFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.debug(u"PlexPy Libraries :: Unable to create cache file with file sizes for rating_key %s." % rating_key)
|
logger.debug(u"Tautulli Libraries :: Unable to create cache file with file sizes for rating_key %s." % rating_key)
|
||||||
elif section_id:
|
elif section_id:
|
||||||
try:
|
try:
|
||||||
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
outFilePath = os.path.join(plexpy.CONFIG.CACHE_DIR,'media_info_%s.json' % section_id)
|
||||||
with open(outFilePath, 'w') as outFile:
|
with open(outFilePath, 'w') as outFile:
|
||||||
json.dump(rows, outFile)
|
json.dump(rows, outFile)
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.debug(u"PlexPy Libraries :: Unable to create cache file with file sizes for section_id %s." % section_id)
|
logger.debug(u"Tautulli Libraries :: Unable to create cache file with file sizes for section_id %s." % section_id)
|
||||||
|
|
||||||
if rating_key:
|
if rating_key:
|
||||||
#logger.debug(u"PlexPy Libraries :: File sizes updated for rating_key %s." % rating_key)
|
#logger.debug(u"Tautulli Libraries :: File sizes updated for rating_key %s." % rating_key)
|
||||||
pass
|
pass
|
||||||
elif section_id:
|
elif section_id:
|
||||||
logger.debug(u"PlexPy Libraries :: File sizes updated for section_id %s." % section_id)
|
logger.debug(u"Tautulli Libraries :: File sizes updated for section_id %s." % section_id)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ class Libraries(object):
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert('library_sections', value_dict, key_dict)
|
monitor_db.upsert('library_sections', value_dict, key_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for set_config: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for set_config: %s." % e)
|
||||||
|
|
||||||
def get_details(self, section_id=None):
|
def get_details(self, section_id=None):
|
||||||
default_return = {'section_id': 0,
|
default_return = {'section_id': 0,
|
||||||
|
@ -647,7 +647,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_details: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_details: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
library_details = {}
|
library_details = {}
|
||||||
|
@ -680,7 +680,7 @@ class Libraries(object):
|
||||||
return library_details
|
return library_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to retrieve library %s from database. Requesting library list refresh."
|
logger.warn(u"Tautulli Libraries :: Unable to retrieve library %s from database. Requesting library list refresh."
|
||||||
% section_id)
|
% section_id)
|
||||||
# Let's first refresh the libraries list to make sure the library isn't newly added and not in the db yet
|
# Let's first refresh the libraries list to make sure the library isn't newly added and not in the db yet
|
||||||
pmsconnect.refresh_libraries()
|
pmsconnect.refresh_libraries()
|
||||||
|
@ -691,7 +691,7 @@ class Libraries(object):
|
||||||
return library_details
|
return library_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve library %s from database. Returning 'Local' library."
|
logger.warn(u"Tautulli Users :: Unable to retrieve library %s from database. Returning 'Local' library."
|
||||||
% section_id)
|
% section_id)
|
||||||
# If there is no library data we must return something
|
# If there is no library data we must return something
|
||||||
return default_return
|
return default_return
|
||||||
|
@ -731,7 +731,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_watch_time_stats: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_watch_time_stats: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -774,7 +774,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_user_stats: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_user_stats: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -813,7 +813,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_recently_watched: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_recently_watched: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
|
@ -853,7 +853,7 @@ class Libraries(object):
|
||||||
query = 'SELECT section_id, section_name FROM library_sections WHERE deleted_section = 0'
|
query = 'SELECT section_id, section_name FROM library_sections WHERE deleted_section = 0'
|
||||||
result = monitor_db.select(query=query)
|
result = monitor_db.select(query=query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_sections: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for get_sections: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
libraries = []
|
libraries = []
|
||||||
|
@ -870,7 +870,7 @@ class Libraries(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if section_id.isdigit():
|
if section_id.isdigit():
|
||||||
logger.info(u"PlexPy Libraries :: Deleting all history for library id %s from database." % section_id)
|
logger.info(u"Tautulli Libraries :: Deleting all history for library id %s from database." % section_id)
|
||||||
session_history_media_info_del = \
|
session_history_media_info_del = \
|
||||||
monitor_db.action('DELETE FROM '
|
monitor_db.action('DELETE FROM '
|
||||||
'session_history_media_info '
|
'session_history_media_info '
|
||||||
|
@ -894,7 +894,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to delete items, section_id not valid.'
|
return 'Unable to delete items, section_id not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for delete_all_history: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for delete_all_history: %s." % e)
|
||||||
|
|
||||||
def delete(self, section_id=None):
|
def delete(self, section_id=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
@ -902,7 +902,7 @@ class Libraries(object):
|
||||||
try:
|
try:
|
||||||
if section_id.isdigit():
|
if section_id.isdigit():
|
||||||
self.delete_all_history(section_id)
|
self.delete_all_history(section_id)
|
||||||
logger.info(u"PlexPy Libraries :: Deleting library with id %s from database." % section_id)
|
logger.info(u"Tautulli Libraries :: Deleting library with id %s from database." % section_id)
|
||||||
monitor_db.action('UPDATE library_sections SET deleted_section = 1 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET deleted_section = 1 WHERE section_id = ?', [section_id])
|
||||||
monitor_db.action('UPDATE library_sections SET keep_history = 0 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET keep_history = 0 WHERE section_id = ?', [section_id])
|
||||||
monitor_db.action('UPDATE library_sections SET do_notify = 0 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET do_notify = 0 WHERE section_id = ?', [section_id])
|
||||||
|
@ -918,14 +918,14 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to delete library, section_id not valid.'
|
return 'Unable to delete library, section_id not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for delete: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for delete: %s." % e)
|
||||||
|
|
||||||
def undelete(self, section_id=None, section_name=None):
|
def undelete(self, section_id=None, section_name=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if section_id and section_id.isdigit():
|
if section_id and section_id.isdigit():
|
||||||
logger.info(u"PlexPy Libraries :: Re-adding library with id %s to database." % section_id)
|
logger.info(u"Tautulli Libraries :: Re-adding library with id %s to database." % section_id)
|
||||||
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_id = ?', [section_id])
|
||||||
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_id = ?', [section_id])
|
||||||
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_id = ?', [section_id])
|
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_id = ?', [section_id])
|
||||||
|
@ -933,7 +933,7 @@ class Libraries(object):
|
||||||
|
|
||||||
return 'Re-added library with id %s.' % section_id
|
return 'Re-added library with id %s.' % section_id
|
||||||
elif section_name:
|
elif section_name:
|
||||||
logger.info(u"PlexPy Libraries :: Re-adding library with name %s to database." % section_name)
|
logger.info(u"Tautulli Libraries :: Re-adding library with name %s to database." % section_name)
|
||||||
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_name = ?', [section_name])
|
monitor_db.action('UPDATE library_sections SET deleted_section = 0 WHERE section_name = ?', [section_name])
|
||||||
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_name = ?', [section_name])
|
monitor_db.action('UPDATE library_sections SET keep_history = 1 WHERE section_name = ?', [section_name])
|
||||||
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_name = ?', [section_name])
|
monitor_db.action('UPDATE library_sections SET do_notify = 1 WHERE section_name = ?', [section_name])
|
||||||
|
@ -943,7 +943,7 @@ class Libraries(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to re-add library, section_id or section_name not valid.'
|
return 'Unable to re-add library, section_id or section_name not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to execute database query for undelete: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to execute database query for undelete: %s." % e)
|
||||||
|
|
||||||
def delete_datatable_media_info_cache(self, section_id=None):
|
def delete_datatable_media_info_cache(self, section_id=None):
|
||||||
import os
|
import os
|
||||||
|
@ -953,12 +953,12 @@ class Libraries(object):
|
||||||
[os.remove(os.path.join(plexpy.CONFIG.CACHE_DIR, f)) for f in os.listdir(plexpy.CONFIG.CACHE_DIR)
|
[os.remove(os.path.join(plexpy.CONFIG.CACHE_DIR, f)) for f in os.listdir(plexpy.CONFIG.CACHE_DIR)
|
||||||
if f.startswith('media_info-%s' % section_id) and f.endswith('.json')]
|
if f.startswith('media_info-%s' % section_id) and f.endswith('.json')]
|
||||||
|
|
||||||
logger.debug(u"PlexPy Libraries :: Deleted media info table cache for section_id %s." % section_id)
|
logger.debug(u"Tautulli Libraries :: Deleted media info table cache for section_id %s." % section_id)
|
||||||
return 'Deleted media info table cache for library with id %s.' % section_id
|
return 'Deleted media info table cache for library with id %s.' % section_id
|
||||||
else:
|
else:
|
||||||
return 'Unable to delete media info table cache, section_id not valid.'
|
return 'Unable to delete media info table cache, section_id not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to delete media info table cache: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to delete media info table cache: %s." % e)
|
||||||
|
|
||||||
def delete_duplicate_libraries(self):
|
def delete_duplicate_libraries(self):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
@ -969,16 +969,16 @@ class Libraries(object):
|
||||||
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug(u"PlexPy Libraries :: Deleting libraries where server_id does not match %s." % server_id)
|
logger.debug(u"Tautulli Libraries :: Deleting libraries where server_id does not match %s." % server_id)
|
||||||
monitor_db.action('DELETE FROM library_sections WHERE server_id != ?', [server_id])
|
monitor_db.action('DELETE FROM library_sections WHERE server_id != ?', [server_id])
|
||||||
|
|
||||||
return 'Deleted duplicate libraries from the database.'
|
return 'Deleted duplicate libraries from the database.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Libraries :: Unable to delete duplicate libraries: %s." % e)
|
logger.warn(u"Tautulli Libraries :: Unable to delete duplicate libraries: %s." % e)
|
||||||
|
|
||||||
|
|
||||||
def update_libraries_db_notify():
|
def update_libraries_db_notify():
|
||||||
logger.info(u"PlexPy Libraries :: Upgrading library notification toggles...")
|
logger.info(u"Tautulli Libraries :: Upgrading library notification toggles...")
|
||||||
|
|
||||||
# Set flag first in case something fails we don't want to keep re-adding the notifiers
|
# Set flag first in case something fails we don't want to keep re-adding the notifiers
|
||||||
plexpy.CONFIG.__setattr__('UPDATE_LIBRARIES_DB_NOTIFY', 0)
|
plexpy.CONFIG.__setattr__('UPDATE_LIBRARIES_DB_NOTIFY', 0)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ def get_log_tail(window=20, parsed=True, log_type="server"):
|
||||||
clean_lines.append(full_line)
|
clean_lines.append(full_line)
|
||||||
|
|
||||||
if line_error:
|
if line_error:
|
||||||
logger.error('PlexPy was unable to parse some lines of the Plex Media Server log.')
|
logger.error('Tautulli was unable to parse some lines of the Plex Media Server log.')
|
||||||
|
|
||||||
return clean_lines
|
return clean_lines
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from logutils.queue import QueueHandler, QueueListener
|
from logutils.queue import QueueHandler, QueueListener
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
|
@ -38,11 +38,11 @@ MAX_FILES = 5
|
||||||
|
|
||||||
_BLACKLIST_WORDS = set()
|
_BLACKLIST_WORDS = set()
|
||||||
|
|
||||||
# PlexPy logger
|
# Tautulli logger
|
||||||
logger = logging.getLogger("plexpy")
|
logger = logging.getLogger("plexpy")
|
||||||
# PlexPy API logger
|
# Tautulli API logger
|
||||||
logger_api = logging.getLogger("plexpy_api")
|
logger_api = logging.getLogger("plexpy_api")
|
||||||
# PlexPy websocket logger
|
# Tautulli websocket logger
|
||||||
logger_plex_websocket = logging.getLogger("plex_websocket")
|
logger_plex_websocket = logging.getLogger("plex_websocket")
|
||||||
|
|
||||||
# Global queue for multiprocessing logging
|
# Global queue for multiprocessing logging
|
||||||
|
@ -177,7 +177,7 @@ def initMultiprocessing():
|
||||||
|
|
||||||
def initLogger(console=False, log_dir=False, verbose=False):
|
def initLogger(console=False, log_dir=False, verbose=False):
|
||||||
"""
|
"""
|
||||||
Setup logging for PlexPy. It uses the logger instance with the name
|
Setup logging for Tautulli. It uses the logger instance with the name
|
||||||
'plexpy'. Three log handlers are added:
|
'plexpy'. Three log handlers are added:
|
||||||
|
|
||||||
* RotatingFileHandler: for the file plexpy.log
|
* RotatingFileHandler: for the file plexpy.log
|
||||||
|
@ -185,7 +185,7 @@ def initLogger(console=False, log_dir=False, verbose=False):
|
||||||
* StreamHandler: for console (if console)
|
* StreamHandler: for console (if console)
|
||||||
|
|
||||||
Console logging is only enabled if console is set to True. This method can
|
Console logging is only enabled if console is set to True. This method can
|
||||||
be invoked multiple times, during different stages of PlexPy.
|
be invoked multiple times, during different stages of Tautulli.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Close and remove old handlers. This is required to reinit the loggers
|
# Close and remove old handlers. This is required to reinit the loggers
|
||||||
|
@ -213,7 +213,7 @@ def initLogger(console=False, log_dir=False, verbose=False):
|
||||||
if log_dir:
|
if log_dir:
|
||||||
file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%Y-%m-%d %H:%M:%S')
|
file_formatter = logging.Formatter('%(asctime)s - %(levelname)-7s :: %(threadName)s : %(message)s', '%Y-%m-%d %H:%M:%S')
|
||||||
|
|
||||||
# Main PlexPy logger
|
# Main Tautulli logger
|
||||||
filename = os.path.join(log_dir, FILENAME)
|
filename = os.path.join(log_dir, FILENAME)
|
||||||
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
||||||
file_handler.setLevel(logging.DEBUG)
|
file_handler.setLevel(logging.DEBUG)
|
||||||
|
@ -221,7 +221,7 @@ def initLogger(console=False, log_dir=False, verbose=False):
|
||||||
|
|
||||||
logger.addHandler(file_handler)
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
# PlexPy API logger
|
# Tautulli API logger
|
||||||
filename = os.path.join(log_dir, FILENAME_API)
|
filename = os.path.join(log_dir, FILENAME_API)
|
||||||
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
||||||
file_handler.setLevel(logging.DEBUG)
|
file_handler.setLevel(logging.DEBUG)
|
||||||
|
@ -229,7 +229,7 @@ def initLogger(console=False, log_dir=False, verbose=False):
|
||||||
|
|
||||||
logger_api.addHandler(file_handler)
|
logger_api.addHandler(file_handler)
|
||||||
|
|
||||||
# PlexPy websocket logger
|
# Tautulli websocket logger
|
||||||
filename = os.path.join(log_dir, FILENAME_PLEX_WEBSOCKET)
|
filename = os.path.join(log_dir, FILENAME_PLEX_WEBSOCKET)
|
||||||
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
file_handler = handlers.RotatingFileHandler(filename, maxBytes=MAX_SIZE, backupCount=MAX_FILES)
|
||||||
file_handler.setLevel(logging.DEBUG)
|
file_handler.setLevel(logging.DEBUG)
|
||||||
|
@ -307,7 +307,7 @@ def initHooks(global_exceptions=True, thread_exceptions=True, pass_original=True
|
||||||
threading.Thread.__init__ = new_init
|
threading.Thread.__init__ = new_init
|
||||||
|
|
||||||
# Expose logger methods
|
# Expose logger methods
|
||||||
# Main PlexPy logger
|
# Main Tautulli logger
|
||||||
info = logger.info
|
info = logger.info
|
||||||
warn = logger.warn
|
warn = logger.warn
|
||||||
error = logger.error
|
error = logger.error
|
||||||
|
@ -315,7 +315,7 @@ debug = logger.debug
|
||||||
warning = logger.warning
|
warning = logger.warning
|
||||||
exception = logger.exception
|
exception = logger.exception
|
||||||
|
|
||||||
# PlexPy API logger
|
# Tautulli API logger
|
||||||
api_info = logger_api.info
|
api_info = logger_api.info
|
||||||
api_warn = logger_api.warn
|
api_warn = logger_api.warn
|
||||||
api_error = logger_api.error
|
api_error = logger_api.error
|
||||||
|
@ -323,7 +323,7 @@ api_debug = logger_api.debug
|
||||||
api_warning = logger_api.warning
|
api_warning = logger_api.warning
|
||||||
api_exception = logger_api.exception
|
api_exception = logger_api.exception
|
||||||
|
|
||||||
# PlexPy websocket logger
|
# Tautulli websocket logger
|
||||||
websocket_info = logger_plex_websocket.info
|
websocket_info = logger_plex_websocket.info
|
||||||
websocket_warn = logger_plex_websocket.warn
|
websocket_warn = logger_plex_websocket.warn
|
||||||
websocket_error = logger_plex_websocket.error
|
websocket_error = logger_plex_websocket.error
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -64,13 +64,13 @@ def add_mobile_device(device_id=None, device_name=None, device_token=None, frien
|
||||||
try:
|
try:
|
||||||
result = db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
result = db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy MobileApp :: Failed to register mobile device in the database: %s." % e)
|
logger.warn(u"Tautulli MobileApp :: Failed to register mobile device in the database: %s." % e)
|
||||||
return
|
return
|
||||||
|
|
||||||
if result == 'insert':
|
if result == 'insert':
|
||||||
logger.info(u"PlexPy MobileApp :: Registered mobile device '%s' in the database." % device_name)
|
logger.info(u"Tautulli MobileApp :: Registered mobile device '%s' in the database." % device_name)
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy MobileApp :: Re-registered mobile device '%s' in the database." % device_name)
|
logger.debug(u"Tautulli MobileApp :: Re-registered mobile device '%s' in the database." % device_name)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ def get_mobile_device_config(mobile_device_id=None):
|
||||||
if str(mobile_device_id).isdigit():
|
if str(mobile_device_id).isdigit():
|
||||||
mobile_device_id = int(mobile_device_id)
|
mobile_device_id = int(mobile_device_id)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy MobileApp :: Unable to retrieve mobile device config: invalid mobile_device_id %s." % mobile_device_id)
|
logger.error(u"Tautulli MobileApp :: Unable to retrieve mobile device config: invalid mobile_device_id %s." % mobile_device_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
@ -93,7 +93,7 @@ def set_mobile_device_config(mobile_device_id=None, **kwargs):
|
||||||
if str(mobile_device_id).isdigit():
|
if str(mobile_device_id).isdigit():
|
||||||
mobile_device_id = int(mobile_device_id)
|
mobile_device_id = int(mobile_device_id)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy MobileApp :: Unable to set exisiting mobile device: invalid mobile_device_id %s." % mobile_device_id)
|
logger.error(u"Tautulli MobileApp :: Unable to set exisiting mobile device: invalid mobile_device_id %s." % mobile_device_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
keys = {'id': mobile_device_id}
|
keys = {'id': mobile_device_id}
|
||||||
|
@ -105,10 +105,10 @@ def set_mobile_device_config(mobile_device_id=None, **kwargs):
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
db.upsert(table_name='mobile_devices', key_dict=keys, value_dict=values)
|
||||||
logger.info(u"PlexPy MobileApp :: Updated mobile device agent: mobile_device_id %s." % mobile_device_id)
|
logger.info(u"Tautulli MobileApp :: Updated mobile device agent: mobile_device_id %s." % mobile_device_id)
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy MobileApp :: Unable to update mobile device: %s." % e)
|
logger.warn(u"Tautulli MobileApp :: Unable to update mobile device: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ def delete_mobile_device(mobile_device_id=None):
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
|
||||||
if mobile_device_id:
|
if mobile_device_id:
|
||||||
logger.debug(u"PlexPy MobileApp :: Deleting device_id %s from the database." % mobile_device_id)
|
logger.debug(u"Tautulli MobileApp :: Deleting device_id %s from the database." % mobile_device_id)
|
||||||
result = db.action('DELETE FROM mobile_devices WHERE id = ?', args=[mobile_device_id])
|
result = db.action('DELETE FROM mobile_devices WHERE id = ?', args=[mobile_device_id])
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
|
@ -132,7 +132,7 @@ def set_last_seen(device_token=None):
|
||||||
result = db.action('UPDATE mobile_devices SET last_seen = ? WHERE device_token = ?',
|
result = db.action('UPDATE mobile_devices SET last_seen = ? WHERE device_token = ?',
|
||||||
args=[last_seen, device_token])
|
args=[last_seen, device_token])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy MobileApp :: Failed to set last_seen time for device: %s." % e)
|
logger.warn(u"Tautulli MobileApp :: Failed to set last_seen time for device: %s." % e)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
|
@ -54,15 +54,15 @@ def process_queue():
|
||||||
else:
|
else:
|
||||||
add_notifier_each(**params)
|
add_notifier_each(**params)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(u"PlexPy NotificationHandler :: Notification thread exception: %s" % e)
|
logger.exception(u"Tautulli NotificationHandler :: Notification thread exception: %s" % e)
|
||||||
|
|
||||||
queue.task_done()
|
queue.task_done()
|
||||||
|
|
||||||
logger.info(u"PlexPy NotificationHandler :: Notification thread exiting...")
|
logger.info(u"Tautulli NotificationHandler :: Notification thread exiting...")
|
||||||
|
|
||||||
|
|
||||||
def start_threads(num_threads=1):
|
def start_threads(num_threads=1):
|
||||||
logger.info(u"PlexPy NotificationHandler :: Starting background notification handler ({} threads).".format(num_threads))
|
logger.info(u"Tautulli NotificationHandler :: Starting background notification handler ({} threads).".format(num_threads))
|
||||||
for x in range(num_threads):
|
for x in range(num_threads):
|
||||||
thread = threading.Thread(target=process_queue)
|
thread = threading.Thread(target=process_queue)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
|
@ -71,7 +71,7 @@ def start_threads(num_threads=1):
|
||||||
|
|
||||||
def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, timeline_data=None, manual_trigger=False, **kwargs):
|
def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, timeline_data=None, manual_trigger=False, **kwargs):
|
||||||
if not notify_action:
|
if not notify_action:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Notify called but no action received.")
|
logger.debug(u"Tautulli NotificationHandler :: Notify called but no action received.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if notifier_id:
|
if notifier_id:
|
||||||
|
@ -101,7 +101,7 @@ def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, ti
|
||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
if not parameters:
|
if not parameters:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Failed to build notification parameters.")
|
logger.error(u"Tautulli NotificationHandler :: Failed to build notification parameters.")
|
||||||
return
|
return
|
||||||
|
|
||||||
for notifier in notifiers_enabled:
|
for notifier in notifiers_enabled:
|
||||||
|
@ -117,7 +117,7 @@ def add_notifier_each(notifier_id=None, notify_action=None, stream_data=None, ti
|
||||||
data.update(kwargs)
|
data.update(kwargs)
|
||||||
plexpy.NOTIFY_QUEUE.put(data)
|
plexpy.NOTIFY_QUEUE.put(data)
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Custom notification conditions not satisfied, skipping notifier_id %s." % notifier['id'])
|
logger.debug(u"Tautulli NotificationHandler :: Custom notification conditions not satisfied, skipping notifier_id %s." % notifier['id'])
|
||||||
|
|
||||||
# Add on_concurrent and on_newdevice to queue if action is on_play
|
# Add on_concurrent and on_newdevice to queue if action is on_play
|
||||||
if notify_action == 'on_play':
|
if notify_action == 'on_play':
|
||||||
|
@ -137,11 +137,11 @@ def notify_conditions(notify_action=None, stream_data=None, timeline_data=None):
|
||||||
library_details = library_data.get_details(section_id=stream_data['section_id'])
|
library_details = library_data.get_details(section_id=stream_data['section_id'])
|
||||||
|
|
||||||
if not user_details['do_notify']:
|
if not user_details['do_notify']:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Notifications for user '%s' are disabled." % user_details['username'])
|
logger.debug(u"Tautulli NotificationHandler :: Notifications for user '%s' are disabled." % user_details['username'])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif not library_details['do_notify'] and notify_action not in ('on_concurrent', 'on_newdevice'):
|
elif not library_details['do_notify'] and notify_action not in ('on_concurrent', 'on_newdevice'):
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Notifications for library '%s' are disabled." % library_details['section_name'])
|
logger.debug(u"Tautulli NotificationHandler :: Notifications for library '%s' are disabled." % library_details['section_name'])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if notify_action == 'on_concurrent':
|
if notify_action == 'on_concurrent':
|
||||||
|
@ -184,7 +184,7 @@ def notify_conditions(notify_action=None, stream_data=None, timeline_data=None):
|
||||||
library_details = library_data.get_details(section_id=timeline_data['section_id'])
|
library_details = library_data.get_details(section_id=timeline_data['section_id'])
|
||||||
|
|
||||||
if not library_details['do_notify_created']:
|
if not library_details['do_notify_created']:
|
||||||
# logger.debug(u"PlexPy NotificationHandler :: Notifications for library '%s' is disabled." % library_details['section_name'])
|
# logger.debug(u"Tautulli NotificationHandler :: Notifications for library '%s' is disabled." % library_details['section_name'])
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -200,7 +200,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
|
||||||
custom_conditions_logic = notifier_config['custom_conditions_logic']
|
custom_conditions_logic = notifier_config['custom_conditions_logic']
|
||||||
|
|
||||||
if custom_conditions_logic:
|
if custom_conditions_logic:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Checking custom notification conditions for notifier_id %s." % notifier_id)
|
logger.debug(u"Tautulli NotificationHandler :: Checking custom notification conditions for notifier_id %s." % notifier_id)
|
||||||
|
|
||||||
custom_conditions = json.loads(notifier_config['custom_conditions'])
|
custom_conditions = json.loads(notifier_config['custom_conditions'])
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
|
||||||
# Parse and validate the custom conditions logic
|
# Parse and validate the custom conditions logic
|
||||||
logic_groups = helpers.parse_condition_logic_string(custom_conditions_logic, len(custom_conditions))
|
logic_groups = helpers.parse_condition_logic_string(custom_conditions_logic, len(custom_conditions))
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom condition logic '%s': %s."
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse custom condition logic '%s': %s."
|
||||||
% (custom_conditions_logic, e))
|
% (custom_conditions_logic, e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
|
||||||
values = [float(v) for v in values]
|
values = [float(v) for v in values]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to cast condition '%s' to type '%s'."
|
logger.error(u"Tautulli NotificationHandler :: Unable to cast condition '%s' to type '%s'."
|
||||||
% (parameter, parameter_type))
|
% (parameter, parameter_type))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -257,7 +257,7 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
|
||||||
parameter_value = float(parameters[parameter])
|
parameter_value = float(parameters[parameter])
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to cast parameter '%s' to type '%s'."
|
logger.error(u"Tautulli NotificationHandler :: Unable to cast parameter '%s' to type '%s'."
|
||||||
% (parameter, parameter_type))
|
% (parameter, parameter_type))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -287,17 +287,17 @@ def notify_custom_conditions(notifier_id=None, parameters=None):
|
||||||
evaluated_conditions.append(any(parameter_value < c for c in values))
|
evaluated_conditions.append(any(parameter_value < c for c in values))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy NotificationHandler :: Invalid condition operator '%s'." % operator)
|
logger.warn(u"Tautulli NotificationHandler :: Invalid condition operator '%s'." % operator)
|
||||||
evaluated_conditions.append(None)
|
evaluated_conditions.append(None)
|
||||||
|
|
||||||
# Format and evaluate the logic string
|
# Format and evaluate the logic string
|
||||||
try:
|
try:
|
||||||
evaluated_logic = helpers.eval_logic_groups_to_bool(logic_groups, evaluated_conditions)
|
evaluated_logic = helpers.eval_logic_groups_to_bool(logic_groups, evaluated_conditions)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to evaluate custom condition logic: %s." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to evaluate custom condition logic: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Custom condition evaluated to '%s'." % str(evaluated_logic))
|
logger.debug(u"Tautulli NotificationHandler :: Custom condition evaluated to '%s'." % str(evaluated_logic))
|
||||||
return evaluated_logic
|
return evaluated_logic
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -311,7 +311,7 @@ def notify(notifier_id=None, notify_action=None, stream_data=None, timeline_data
|
||||||
# Return if the notification has already been sent
|
# Return if the notification has already been sent
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(u"PlexPy NotificationHandler :: Preparing notifications for notifier_id %s." % notifier_id)
|
logger.info(u"Tautulli NotificationHandler :: Preparing notifications for notifier_id %s." % notifier_id)
|
||||||
|
|
||||||
notifier_config = notifiers.get_notifier_config(notifier_id=notifier_id)
|
notifier_config = notifiers.get_notifier_config(notifier_id=notifier_id)
|
||||||
|
|
||||||
|
@ -319,7 +319,7 @@ def notify(notifier_id=None, notify_action=None, stream_data=None, timeline_data
|
||||||
return
|
return
|
||||||
|
|
||||||
if notify_action == 'test':
|
if notify_action == 'test':
|
||||||
subject = kwargs.pop('subject', 'PlexPy')
|
subject = kwargs.pop('subject', 'Tautulli')
|
||||||
body = kwargs.pop('body', 'Test Notification')
|
body = kwargs.pop('body', 'Test Notification')
|
||||||
script_args = kwargs.pop('script_args', [])
|
script_args = kwargs.pop('script_args', [])
|
||||||
else:
|
else:
|
||||||
|
@ -404,7 +404,7 @@ def set_notify_state(notify_action, notifier, subject, body, script_args, sessio
|
||||||
monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values)
|
monitor_db.upsert(table_name='notify_log', key_dict=keys, value_dict=values)
|
||||||
return monitor_db.last_insert_id()
|
return monitor_db.last_insert_id()
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to set notify state.")
|
logger.error(u"Tautulli NotificationHandler :: Unable to set notify state.")
|
||||||
|
|
||||||
|
|
||||||
def set_notify_success(notification_id):
|
def set_notify_success(notification_id):
|
||||||
|
@ -432,7 +432,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||||
updated_at = server_times['updated_at']
|
updated_at = server_times['updated_at']
|
||||||
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
|
logger.error(u"Tautulli NotificationHandler :: Unable to retrieve server uptime.")
|
||||||
server_uptime = 'N/A'
|
server_uptime = 'N/A'
|
||||||
|
|
||||||
# Get metadata for the item
|
# Get metadata for the item
|
||||||
|
@ -445,7 +445,7 @@ def build_media_notify_params(notify_action=None, session=None, timeline=None, m
|
||||||
metadata = pms_connect.get_metadata_details(rating_key=rating_key)
|
metadata = pms_connect.get_metadata_details(rating_key=rating_key)
|
||||||
|
|
||||||
if not metadata:
|
if not metadata:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
logger.error(u"Tautulli NotificationHandler :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
## TODO: Check list of media info items, currently only grabs first item
|
## TODO: Check list of media info items, currently only grabs first item
|
||||||
|
@ -827,7 +827,7 @@ def build_server_notify_params(notify_action=None, **kwargs):
|
||||||
updated_at = server_times['updated_at']
|
updated_at = server_times['updated_at']
|
||||||
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
server_uptime = helpers.human_duration(int(time.time() - helpers.cast_to_int(updated_at)))
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve server uptime.")
|
logger.error(u"Tautulli NotificationHandler :: Unable to retrieve server uptime.")
|
||||||
server_uptime = 'N/A'
|
server_uptime = 'N/A'
|
||||||
|
|
||||||
available_params = {# Global paramaters
|
available_params = {# Global paramaters
|
||||||
|
@ -853,7 +853,7 @@ def build_server_notify_params(notify_action=None, **kwargs):
|
||||||
'update_extra_info': pms_download_info.get('extra_info',''),
|
'update_extra_info': pms_download_info.get('extra_info',''),
|
||||||
'update_changelog_added': pms_download_info.get('changelog_added',''),
|
'update_changelog_added': pms_download_info.get('changelog_added',''),
|
||||||
'update_changelog_fixed': pms_download_info.get('changelog_fixed',''),
|
'update_changelog_fixed': pms_download_info.get('changelog_fixed',''),
|
||||||
# PlexPy update parameters
|
# Tautulli update parameters
|
||||||
'plexpy_update_version': plexpy_download_info.get('tag_name', ''),
|
'plexpy_update_version': plexpy_download_info.get('tag_name', ''),
|
||||||
'plexpy_update_tar': plexpy_download_info.get('tarball_url', ''),
|
'plexpy_update_tar': plexpy_download_info.get('tarball_url', ''),
|
||||||
'plexpy_update_zip': plexpy_download_info.get('zipball_url', ''),
|
'plexpy_update_zip': plexpy_download_info.get('zipball_url', ''),
|
||||||
|
@ -876,10 +876,10 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
|
||||||
|
|
||||||
# Make sure subject and body text are strings
|
# Make sure subject and body text are strings
|
||||||
if not isinstance(subject, basestring):
|
if not isinstance(subject, basestring):
|
||||||
logger.error(u"PlexPy NotificationHandler :: Invalid subject text. Using fallback.")
|
logger.error(u"Tautulli NotificationHandler :: Invalid subject text. Using fallback.")
|
||||||
subject = default_subject
|
subject = default_subject
|
||||||
if not isinstance(body, basestring):
|
if not isinstance(body, basestring):
|
||||||
logger.error(u"PlexPy NotificationHandler :: Invalid body text. Using fallback.")
|
logger.error(u"Tautulli NotificationHandler :: Invalid body text. Using fallback.")
|
||||||
body = default_body
|
body = default_body
|
||||||
|
|
||||||
media_type = parameters.get('media_type')
|
media_type = parameters.get('media_type')
|
||||||
|
@ -919,10 +919,10 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
|
||||||
try:
|
try:
|
||||||
script_args = [custom_formatter.format(unicode(arg), **parameters) for arg in subject.split()]
|
script_args = [custom_formatter.format(unicode(arg), **parameters) for arg in subject.split()]
|
||||||
except LookupError as e:
|
except LookupError as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in script argument. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse field %s in script argument. Using fallback." % e)
|
||||||
script_args = []
|
script_args = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom script arguments: %s. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse custom script arguments: %s. Using fallback." % e)
|
||||||
script_args = []
|
script_args = []
|
||||||
else:
|
else:
|
||||||
script_args = []
|
script_args = []
|
||||||
|
@ -930,19 +930,19 @@ def build_notify_text(subject='', body='', notify_action=None, parameters=None,
|
||||||
try:
|
try:
|
||||||
subject = custom_formatter.format(unicode(subject), **parameters)
|
subject = custom_formatter.format(unicode(subject), **parameters)
|
||||||
except LookupError as e:
|
except LookupError as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse field %s in notification subject. Using fallback." % e)
|
||||||
subject = unicode(default_subject).format(**parameters)
|
subject = unicode(default_subject).format(**parameters)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification subject: %s. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse custom notification subject: %s. Using fallback." % e)
|
||||||
subject = unicode(default_subject).format(**parameters)
|
subject = unicode(default_subject).format(**parameters)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
body = custom_formatter.format(unicode(body), **parameters)
|
body = custom_formatter.format(unicode(body), **parameters)
|
||||||
except LookupError as e:
|
except LookupError as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse field %s in notification body. Using fallback." % e)
|
||||||
body = unicode(default_body).format(**parameters)
|
body = unicode(default_body).format(**parameters)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to parse custom notification body: %s. Using fallback." % e)
|
logger.error(u"Tautulli NotificationHandler :: Unable to parse custom notification body: %s. Using fallback." % e)
|
||||||
body = unicode(default_body).format(**parameters)
|
body = unicode(default_body).format(**parameters)
|
||||||
|
|
||||||
return subject, body, script_args
|
return subject, body, script_args
|
||||||
|
@ -1030,7 +1030,7 @@ def get_poster_info(poster_thumb, poster_key, poster_title):
|
||||||
# Delete the cached poster
|
# Delete the cached poster
|
||||||
os.remove(poster_file)
|
os.remove(poster_file)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy NotificationHandler :: Unable to retrieve poster for rating_key %s: %s." % (str(metadata['rating_key']), e))
|
logger.error(u"Tautulli NotificationHandler :: Unable to retrieve poster for rating_key %s: %s." % (str(metadata['rating_key']), e))
|
||||||
|
|
||||||
return poster_info
|
return poster_info
|
||||||
|
|
||||||
|
@ -1043,16 +1043,16 @@ def lookup_tvmaze_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
|
||||||
'WHERE rating_key = ?'
|
'WHERE rating_key = ?'
|
||||||
tvmaze_info = db.select_single(query, args=[rating_key])
|
tvmaze_info = db.select_single(query, args=[rating_key])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy NotificationHandler :: Unable to execute database query for lookup_tvmaze_by_tvdb_id: %s." % e)
|
logger.warn(u"Tautulli NotificationHandler :: Unable to execute database query for lookup_tvmaze_by_tvdb_id: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not tvmaze_info:
|
if not tvmaze_info:
|
||||||
tvmaze_info = {}
|
tvmaze_info = {}
|
||||||
|
|
||||||
if thetvdb_id:
|
if thetvdb_id:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Looking up TVmaze info for thetvdb_id '{}'.".format(thetvdb_id))
|
logger.debug(u"Tautulli NotificationHandler :: Looking up TVmaze info for thetvdb_id '{}'.".format(thetvdb_id))
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Looking up TVmaze info for imdb_id '{}'.".format(imdb_id))
|
logger.debug(u"Tautulli NotificationHandler :: Looking up TVmaze info for imdb_id '{}'.".format(imdb_id))
|
||||||
|
|
||||||
params = {'thetvdb': thetvdb_id} if thetvdb_id else {'imdb': imdb_id}
|
params = {'thetvdb': thetvdb_id} if thetvdb_id else {'imdb': imdb_id}
|
||||||
response, err_msg, req_msg = request.request_response2('http://api.tvmaze.com/lookup/shows', params=params)
|
response, err_msg, req_msg = request.request_response2('http://api.tvmaze.com/lookup/shows', params=params)
|
||||||
|
@ -1076,10 +1076,10 @@ def lookup_tvmaze_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if err_msg:
|
if err_msg:
|
||||||
logger.error(u"PlexPy NotificationHandler :: {}".format(err_msg))
|
logger.error(u"Tautulli NotificationHandler :: {}".format(err_msg))
|
||||||
|
|
||||||
if req_msg:
|
if req_msg:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Request response: {}".format(req_msg))
|
logger.debug(u"Tautulli NotificationHandler :: Request response: {}".format(req_msg))
|
||||||
|
|
||||||
return tvmaze_info
|
return tvmaze_info
|
||||||
|
|
||||||
|
@ -1092,16 +1092,16 @@ def lookup_themoviedb_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
|
||||||
'WHERE rating_key = ?'
|
'WHERE rating_key = ?'
|
||||||
themoviedb_info = db.select_single(query, args=[rating_key])
|
themoviedb_info = db.select_single(query, args=[rating_key])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy NotificationHandler :: Unable to execute database query for lookup_themoviedb_by_imdb_id: %s." % e)
|
logger.warn(u"Tautulli NotificationHandler :: Unable to execute database query for lookup_themoviedb_by_imdb_id: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not themoviedb_info:
|
if not themoviedb_info:
|
||||||
themoviedb_info = {}
|
themoviedb_info = {}
|
||||||
|
|
||||||
if thetvdb_id:
|
if thetvdb_id:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Looking up The Movie Database info for thetvdb_id '{}'.".format(thetvdb_id))
|
logger.debug(u"Tautulli NotificationHandler :: Looking up The Movie Database info for thetvdb_id '{}'.".format(thetvdb_id))
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Looking up The Movie Database info for imdb_id '{}'.".format(imdb_id))
|
logger.debug(u"Tautulli NotificationHandler :: Looking up The Movie Database info for imdb_id '{}'.".format(imdb_id))
|
||||||
|
|
||||||
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY,
|
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY,
|
||||||
'external_source': 'tvdb_id' if thetvdb_id else 'imdb_id'
|
'external_source': 'tvdb_id' if thetvdb_id else 'imdb_id'
|
||||||
|
@ -1138,10 +1138,10 @@ def lookup_themoviedb_by_id(rating_key=None, thetvdb_id=None, imdb_id=None):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if err_msg:
|
if err_msg:
|
||||||
logger.error(u"PlexPy NotificationHandler :: {}".format(err_msg))
|
logger.error(u"Tautulli NotificationHandler :: {}".format(err_msg))
|
||||||
|
|
||||||
if req_msg:
|
if req_msg:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Request response: {}".format(req_msg))
|
logger.debug(u"Tautulli NotificationHandler :: Request response: {}".format(req_msg))
|
||||||
|
|
||||||
return themoviedb_info
|
return themoviedb_info
|
||||||
|
|
||||||
|
@ -1157,7 +1157,7 @@ def get_themoviedb_info(rating_key=None, media_type=None, themoviedb_id=None):
|
||||||
'WHERE rating_key = ?'
|
'WHERE rating_key = ?'
|
||||||
result = db.select_single(query, args=[rating_key])
|
result = db.select_single(query, args=[rating_key])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy NotificationHandler :: Unable to execute database query for get_themoviedb_info: %s." % e)
|
logger.warn(u"Tautulli NotificationHandler :: Unable to execute database query for get_themoviedb_info: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
|
@ -1168,7 +1168,7 @@ def get_themoviedb_info(rating_key=None, media_type=None, themoviedb_id=None):
|
||||||
|
|
||||||
themoviedb_json = {}
|
themoviedb_json = {}
|
||||||
|
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Looking up The Movie Database info for themoviedb_id '{}'.".format(themoviedb_id))
|
logger.debug(u"Tautulli NotificationHandler :: Looking up The Movie Database info for themoviedb_id '{}'.".format(themoviedb_id))
|
||||||
|
|
||||||
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY}
|
params = {'api_key': plexpy.CONFIG.THEMOVIEDB_APIKEY}
|
||||||
response, err_msg, req_msg = request.request_response2('https://api.themoviedb.org/3/{}/{}'.format(media_type, themoviedb_id), params=params)
|
response, err_msg, req_msg = request.request_response2('https://api.themoviedb.org/3/{}/{}'.format(media_type, themoviedb_id), params=params)
|
||||||
|
@ -1178,10 +1178,10 @@ def get_themoviedb_info(rating_key=None, media_type=None, themoviedb_id=None):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if err_msg:
|
if err_msg:
|
||||||
logger.error(u"PlexPy NotificationHandler :: {}".format(err_msg))
|
logger.error(u"Tautulli NotificationHandler :: {}".format(err_msg))
|
||||||
|
|
||||||
if req_msg:
|
if req_msg:
|
||||||
logger.debug(u"PlexPy NotificationHandler :: Request response: {}".format(req_msg))
|
logger.debug(u"Tautulli NotificationHandler :: Request response: {}".format(req_msg))
|
||||||
|
|
||||||
return themoviedb_json
|
return themoviedb_json
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import bleach
|
import bleach
|
||||||
|
@ -92,7 +92,7 @@ AGENT_IDS = {'growl': 0,
|
||||||
|
|
||||||
|
|
||||||
def available_notification_agents():
|
def available_notification_agents():
|
||||||
agents = [{'label': 'PlexPy Android App',
|
agents = [{'label': 'Tautulli Remote Android App',
|
||||||
'name': 'androidapp',
|
'name': 'androidapp',
|
||||||
'id': AGENT_IDS['androidapp']
|
'id': AGENT_IDS['androidapp']
|
||||||
},
|
},
|
||||||
|
@ -200,7 +200,7 @@ def available_notification_actions():
|
||||||
actions = [{'label': 'Playback Start',
|
actions = [{'label': 'Playback Start',
|
||||||
'name': 'on_play',
|
'name': 'on_play',
|
||||||
'description': 'Trigger a notification when a stream is started.',
|
'description': 'Trigger a notification when a stream is started.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) started playing {title}.',
|
'body': '{user} ({player}) started playing {title}.',
|
||||||
'icon': 'fa-play',
|
'icon': 'fa-play',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -208,7 +208,7 @@ def available_notification_actions():
|
||||||
{'label': 'Playback Stop',
|
{'label': 'Playback Stop',
|
||||||
'name': 'on_stop',
|
'name': 'on_stop',
|
||||||
'description': 'Trigger a notification when a stream is stopped.',
|
'description': 'Trigger a notification when a stream is stopped.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) has stopped {title}.',
|
'body': '{user} ({player}) has stopped {title}.',
|
||||||
'icon': 'fa-stop',
|
'icon': 'fa-stop',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -216,7 +216,7 @@ def available_notification_actions():
|
||||||
{'label': 'Playback Pause',
|
{'label': 'Playback Pause',
|
||||||
'name': 'on_pause',
|
'name': 'on_pause',
|
||||||
'description': 'Trigger a notification when a stream is paused.',
|
'description': 'Trigger a notification when a stream is paused.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) has paused {title}.',
|
'body': '{user} ({player}) has paused {title}.',
|
||||||
'icon': 'fa-pause',
|
'icon': 'fa-pause',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -224,7 +224,7 @@ def available_notification_actions():
|
||||||
{'label': 'Playback Resume',
|
{'label': 'Playback Resume',
|
||||||
'name': 'on_resume',
|
'name': 'on_resume',
|
||||||
'description': 'Trigger a notification when a stream is resumed.',
|
'description': 'Trigger a notification when a stream is resumed.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) has resumed {title}.',
|
'body': '{user} ({player}) has resumed {title}.',
|
||||||
'icon': 'fa-play',
|
'icon': 'fa-play',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -232,7 +232,7 @@ def available_notification_actions():
|
||||||
{'label': 'Watched',
|
{'label': 'Watched',
|
||||||
'name': 'on_watched',
|
'name': 'on_watched',
|
||||||
'description': 'Trigger a notification when a video stream reaches the specified watch percentage.',
|
'description': 'Trigger a notification when a video stream reaches the specified watch percentage.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) has watched {title}.',
|
'body': '{user} ({player}) has watched {title}.',
|
||||||
'icon': 'fa-eye',
|
'icon': 'fa-eye',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -240,7 +240,7 @@ def available_notification_actions():
|
||||||
{'label': 'Buffer Warning',
|
{'label': 'Buffer Warning',
|
||||||
'name': 'on_buffer',
|
'name': 'on_buffer',
|
||||||
'description': 'Trigger a notification when a stream exceeds the specified buffer threshold.',
|
'description': 'Trigger a notification when a stream exceeds the specified buffer threshold.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} ({player}) is buffering {title}.',
|
'body': '{user} ({player}) is buffering {title}.',
|
||||||
'icon': 'fa-spinner',
|
'icon': 'fa-spinner',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -248,7 +248,7 @@ def available_notification_actions():
|
||||||
{'label': 'User Concurrent Streams',
|
{'label': 'User Concurrent Streams',
|
||||||
'name': 'on_concurrent',
|
'name': 'on_concurrent',
|
||||||
'description': 'Trigger a notification when a user exceeds the concurrent stream threshold.',
|
'description': 'Trigger a notification when a user exceeds the concurrent stream threshold.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} has {user_streams} concurrent streams.',
|
'body': '{user} has {user_streams} concurrent streams.',
|
||||||
'icon': 'fa-arrow-circle-o-right',
|
'icon': 'fa-arrow-circle-o-right',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -256,7 +256,7 @@ def available_notification_actions():
|
||||||
{'label': 'User New Device',
|
{'label': 'User New Device',
|
||||||
'name': 'on_newdevice',
|
'name': 'on_newdevice',
|
||||||
'description': 'Trigger a notification when a user streams from a new device.',
|
'description': 'Trigger a notification when a user streams from a new device.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{user} is streaming from a new device: {player}.',
|
'body': '{user} is streaming from a new device: {player}.',
|
||||||
'icon': 'fa-desktop',
|
'icon': 'fa-desktop',
|
||||||
'media_types': ('movie', 'episode', 'track')
|
'media_types': ('movie', 'episode', 'track')
|
||||||
|
@ -264,7 +264,7 @@ def available_notification_actions():
|
||||||
{'label': 'Recently Added',
|
{'label': 'Recently Added',
|
||||||
'name': 'on_created',
|
'name': 'on_created',
|
||||||
'description': 'Trigger a notification when a media item is added to the Plex Media Server.',
|
'description': 'Trigger a notification when a media item is added to the Plex Media Server.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': '{title} was recently added to Plex.',
|
'body': '{title} was recently added to Plex.',
|
||||||
'icon': 'fa-download',
|
'icon': 'fa-download',
|
||||||
'media_types': ('movie', 'show', 'season', 'episode', 'artist', 'album', 'track')
|
'media_types': ('movie', 'show', 'season', 'episode', 'artist', 'album', 'track')
|
||||||
|
@ -272,7 +272,7 @@ def available_notification_actions():
|
||||||
{'label': 'Plex Server Down',
|
{'label': 'Plex Server Down',
|
||||||
'name': 'on_intdown',
|
'name': 'on_intdown',
|
||||||
'description': 'Trigger a notification when the Plex Media Server cannot be reached internally.',
|
'description': 'Trigger a notification when the Plex Media Server cannot be reached internally.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'The Plex Media Server is down.',
|
'body': 'The Plex Media Server is down.',
|
||||||
'icon': 'fa-server',
|
'icon': 'fa-server',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
|
@ -280,7 +280,7 @@ def available_notification_actions():
|
||||||
{'label': 'Plex Server Back Up',
|
{'label': 'Plex Server Back Up',
|
||||||
'name': 'on_intup',
|
'name': 'on_intup',
|
||||||
'description': 'Trigger a notification when the Plex Media Server can be reached internally after being down.',
|
'description': 'Trigger a notification when the Plex Media Server can be reached internally after being down.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'The Plex Media Server is back up.',
|
'body': 'The Plex Media Server is back up.',
|
||||||
'icon': 'fa-server',
|
'icon': 'fa-server',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
|
@ -288,7 +288,7 @@ def available_notification_actions():
|
||||||
{'label': 'Plex Remote Access Down',
|
{'label': 'Plex Remote Access Down',
|
||||||
'name': 'on_extdown',
|
'name': 'on_extdown',
|
||||||
'description': 'Trigger a notification when the Plex Media Server cannot be reached externally.',
|
'description': 'Trigger a notification when the Plex Media Server cannot be reached externally.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'The Plex Media Server remote access is down.',
|
'body': 'The Plex Media Server remote access is down.',
|
||||||
'icon': 'fa-server',
|
'icon': 'fa-server',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
|
@ -296,7 +296,7 @@ def available_notification_actions():
|
||||||
{'label': 'Plex Remote Access Back Up',
|
{'label': 'Plex Remote Access Back Up',
|
||||||
'name': 'on_extup',
|
'name': 'on_extup',
|
||||||
'description': 'Trigger a notification when the Plex Media Server can be reached externally after being down.',
|
'description': 'Trigger a notification when the Plex Media Server can be reached externally after being down.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'The Plex Media Server remote access is back up.',
|
'body': 'The Plex Media Server remote access is back up.',
|
||||||
'icon': 'fa-server',
|
'icon': 'fa-server',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
|
@ -304,16 +304,16 @@ def available_notification_actions():
|
||||||
{'label': 'Plex Update Available',
|
{'label': 'Plex Update Available',
|
||||||
'name': 'on_pmsupdate',
|
'name': 'on_pmsupdate',
|
||||||
'description': 'Trigger a notification when an update for the Plex Media Server is available.',
|
'description': 'Trigger a notification when an update for the Plex Media Server is available.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'An update is available for the Plex Media Server (version {update_version}).',
|
'body': 'An update is available for the Plex Media Server (version {update_version}).',
|
||||||
'icon': 'fa-refresh',
|
'icon': 'fa-refresh',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
},
|
},
|
||||||
{'label': 'PlexPy Update Available',
|
{'label': 'Tautulli Update Available',
|
||||||
'name': 'on_plexpyupdate',
|
'name': 'on_plexpyupdate',
|
||||||
'description': 'Trigger a notification when an update for the PlexPy is available.',
|
'description': 'Trigger a notification when an update for the Tautulli is available.',
|
||||||
'subject': 'PlexPy ({server_name})',
|
'subject': 'Tautulli ({server_name})',
|
||||||
'body': 'An update is available for PlexPy (version {plexpy_update_version}).',
|
'body': 'An update is available for Tautulli (version {plexpy_update_version}).',
|
||||||
'icon': 'fa-refresh',
|
'icon': 'fa-refresh',
|
||||||
'media_types': ('server',)
|
'media_types': ('server',)
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ def delete_notifier(notifier_id=None):
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
|
||||||
if str(notifier_id).isdigit():
|
if str(notifier_id).isdigit():
|
||||||
logger.debug(u"PlexPy Notifiers :: Deleting notifier_id %s from the database." % notifier_id)
|
logger.debug(u"Tautulli Notifiers :: Deleting notifier_id %s from the database." % notifier_id)
|
||||||
result = db.action('DELETE FROM notifiers WHERE id = ?',
|
result = db.action('DELETE FROM notifiers WHERE id = ?',
|
||||||
args=[notifier_id])
|
args=[notifier_id])
|
||||||
return True
|
return True
|
||||||
|
@ -430,7 +430,7 @@ def get_notifier_config(notifier_id=None):
|
||||||
if str(notifier_id).isdigit():
|
if str(notifier_id).isdigit():
|
||||||
notifier_id = int(notifier_id)
|
notifier_id = int(notifier_id)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve notifier config: invalid notifier_id %s." % notifier_id)
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve notifier config: invalid notifier_id %s." % notifier_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
|
@ -445,7 +445,7 @@ def get_notifier_config(notifier_id=None):
|
||||||
notifier_agent = get_agent_class(agent_id=result['agent_id'], config=config)
|
notifier_agent = get_agent_class(agent_id=result['agent_id'], config=config)
|
||||||
notifier_config = notifier_agent.return_config_options()
|
notifier_config = notifier_agent.return_config_options()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: Failed to get notifier config options: %s." % e)
|
logger.error(u"Tautulli Notifiers :: Failed to get notifier config options: %s." % e)
|
||||||
return
|
return
|
||||||
|
|
||||||
notify_actions = get_notify_actions()
|
notify_actions = get_notify_actions()
|
||||||
|
@ -470,13 +470,13 @@ def add_notifier_config(agent_id=None, **kwargs):
|
||||||
if str(agent_id).isdigit():
|
if str(agent_id).isdigit():
|
||||||
agent_id = int(agent_id)
|
agent_id = int(agent_id)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to add new notifier: invalid agent_id %s." % agent_id)
|
logger.error(u"Tautulli Notifiers :: Unable to add new notifier: invalid agent_id %s." % agent_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
|
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
|
||||||
|
|
||||||
if not agent:
|
if not agent:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve new notification agent: invalid agent_id %s." % agent_id)
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve new notification agent: invalid agent_id %s." % agent_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
keys = {'id': None}
|
keys = {'id': None}
|
||||||
|
@ -499,11 +499,11 @@ def add_notifier_config(agent_id=None, **kwargs):
|
||||||
try:
|
try:
|
||||||
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
||||||
notifier_id = db.last_insert_id()
|
notifier_id = db.last_insert_id()
|
||||||
logger.info(u"PlexPy Notifiers :: Added new notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
logger.info(u"Tautulli Notifiers :: Added new notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
||||||
blacklist_logger()
|
blacklist_logger()
|
||||||
return notifier_id
|
return notifier_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Notifiers :: Unable to add notification agent: %s." % e)
|
logger.warn(u"Tautulli Notifiers :: Unable to add notification agent: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -511,13 +511,13 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
|
||||||
if str(agent_id).isdigit():
|
if str(agent_id).isdigit():
|
||||||
agent_id = int(agent_id)
|
agent_id = int(agent_id)
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to set exisiting notifier: invalid agent_id %s." % agent_id)
|
logger.error(u"Tautulli Notifiers :: Unable to set exisiting notifier: invalid agent_id %s." % agent_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
|
agent = next((a for a in available_notification_agents() if a['id'] == agent_id), None)
|
||||||
|
|
||||||
if not agent:
|
if not agent:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve existing notification agent: invalid agent_id %s." % agent_id)
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve existing notification agent: invalid agent_id %s." % agent_id)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
notify_actions = get_notify_actions()
|
notify_actions = get_notify_actions()
|
||||||
|
@ -549,11 +549,11 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
|
||||||
db = database.MonitorDatabase()
|
db = database.MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
db.upsert(table_name='notifiers', key_dict=keys, value_dict=values)
|
||||||
logger.info(u"PlexPy Notifiers :: Updated notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
logger.info(u"Tautulli Notifiers :: Updated notification agent: %s (notifier_id %s)." % (agent['label'], notifier_id))
|
||||||
blacklist_logger()
|
blacklist_logger()
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Notifiers :: Unable to update notification agent: %s." % e)
|
logger.warn(u"Tautulli Notifiers :: Unable to update notification agent: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -568,7 +568,7 @@ def send_notification(notifier_id=None, subject='', body='', notify_action='', n
|
||||||
notification_id=notification_id,
|
notification_id=notification_id,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Notifiers :: Notification requested but no notifier_id received.")
|
logger.debug(u"Tautulli Notifiers :: Notification requested but no notifier_id received.")
|
||||||
|
|
||||||
|
|
||||||
def blacklist_logger():
|
def blacklist_logger():
|
||||||
|
@ -721,7 +721,7 @@ class Notifier(object):
|
||||||
response, err_msg, req_msg = request.request_response2(url, method, **kwargs)
|
response, err_msg, req_msg = request.request_response2(url, method, **kwargs)
|
||||||
|
|
||||||
if response and not err_msg:
|
if response and not err_msg:
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -729,13 +729,13 @@ class Notifier(object):
|
||||||
if response is not None and response.status_code >= 400 and response.status_code < 500:
|
if response is not None and response.status_code >= 400 and response.status_code < 500:
|
||||||
verify_msg = " Verify you notification agent settings are correct."
|
verify_msg = " Verify you notification agent settings are correct."
|
||||||
|
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed.{}".format(verify_msg, name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed.{}".format(verify_msg, name=self.NAME))
|
||||||
|
|
||||||
if err_msg:
|
if err_msg:
|
||||||
logger.error(u"PlexPy Notifiers :: {}".format(err_msg))
|
logger.error(u"Tautulli Notifiers :: {}".format(err_msg))
|
||||||
|
|
||||||
if req_msg:
|
if req_msg:
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(req_msg))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(req_msg))
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -746,9 +746,9 @@ class Notifier(object):
|
||||||
|
|
||||||
class ANDROIDAPP(Notifier):
|
class ANDROIDAPP(Notifier):
|
||||||
"""
|
"""
|
||||||
PlexPy Android app notifications
|
Tautulli Remote Android app notifications
|
||||||
"""
|
"""
|
||||||
NAME = 'PlexPy Android App'
|
NAME = 'Tautulli Remote Android App'
|
||||||
_DEFAULT_CONFIG = {'device_id': '',
|
_DEFAULT_CONFIG = {'device_id': '',
|
||||||
'priority': 3
|
'priority': 3
|
||||||
}
|
}
|
||||||
|
@ -762,7 +762,7 @@ class ANDROIDAPP(Notifier):
|
||||||
# Check mobile device is still registered
|
# Check mobile device is still registered
|
||||||
device = mobile_app.get_mobile_devices(device_id=self.config['device_id'])
|
device = mobile_app.get_mobile_devices(device_id=self.config['device_id'])
|
||||||
if not device:
|
if not device:
|
||||||
logger.warn(u"PlexPy Notifiers :: Unable to send Android app notification: device not registered.")
|
logger.warn(u"Tautulli Notifiers :: Unable to send Android app notification: device not registered.")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
device = device[0]
|
device = device[0]
|
||||||
|
@ -806,20 +806,20 @@ class ANDROIDAPP(Notifier):
|
||||||
|
|
||||||
payload = {'app_id': self._ONESIGNAL_APP_ID,
|
payload = {'app_id': self._ONESIGNAL_APP_ID,
|
||||||
'include_player_ids': [self.config['device_id']],
|
'include_player_ids': [self.config['device_id']],
|
||||||
'contents': {'en': 'PlexPy Notification'},
|
'contents': {'en': 'Tautulli Notification'},
|
||||||
'data': {'encrypted': True,
|
'data': {'encrypted': True,
|
||||||
'cipher_text': base64.b64encode(encrypted_data),
|
'cipher_text': base64.b64encode(encrypted_data),
|
||||||
'nonce': base64.b64encode(nonce),
|
'nonce': base64.b64encode(nonce),
|
||||||
'salt': base64.b64encode(salt)}
|
'salt': base64.b64encode(salt)}
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Notifiers :: PyCryptodome library is missing. "
|
logger.warn(u"Tautulli Notifiers :: PyCryptodome library is missing. "
|
||||||
"Android app notifications will be sent unecrypted. "
|
"Android app notifications will be sent unecrypted. "
|
||||||
"Install the library to encrypt the notifications.")
|
"Install the library to encrypt the notifications.")
|
||||||
|
|
||||||
payload = {'app_id': self._ONESIGNAL_APP_ID,
|
payload = {'app_id': self._ONESIGNAL_APP_ID,
|
||||||
'include_player_ids': [self.config['device_id']],
|
'include_player_ids': [self.config['device_id']],
|
||||||
'contents': {'en': 'PlexPy Notification'},
|
'contents': {'en': 'Tautulli Notification'},
|
||||||
'data': {'encrypted': False,
|
'data': {'encrypted': False,
|
||||||
'plain_text': plaintext_data}
|
'plain_text': plaintext_data}
|
||||||
}
|
}
|
||||||
|
@ -837,7 +837,7 @@ class ANDROIDAPP(Notifier):
|
||||||
query = 'SELECT * FROM mobile_devices'
|
query = 'SELECT * FROM mobile_devices'
|
||||||
result = db.select(query=query)
|
result = db.select(query=query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Notifiers :: Unable to retrieve Android app devices list: %s." % e)
|
logger.warn(u"Tautulli Notifiers :: Unable to retrieve Android app devices list: %s." % e)
|
||||||
return {'': ''}
|
return {'': ''}
|
||||||
|
|
||||||
devices = {}
|
devices = {}
|
||||||
|
@ -893,7 +893,7 @@ class ANDROIDAPP(Notifier):
|
||||||
'name': 'androidapp_device_id',
|
'name': 'androidapp_device_id',
|
||||||
'description': 'Set your Android app device or ' \
|
'description': 'Set your Android app device or ' \
|
||||||
'<a data-tab-destination="tabs-android_app" data-toggle="tab" data-dismiss="modal" ' \
|
'<a data-tab-destination="tabs-android_app" data-toggle="tab" data-dismiss="modal" ' \
|
||||||
'style="cursor: pointer;">register a new device</a> with PlexPy.',
|
'style="cursor: pointer;">register a new device</a> with Tautulli.',
|
||||||
'input_type': 'select',
|
'input_type': 'select',
|
||||||
'select_options': devices
|
'select_options': devices
|
||||||
})
|
})
|
||||||
|
@ -997,7 +997,7 @@ class BROWSER(Notifier):
|
||||||
if not subject or not body:
|
if not subject or not body:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_notifications(self):
|
def get_notifications(self):
|
||||||
|
@ -1280,11 +1280,11 @@ class EMAIL(Notifier):
|
||||||
mailserver.sendmail(self.config['from'], recipients, msg.as_string())
|
mailserver.sendmail(self.config['from'], recipients, msg.as_string())
|
||||||
mailserver.quit()
|
mailserver.quit()
|
||||||
|
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
|
@ -1390,7 +1390,7 @@ class FACEBOOK(Notifier):
|
||||||
perms=['user_managed_groups','publish_actions'])
|
perms=['user_managed_groups','publish_actions'])
|
||||||
|
|
||||||
def _get_credentials(self, code=''):
|
def _get_credentials(self, code=''):
|
||||||
logger.info(u"PlexPy Notifiers :: Requesting access token from {name}.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: Requesting access token from {name}.".format(name=self.NAME))
|
||||||
|
|
||||||
app_id = plexpy.CONFIG.FACEBOOK_APP_ID
|
app_id = plexpy.CONFIG.FACEBOOK_APP_ID
|
||||||
app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
|
app_secret = plexpy.CONFIG.FACEBOOK_APP_SECRET
|
||||||
|
@ -1412,7 +1412,7 @@ class FACEBOOK(Notifier):
|
||||||
|
|
||||||
plexpy.CONFIG.FACEBOOK_TOKEN = response['access_token']
|
plexpy.CONFIG.FACEBOOK_TOKEN = response['access_token']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: Error requesting {name} access token: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: Error requesting {name} access token: {e}".format(name=self.NAME, e=e))
|
||||||
plexpy.CONFIG.FACEBOOK_TOKEN = ''
|
plexpy.CONFIG.FACEBOOK_TOKEN = ''
|
||||||
|
|
||||||
# Clear out temporary config values
|
# Clear out temporary config values
|
||||||
|
@ -1428,14 +1428,14 @@ class FACEBOOK(Notifier):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api.put_object(parent_object=self.config['group_id'], connection_name='feed', **data)
|
api.put_object(parent_object=self.config['group_id'], connection_name='feed', **data)
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: Error sending {name} post: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: Error sending {name} post: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Error sending {name} post: No {name} Group ID provided.".format(name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: Error sending {name} post: No {name} Group ID provided.".format(name=self.NAME))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def notify(self, subject='', body='', action='', **kwargs):
|
def notify(self, subject='', body='', action='', **kwargs):
|
||||||
|
@ -1472,19 +1472,19 @@ class FACEBOOK(Notifier):
|
||||||
Facebook Developers</a> to add a new app using <strong>basic setup</strong>.<br>\
|
Facebook Developers</a> to add a new app using <strong>basic setup</strong>.<br>\
|
||||||
Step 2: Click <strong>Add Product</strong> on the left, then <strong>Get Started</strong> \
|
Step 2: Click <strong>Add Product</strong> on the left, then <strong>Get Started</strong> \
|
||||||
for <strong>Facebook Login</strong>.<br>\
|
for <strong>Facebook Login</strong>.<br>\
|
||||||
Step 3: Fill in <strong>Valid OAuth redirect URIs</strong> with your PlexPy URL (e.g. http://localhost:8181).<br>\
|
Step 3: Fill in <strong>Valid OAuth redirect URIs</strong> with your Tautulli URL (e.g. http://localhost:8181).<br>\
|
||||||
Step 4: Click <strong>App Review</strong> on the left and toggle "make public" to <strong>Yes</strong>.<br>\
|
Step 4: Click <strong>App Review</strong> on the left and toggle "make public" to <strong>Yes</strong>.<br>\
|
||||||
Step 5: Fill in the <strong>PlexPy URL</strong> below with the exact same URL from Step 3.<br>\
|
Step 5: Fill in the <strong>Tautulli URL</strong> below with the exact same URL from Step 3.<br>\
|
||||||
Step 6: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
|
Step 6: Fill in the <strong>App ID</strong> and <strong>App Secret</strong> below.<br>\
|
||||||
Step 7: Click the <strong>Request Authorization</strong> button below to retrieve your access token.<br>\
|
Step 7: Click the <strong>Request Authorization</strong> button below to retrieve your access token.<br>\
|
||||||
Step 8: Fill in your <strong>Access Token</strong> below if it is not filled in automatically.<br>\
|
Step 8: Fill in your <strong>Access Token</strong> below if it is not filled in automatically.<br>\
|
||||||
Step 9: Fill in your <strong>Group ID</strong> number below. It can be found in the URL of your group page.',
|
Step 9: Fill in your <strong>Group ID</strong> number below. It can be found in the URL of your group page.',
|
||||||
'input_type': 'help'
|
'input_type': 'help'
|
||||||
},
|
},
|
||||||
{'label': 'PlexPy URL',
|
{'label': 'Tautulli URL',
|
||||||
'value': self.config['redirect_uri'],
|
'value': self.config['redirect_uri'],
|
||||||
'name': 'facebook_redirect_uri',
|
'name': 'facebook_redirect_uri',
|
||||||
'description': 'Your PlexPy URL. This will tell Facebook where to redirect you after authorization.\
|
'description': 'Your Tautulli URL. This will tell Facebook where to redirect you after authorization.\
|
||||||
(e.g. http://localhost:8181)',
|
(e.g. http://localhost:8181)',
|
||||||
'input_type': 'text'
|
'input_type': 'text'
|
||||||
},
|
},
|
||||||
|
@ -1595,13 +1595,13 @@ class GROUPME(Notifier):
|
||||||
r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content)
|
r = requests.post('https://image.groupme.com/pictures', headers=headers, data=poster_content)
|
||||||
|
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
logger.info(u"PlexPy Notifiers :: {name} poster sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} poster sent.".format(name=self.NAME))
|
||||||
r_content = r.json()
|
r_content = r.json()
|
||||||
data['attachments'] = [{'type': 'image',
|
data['attachments'] = [{'type': 'image',
|
||||||
'url': r_content['payload']['picture_url']}]
|
'url': r_content['payload']['picture_url']}]
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} poster failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: {name} poster failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return self.make_request('https://api.groupme.com/v3/bots/post', json=data)
|
return self.make_request('https://api.groupme.com/v3/bots/post', json=data)
|
||||||
|
@ -1666,7 +1666,7 @@ class GROWL(Notifier):
|
||||||
|
|
||||||
# Register notification
|
# Register notification
|
||||||
growl = gntp.notifier.GrowlNotifier(
|
growl = gntp.notifier.GrowlNotifier(
|
||||||
applicationName='PlexPy',
|
applicationName='Tautulli',
|
||||||
notifications=['New Event'],
|
notifications=['New Event'],
|
||||||
defaultNotifications=['New Event'],
|
defaultNotifications=['New Event'],
|
||||||
hostname=host,
|
hostname=host,
|
||||||
|
@ -1677,10 +1677,10 @@ class GROWL(Notifier):
|
||||||
try:
|
try:
|
||||||
growl.register()
|
growl.register()
|
||||||
except gntp.notifier.errors.NetworkError:
|
except gntp.notifier.errors.NetworkError:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: network error".format(name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: network error".format(name=self.NAME))
|
||||||
return False
|
return False
|
||||||
except gntp.notifier.errors.AuthError:
|
except gntp.notifier.errors.AuthError:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: authentication error".format(name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: authentication error".format(name=self.NAME))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Fix message
|
# Fix message
|
||||||
|
@ -1700,10 +1700,10 @@ class GROWL(Notifier):
|
||||||
description=body,
|
description=body,
|
||||||
icon=image
|
icon=image
|
||||||
)
|
)
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
except gntp.notifier.errors.NetworkError:
|
except gntp.notifier.errors.NetworkError:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: network error".format(name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: network error".format(name=self.NAME))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
|
@ -1969,15 +1969,15 @@ class JOIN(Notifier):
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
response_data = r.json()
|
response_data = r.json()
|
||||||
if response_data.get('success'):
|
if response_data.get('success'):
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
error_msg = response_data.get('errorMessage')
|
error_msg = response_data.get('errorMessage')
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: {msg}".format(name=self.NAME, msg=error_msg))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: {msg}".format(name=self.NAME, msg=error_msg))
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_devices(self):
|
def get_devices(self):
|
||||||
|
@ -1995,11 +1995,11 @@ class JOIN(Notifier):
|
||||||
return devices
|
return devices
|
||||||
else:
|
else:
|
||||||
error_msg = response_data.get('errorMessage')
|
error_msg = response_data.get('errorMessage')
|
||||||
logger.info(u"PlexPy Notifiers :: Unable to retrieve {name} devices list: {msg}".format(name=self.NAME, msg=error_msg))
|
logger.info(u"Tautulli Notifiers :: Unable to retrieve {name} devices list: {msg}".format(name=self.NAME, msg=error_msg))
|
||||||
return {'': ''}
|
return {'': ''}
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve {name} devices list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve {name} devices list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
return {'': ''}
|
return {'': ''}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -2061,7 +2061,7 @@ class MQTT(Notifier):
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.config['topic']:
|
if not self.config['topic']:
|
||||||
logger.error(u"PlexPy Notifiers :: MQTT topic not specified.")
|
logger.error(u"Tautulli Notifiers :: MQTT topic not specified.")
|
||||||
return
|
return
|
||||||
|
|
||||||
data = {'subject': subject.encode("utf-8"),
|
data = {'subject': subject.encode("utf-8"),
|
||||||
|
@ -2166,7 +2166,7 @@ class NMA(Notifier):
|
||||||
if not subject or not body:
|
if not subject or not body:
|
||||||
return
|
return
|
||||||
|
|
||||||
title = 'PlexPy'
|
title = 'Tautulli'
|
||||||
batch = False
|
batch = False
|
||||||
|
|
||||||
p = pynma.PyNMA()
|
p = pynma.PyNMA()
|
||||||
|
@ -2179,10 +2179,10 @@ class NMA(Notifier):
|
||||||
response = p.push(title, subject, body, priority=self.config['priority'], batch_mode=batch)
|
response = p.push(title, subject, body, priority=self.config['priority'], batch_mode=batch)
|
||||||
|
|
||||||
if response[self.config['api_key']][u'code'] == u'200':
|
if response[self.config['api_key']][u'code'] == u'200':
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed.".format(name=self.NAME))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed.".format(name=self.NAME))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
|
@ -2209,7 +2209,7 @@ class OSX(Notifier):
|
||||||
OSX notifications
|
OSX notifications
|
||||||
"""
|
"""
|
||||||
NAME = 'OSX Notify'
|
NAME = 'OSX Notify'
|
||||||
_DEFAULT_CONFIG = {'notify_app': '/Applications/PlexPy'
|
_DEFAULT_CONFIG = {'notify_app': '/Applications/Tautulli'
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, config=None):
|
def __init__(self, config=None):
|
||||||
|
@ -2219,7 +2219,7 @@ class OSX(Notifier):
|
||||||
self.objc = __import__("objc")
|
self.objc = __import__("objc")
|
||||||
self.AppKit = __import__("AppKit")
|
self.AppKit = __import__("AppKit")
|
||||||
except:
|
except:
|
||||||
# logger.error(u"PlexPy Notifiers :: Cannot load OSX Notifications agent.")
|
# logger.error(u"Tautulli Notifiers :: Cannot load OSX Notifications agent.")
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
|
@ -2278,13 +2278,13 @@ class OSX(Notifier):
|
||||||
|
|
||||||
notification_center = NSUserNotificationCenter.defaultUserNotificationCenter()
|
notification_center = NSUserNotificationCenter.defaultUserNotificationCenter()
|
||||||
notification_center.deliverNotification_(notification)
|
notification_center.deliverNotification_(notification)
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
|
|
||||||
del pool
|
del pool
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} failed: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: {name} failed: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def return_config_options(self):
|
def return_config_options(self):
|
||||||
|
@ -2292,7 +2292,7 @@ class OSX(Notifier):
|
||||||
'value': self.config['notify_app'],
|
'value': self.config['notify_app'],
|
||||||
'name': 'osx_notify_app',
|
'name': 'osx_notify_app',
|
||||||
'description': 'Enter the path/application name to be registered with the '
|
'description': 'Enter the path/application name to be registered with the '
|
||||||
'Notification Center, default is /Applications/PlexPy.',
|
'Notification Center, default is /Applications/Tautulli.',
|
||||||
'input_type': 'text'
|
'input_type': 'text'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -2352,7 +2352,7 @@ class PLEX(Notifier):
|
||||||
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo.png"))
|
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo.png"))
|
||||||
|
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
logger.info(u"PlexPy Notifiers :: Sending notification command to {name} @ {host}".format(name=self.NAME, host=host))
|
logger.info(u"Tautulli Notifiers :: Sending notification command to {name} @ {host}".format(name=self.NAME, host=host))
|
||||||
try:
|
try:
|
||||||
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
|
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
|
||||||
|
|
||||||
|
@ -2368,10 +2368,10 @@ class PLEX(Notifier):
|
||||||
if not request:
|
if not request:
|
||||||
raise Exception
|
raise Exception
|
||||||
else:
|
else:
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -2426,7 +2426,7 @@ class PROWL(Notifier):
|
||||||
return
|
return
|
||||||
|
|
||||||
data = {'apikey': self.config['key'],
|
data = {'apikey': self.config['key'],
|
||||||
'application': 'PlexPy',
|
'application': 'Tautulli',
|
||||||
'event': subject.encode("utf-8"),
|
'event': subject.encode("utf-8"),
|
||||||
'description': body.encode("utf-8"),
|
'description': body.encode("utf-8"),
|
||||||
'priority': self.config['priority']}
|
'priority': self.config['priority']}
|
||||||
|
@ -2531,8 +2531,8 @@ class PUSHBULLET(Notifier):
|
||||||
devices.update({'': ''})
|
devices.update({'': ''})
|
||||||
return devices
|
return devices
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve {name} devices list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve {name} devices list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
return {'': ''}
|
return {'': ''}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -2628,8 +2628,8 @@ class PUSHOVER(Notifier):
|
||||||
sounds.update({'': ''})
|
sounds.update({'': ''})
|
||||||
return sounds
|
return sounds
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: Unable to retrieve {name} sounds list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: Unable to retrieve {name} sounds list: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
return {'': ''}
|
return {'': ''}
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -2744,7 +2744,7 @@ class SCRIPTS(Notifier):
|
||||||
|
|
||||||
def run_script(self, script):
|
def run_script(self, script):
|
||||||
def kill_script(process):
|
def kill_script(process):
|
||||||
logger.warn(u"PlexPy Notifiers :: Script exceeded timeout limit of %d seconds. "
|
logger.warn(u"Tautulli Notifiers :: Script exceeded timeout limit of %d seconds. "
|
||||||
"Script killed." % self.config['timeout'])
|
"Script killed." % self.config['timeout'])
|
||||||
process.kill()
|
process.kill()
|
||||||
self.script_killed = True
|
self.script_killed = True
|
||||||
|
@ -2771,20 +2771,20 @@ class SCRIPTS(Notifier):
|
||||||
if timer: timer.cancel()
|
if timer: timer.cancel()
|
||||||
|
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
logger.error(u"PlexPy Notifiers :: Failed to run script: %s" % e)
|
logger.error(u"Tautulli Notifiers :: Failed to run script: %s" % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if error:
|
if error:
|
||||||
err = '\n '.join([l for l in error.splitlines()])
|
err = '\n '.join([l for l in error.splitlines()])
|
||||||
logger.error(u"PlexPy Notifiers :: Script error: \n %s" % err)
|
logger.error(u"Tautulli Notifiers :: Script error: \n %s" % err)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if output:
|
if output:
|
||||||
out = '\n '.join([l for l in output.splitlines()])
|
out = '\n '.join([l for l in output.splitlines()])
|
||||||
logger.debug(u"PlexPy Notifiers :: Script returned: \n %s" % out)
|
logger.debug(u"Tautulli Notifiers :: Script returned: \n %s" % out)
|
||||||
|
|
||||||
if not self.script_killed:
|
if not self.script_killed:
|
||||||
logger.info(u"PlexPy Notifiers :: Script notification sent.")
|
logger.info(u"Tautulli Notifiers :: Script notification sent.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def notify(self, subject='', body='', action='', **kwargs):
|
def notify(self, subject='', body='', action='', **kwargs):
|
||||||
|
@ -2795,22 +2795,22 @@ class SCRIPTS(Notifier):
|
||||||
action(string): 'play'
|
action(string): 'play'
|
||||||
"""
|
"""
|
||||||
if not self.config['script_folder']:
|
if not self.config['script_folder']:
|
||||||
logger.error(u"PlexPy Notifiers :: No script folder specified.")
|
logger.error(u"Tautulli Notifiers :: No script folder specified.")
|
||||||
return
|
return
|
||||||
|
|
||||||
script_args = kwargs.get('script_args', [])
|
script_args = kwargs.get('script_args', [])
|
||||||
|
|
||||||
logger.debug(u"PlexPy Notifiers :: Trying to run notify script, action: %s, arguments: %s"
|
logger.debug(u"Tautulli Notifiers :: Trying to run notify script, action: %s, arguments: %s"
|
||||||
% (action, script_args))
|
% (action, script_args))
|
||||||
|
|
||||||
script = kwargs.get('script', self.config.get('script', ''))
|
script = kwargs.get('script', self.config.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 action and not script:
|
if action and not script:
|
||||||
logger.debug(u"PlexPy Notifiers :: No script selected for action %s, exiting..." % action)
|
logger.debug(u"Tautulli Notifiers :: No script selected for action %s, exiting..." % action)
|
||||||
return
|
return
|
||||||
elif not script:
|
elif not script:
|
||||||
logger.debug(u"PlexPy Notifiers :: No script selected, exiting...")
|
logger.debug(u"Tautulli Notifiers :: No script selected, exiting...")
|
||||||
return
|
return
|
||||||
|
|
||||||
name, ext = os.path.splitext(script)
|
name, ext = os.path.splitext(script)
|
||||||
|
@ -2842,8 +2842,8 @@ class SCRIPTS(Notifier):
|
||||||
|
|
||||||
script.extend(script_args)
|
script.extend(script_args)
|
||||||
|
|
||||||
logger.debug(u"PlexPy Notifiers :: Full script is: %s" % script)
|
logger.debug(u"Tautulli Notifiers :: Full script is: %s" % script)
|
||||||
logger.debug(u"PlexPy Notifiers :: Executing script in a new thread.")
|
logger.debug(u"Tautulli Notifiers :: Executing script in a new thread.")
|
||||||
thread = threading.Thread(target=self.run_script, args=(script,)).start()
|
thread = threading.Thread(target=self.run_script, args=(script,)).start()
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -3097,10 +3097,10 @@ class TELEGRAM(Notifier):
|
||||||
r = requests.post('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']), json=poster_data)
|
r = requests.post('https://api.telegram.org/bot{}/sendPhoto'.format(self.config['bot_token']), json=poster_data)
|
||||||
|
|
||||||
if r.status_code == 200:
|
if r.status_code == 200:
|
||||||
logger.info(u"PlexPy Notifiers :: {name} poster sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} poster sent.".format(name=self.NAME))
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} poster failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
logger.error(u"Tautulli Notifiers :: {name} poster failed: [{r.status_code}] {r.reason}".format(name=self.NAME, r=r))
|
||||||
logger.debug(u"PlexPy Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
logger.debug(u"Tautulli Notifiers :: Request response: {}".format(request.server_message(r, True)))
|
||||||
|
|
||||||
data['text'] = text
|
data['text'] = text
|
||||||
|
|
||||||
|
@ -3183,16 +3183,16 @@ class TWITTER(Notifier):
|
||||||
access_token = self.config['access_token']
|
access_token = self.config['access_token']
|
||||||
access_token_secret = self.config['access_token_secret']
|
access_token_secret = self.config['access_token_secret']
|
||||||
|
|
||||||
# logger.info(u"PlexPy Notifiers :: Sending tweet: " + message)
|
# logger.info(u"Tautulli Notifiers :: Sending tweet: " + message)
|
||||||
|
|
||||||
api = twitter.Api(consumer_key, consumer_secret, access_token, access_token_secret)
|
api = twitter.Api(consumer_key, consumer_secret, access_token, access_token_secret)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api.PostUpdate(message, media=attachment)
|
api.PostUpdate(message, media=attachment)
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def notify(self, subject='', body='', action='', **kwargs):
|
def notify(self, subject='', body='', action='', **kwargs):
|
||||||
|
@ -3312,7 +3312,7 @@ class XBMC(Notifier):
|
||||||
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo.png"))
|
image = os.path.join(plexpy.DATA_DIR, os.path.abspath("data/interfaces/default/images/logo.png"))
|
||||||
|
|
||||||
for host in hosts:
|
for host in hosts:
|
||||||
logger.info(u"PlexPy Notifiers :: Sending notification command to XMBC @ " + host)
|
logger.info(u"Tautulli Notifiers :: Sending notification command to XMBC @ " + host)
|
||||||
try:
|
try:
|
||||||
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
|
version = self._sendjson(host, 'Application.GetProperties', {'properties': ['version']})['version']['major']
|
||||||
|
|
||||||
|
@ -3328,10 +3328,10 @@ class XBMC(Notifier):
|
||||||
if not request:
|
if not request:
|
||||||
raise Exception
|
raise Exception
|
||||||
else:
|
else:
|
||||||
logger.info(u"PlexPy Notifiers :: {name} notification sent.".format(name=self.NAME))
|
logger.info(u"Tautulli Notifiers :: {name} notification sent.".format(name=self.NAME))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
logger.error(u"Tautulli Notifiers :: {name} notification failed: {e}".format(name=self.NAME, e=e))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -3373,7 +3373,7 @@ class XBMC(Notifier):
|
||||||
|
|
||||||
|
|
||||||
def upgrade_config_to_db():
|
def upgrade_config_to_db():
|
||||||
logger.info(u"PlexPy Notifiers :: Upgrading to new notification system...")
|
logger.info(u"Tautulli Notifiers :: Upgrading to new notification system...")
|
||||||
|
|
||||||
# Set flag first in case something fails we don't want to keep re-adding the notifiers
|
# Set flag first in case something fails we don't want to keep re-adding the notifiers
|
||||||
plexpy.CONFIG.__setattr__('UPDATE_NOTIFIERS_DB', 0)
|
plexpy.CONFIG.__setattr__('UPDATE_NOTIFIERS_DB', 0)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
@ -33,13 +33,13 @@ def extract_plexivity_xml(xml=None):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(clean_xml)
|
xml_parse = minidom.parseString(clean_xml)
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy Importer :: Error parsing XML for Plexivity database.")
|
logger.warn(u"Tautulli Importer :: Error parsing XML for Plexivity database.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# I think Plexivity only tracked videos and not music?
|
# I think Plexivity only tracked videos and not music?
|
||||||
xml_head = xml_parse.getElementsByTagName('Video')
|
xml_head = xml_parse.getElementsByTagName('Video')
|
||||||
if not xml_head:
|
if not xml_head:
|
||||||
logger.warn(u"PlexPy Importer :: Error parsing XML for Plexivity database.")
|
logger.warn(u"Tautulli Importer :: Error parsing XML for Plexivity database.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -238,23 +238,23 @@ def validate_database(database=None, table_name=None):
|
||||||
try:
|
try:
|
||||||
connection = sqlite3.connect(database, timeout=20)
|
connection = sqlite3.connect(database, timeout=20)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except:
|
except:
|
||||||
logger.error(u"PlexPy Importer :: Uncaught exception.")
|
logger.error(u"Tautulli Importer :: Uncaught exception.")
|
||||||
return 'Uncaught exception.'
|
return 'Uncaught exception.'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.execute('SELECT xml from %s' % table_name)
|
connection.execute('SELECT xml from %s' % table_name)
|
||||||
connection.close()
|
connection.close()
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except:
|
except:
|
||||||
logger.error(u"PlexPy Importer :: Uncaught exception.")
|
logger.error(u"Tautulli Importer :: Uncaught exception.")
|
||||||
return 'Uncaught exception.'
|
return 'Uncaught exception.'
|
||||||
|
|
||||||
return 'success'
|
return 'success'
|
||||||
|
@ -265,19 +265,19 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
|
||||||
connection = sqlite3.connect(database, timeout=20)
|
connection = sqlite3.connect(database, timeout=20)
|
||||||
connection.row_factory = sqlite3.Row
|
connection.row_factory = sqlite3.Row
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid filename.")
|
logger.error(u"Tautulli Importer :: Invalid filename.")
|
||||||
return None
|
return None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid filename.")
|
logger.error(u"Tautulli Importer :: Invalid filename.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.execute('SELECT xml from %s' % table_name)
|
connection.execute('SELECT xml from %s' % table_name)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Database specified does not contain the required fields.")
|
logger.error(u"Tautulli Importer :: Database specified does not contain the required fields.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.debug(u"PlexPy Importer :: Plexivity data import in progress...")
|
logger.debug(u"Tautulli Importer :: Plexivity data import in progress...")
|
||||||
|
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
user_data = users.Users()
|
user_data = users.Users()
|
||||||
|
@ -286,7 +286,7 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
|
||||||
try:
|
try:
|
||||||
plextv.refresh_users()
|
plextv.refresh_users()
|
||||||
except:
|
except:
|
||||||
logger.debug(u"PlexPy Importer :: Unable to refresh the users list. Aborting import.")
|
logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
query = 'SELECT id AS id, ' \
|
query = 'SELECT id AS id, ' \
|
||||||
|
@ -319,13 +319,13 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
|
||||||
|
|
||||||
# If we get back None from our xml extractor skip over the record and log error.
|
# If we get back None from our xml extractor skip over the record and log error.
|
||||||
if not extracted_xml:
|
if not extracted_xml:
|
||||||
logger.error(u"PlexPy Importer :: Skipping record with id %s due to malformed xml."
|
logger.error(u"Tautulli Importer :: Skipping record with id %s due to malformed xml."
|
||||||
% str(row['id']))
|
% str(row['id']))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Skip line if we don't have a ratingKey to work with
|
# Skip line if we don't have a ratingKey to work with
|
||||||
#if not row['rating_key']:
|
#if not row['rating_key']:
|
||||||
# logger.error(u"PlexPy Importer :: Skipping record due to null ratingKey.")
|
# logger.error(u"Tautulli Importer :: Skipping record due to null ratingKey.")
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
# If the user_id no longer exists in the friends list, pull it from the xml.
|
# If the user_id no longer exists in the friends list, pull it from the xml.
|
||||||
|
@ -427,13 +427,13 @@ def import_from_plexivity(database=None, table_name=None, import_ignore_interval
|
||||||
is_import=True,
|
is_import=True,
|
||||||
import_ignore_interval=import_ignore_interval)
|
import_ignore_interval=import_ignore_interval)
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key'])
|
logger.debug(u"Tautulli Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key'])
|
||||||
|
|
||||||
logger.debug(u"PlexPy Importer :: Plexivity data import complete.")
|
logger.debug(u"Tautulli Importer :: Plexivity data import complete.")
|
||||||
import_users()
|
import_users()
|
||||||
|
|
||||||
def import_users():
|
def import_users():
|
||||||
logger.debug(u"PlexPy Importer :: Importing Plexivity Users...")
|
logger.debug(u"Tautulli Importer :: Importing Plexivity Users...")
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
query = 'INSERT OR IGNORE INTO users (user_id, username) ' \
|
query = 'INSERT OR IGNORE INTO users (user_id, username) ' \
|
||||||
|
@ -442,6 +442,6 @@ def import_users():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
monitor_db.action(query)
|
monitor_db.action(query)
|
||||||
logger.debug(u"PlexPy Importer :: Users imported.")
|
logger.debug(u"Tautulli Importer :: Users imported.")
|
||||||
except:
|
except:
|
||||||
logger.debug(u"PlexPy Importer :: Failed to import users.")
|
logger.debug(u"Tautulli Importer :: Failed to import users.")
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
|
@ -32,7 +32,7 @@ import session
|
||||||
|
|
||||||
|
|
||||||
def refresh_users():
|
def refresh_users():
|
||||||
logger.info(u"PlexPy PlexTV :: Requesting users list refresh...")
|
logger.info(u"Tautulli PlexTV :: Requesting users list refresh...")
|
||||||
result = PlexTV().get_full_users_list()
|
result = PlexTV().get_full_users_list()
|
||||||
|
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
@ -81,15 +81,15 @@ def refresh_users():
|
||||||
|
|
||||||
monitor_db.upsert('users', new_value_dict, control_value_dict)
|
monitor_db.upsert('users', new_value_dict, control_value_dict)
|
||||||
|
|
||||||
logger.info(u"PlexPy PlexTV :: Users list refreshed.")
|
logger.info(u"Tautulli PlexTV :: Users list refreshed.")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to refresh users list.")
|
logger.warn(u"Tautulli PlexTV :: Unable to refresh users list.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_real_pms_url():
|
def get_real_pms_url():
|
||||||
logger.info(u"PlexPy PlexTV :: Requesting URLs for server...")
|
logger.info(u"Tautulli PlexTV :: Requesting URLs for server...")
|
||||||
|
|
||||||
# Reset any current PMS_URL value
|
# Reset any current PMS_URL value
|
||||||
plexpy.CONFIG.__setattr__('PMS_URL', '')
|
plexpy.CONFIG.__setattr__('PMS_URL', '')
|
||||||
|
@ -124,13 +124,13 @@ def get_real_pms_url():
|
||||||
and c['port'] == str(plexpy.CONFIG.PMS_PORT)), conns[0])
|
and c['port'] == str(plexpy.CONFIG.PMS_PORT)), conns[0])
|
||||||
plexpy.CONFIG.__setattr__('PMS_URL', conn['uri'])
|
plexpy.CONFIG.__setattr__('PMS_URL', conn['uri'])
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.info(u"PlexPy PlexTV :: Server URL retrieved.")
|
logger.info(u"Tautulli PlexTV :: Server URL retrieved.")
|
||||||
|
|
||||||
# get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL
|
# get_server_urls() failed or PMS_URL not found, fallback url doesn't use SSL
|
||||||
if not plexpy.CONFIG.PMS_URL:
|
if not plexpy.CONFIG.PMS_URL:
|
||||||
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
|
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.")
|
logger.warn(u"Tautulli PlexTV :: Unable to retrieve server URLs. Using user-defined value without SSL.")
|
||||||
|
|
||||||
# Not using SSL, remote has no effect
|
# Not using SSL, remote has no effect
|
||||||
else:
|
else:
|
||||||
|
@ -139,7 +139,7 @@ def get_real_pms_url():
|
||||||
|
|
||||||
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
|
plexpy.CONFIG.__setattr__('PMS_URL', fallback_url)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.info(u"PlexPy PlexTV :: Using user-defined URL.")
|
logger.info(u"Tautulli PlexTV :: Using user-defined URL.")
|
||||||
|
|
||||||
|
|
||||||
class PlexTV(object):
|
class PlexTV(object):
|
||||||
|
@ -173,8 +173,8 @@ class PlexTV(object):
|
||||||
uri = '/users/sign_in.xml'
|
uri = '/users/sign_in.xml'
|
||||||
base64string = base64.b64encode(('%s:%s' % (self.username, self.password)).encode('utf-8'))
|
base64string = base64.b64encode(('%s:%s' % (self.username, self.password)).encode('utf-8'))
|
||||||
headers = {'Content-Type': 'application/xml; charset=utf-8',
|
headers = {'Content-Type': 'application/xml; charset=utf-8',
|
||||||
'X-Plex-Device-Name': 'PlexPy',
|
'X-Plex-Device-Name': 'Tautulli',
|
||||||
'X-Plex-Product': 'PlexPy',
|
'X-Plex-Product': 'Tautulli',
|
||||||
'X-Plex-Version': plexpy.common.VERSION_NUMBER,
|
'X-Plex-Version': plexpy.common.VERSION_NUMBER,
|
||||||
'X-Plex-Platform': plexpy.common.PLATFORM,
|
'X-Plex-Platform': plexpy.common.PLATFORM,
|
||||||
'X-Plex-Platform-Version': plexpy.common.PLATFORM_VERSION,
|
'X-Plex-Platform-Version': plexpy.common.PLATFORM_VERSION,
|
||||||
|
@ -202,9 +202,9 @@ class PlexTV(object):
|
||||||
'user_id': xml_head[0].getAttribute('id')
|
'user_id': xml_head[0].getAttribute('id')
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy PlexTV :: Could not get Plex authentication token.")
|
logger.warn(u"Tautulli PlexTV :: Could not get Plex authentication token.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_token: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_token: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
@ -213,27 +213,27 @@ class PlexTV(object):
|
||||||
|
|
||||||
def get_plexpy_pms_token(self, force=False):
|
def get_plexpy_pms_token(self, force=False):
|
||||||
if force:
|
if force:
|
||||||
logger.debug(u"PlexPy PlexTV :: Forcing refresh of Plex.tv token.")
|
logger.debug(u"Tautulli PlexTV :: Forcing refresh of Plex.tv token.")
|
||||||
devices_list = self.get_devices_list()
|
devices_list = self.get_devices_list()
|
||||||
device_id = next((d for d in devices_list if d['device_identifier'] == plexpy.CONFIG.PMS_UUID), {}).get('device_id', None)
|
device_id = next((d for d in devices_list if d['device_identifier'] == plexpy.CONFIG.PMS_UUID), {}).get('device_id', None)
|
||||||
|
|
||||||
if device_id:
|
if device_id:
|
||||||
logger.debug(u"PlexPy PlexTV :: Removing PlexPy from Plex.tv devices.")
|
logger.debug(u"Tautulli PlexTV :: Removing Tautulli from Plex.tv devices.")
|
||||||
try:
|
try:
|
||||||
self.delete_plextv_device(device_id=device_id)
|
self.delete_plextv_device(device_id=device_id)
|
||||||
except:
|
except:
|
||||||
logger.error(u"PlexPy PlexTV :: Failed to remove PlexPy from Plex.tv devices.")
|
logger.error(u"Tautulli PlexTV :: Failed to remove Tautulli from Plex.tv devices.")
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy PlexTV :: No existing PlexPy device found.")
|
logger.warn(u"Tautulli PlexTV :: No existing Tautulli device found.")
|
||||||
|
|
||||||
logger.info(u"PlexPy PlexTV :: Fetching a new Plex.tv token for PlexPy.")
|
logger.info(u"Tautulli PlexTV :: Fetching a new Plex.tv token for Tautulli.")
|
||||||
user = self.get_token()
|
user = self.get_token()
|
||||||
if user:
|
if user:
|
||||||
token = user['auth_token']
|
token = user['auth_token']
|
||||||
plexpy.CONFIG.__setattr__('PMS_TOKEN', token)
|
plexpy.CONFIG.__setattr__('PMS_TOKEN', token)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.info(u"PlexPy PlexTV :: Updated Plex.tv token for PlexPy.")
|
logger.info(u"Tautulli PlexTV :: Updated Plex.tv token for Tautulli.")
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,7 +244,7 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_head = servers.getElementsByTagName('Server')
|
xml_head = servers.getElementsByTagName('Server')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_token: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_token: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -366,15 +366,15 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(own_account)
|
xml_parse = minidom.parseString(own_account)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list own account: %s" % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list own account: %s" % e)
|
||||||
return []
|
return []
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list own account.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list own account.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
xml_head = xml_parse.getElementsByTagName('user')
|
xml_head = xml_parse.getElementsByTagName('user')
|
||||||
if not xml_head:
|
if not xml_head:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list.")
|
||||||
else:
|
else:
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
own_details = {"user_id": helpers.get_xml_attr(a, 'id'),
|
own_details = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||||
|
@ -396,15 +396,15 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(friends_list)
|
xml_parse = minidom.parseString(friends_list)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list friends list: %s" % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list friends list: %s" % e)
|
||||||
return []
|
return []
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list friends list.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list friends list.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
xml_head = xml_parse.getElementsByTagName('User')
|
xml_head = xml_parse.getElementsByTagName('User')
|
||||||
if not xml_head:
|
if not xml_head:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_full_users_list.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_full_users_list.")
|
||||||
else:
|
else:
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
friend = {"user_id": helpers.get_xml_attr(a, 'id'),
|
friend = {"user_id": helpers.get_xml_attr(a, 'id'),
|
||||||
|
@ -434,16 +434,16 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(sync_list)
|
xml_parse = minidom.parseString(sync_list)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items: %s" % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items: %s" % e)
|
||||||
return []
|
return []
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
xml_head = xml_parse.getElementsByTagName('SyncList')
|
xml_head = xml_parse.getElementsByTagName('SyncList')
|
||||||
|
|
||||||
if not xml_head:
|
if not xml_head:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_synced_items.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_synced_items.")
|
||||||
else:
|
else:
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
sync_id = helpers.get_xml_attr(a, 'id')
|
sync_id = helpers.get_xml_attr(a, 'id')
|
||||||
|
@ -536,7 +536,7 @@ class PlexTV(object):
|
||||||
return session.filter_session_info(synced_items, filter_key='user_id')
|
return session.filter_session_info(synced_items, filter_key='user_id')
|
||||||
|
|
||||||
def delete_sync(self, client_id, sync_id):
|
def delete_sync(self, client_id, sync_id):
|
||||||
logger.info(u"PlexPy PlexTV :: Deleting sync item '%s'." % sync_id)
|
logger.info(u"Tautulli PlexTV :: Deleting sync item '%s'." % sync_id)
|
||||||
self.delete_plextv_sync(client_id=client_id, sync_id=sync_id)
|
self.delete_plextv_sync(client_id=client_id, sync_id=sync_id)
|
||||||
|
|
||||||
def get_server_urls(self, include_https=True):
|
def get_server_urls(self, include_https=True):
|
||||||
|
@ -544,7 +544,7 @@ class PlexTV(object):
|
||||||
if plexpy.CONFIG.PMS_IDENTIFIER:
|
if plexpy.CONFIG.PMS_IDENTIFIER:
|
||||||
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy PlexTV :: Unable to retrieve server identity.")
|
logger.error(u"Tautulli PlexTV :: Unable to retrieve server identity.")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
plextv_resources = self.get_plextv_resources(include_https=include_https)
|
plextv_resources = self.get_plextv_resources(include_https=include_https)
|
||||||
|
@ -552,16 +552,16 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(plextv_resources)
|
xml_parse = minidom.parseString(plextv_resources)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s" % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s" % e)
|
||||||
return {}
|
return {}
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls.")
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls.")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xml_head = xml_parse.getElementsByTagName('Device')
|
xml_head = xml_parse.getElementsByTagName('Device')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_urls: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_urls: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Function to get all connections for a device
|
# Function to get all connections for a device
|
||||||
|
@ -607,7 +607,7 @@ class PlexTV(object):
|
||||||
plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier')
|
plexpy.CONFIG.PMS_IDENTIFIER = helpers.get_xml_attr(a, 'clientIdentifier')
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
|
|
||||||
logger.info(u"PlexPy PlexTV :: PMS identifier changed from %s to %s."
|
logger.info(u"Tautulli PlexTV :: PMS identifier changed from %s to %s."
|
||||||
% (server_id, plexpy.CONFIG.PMS_IDENTIFIER))
|
% (server_id, plexpy.CONFIG.PMS_IDENTIFIER))
|
||||||
|
|
||||||
server = get_connections(a)
|
server = get_connections(a)
|
||||||
|
@ -625,7 +625,7 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_head = servers.getElementsByTagName('Server')
|
xml_head = servers.getElementsByTagName('Server')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_server_times: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_server_times: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -646,7 +646,7 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_head = servers.getElementsByTagName('MediaContainer')
|
xml_head = servers.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Failed to get servers from plex: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Failed to get servers from plex: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -691,16 +691,16 @@ class PlexTV(object):
|
||||||
return clean_servers
|
return clean_servers
|
||||||
|
|
||||||
def get_plex_downloads(self):
|
def get_plex_downloads(self):
|
||||||
logger.debug(u"PlexPy PlexTV :: Retrieving current server version.")
|
logger.debug(u"Tautulli PlexTV :: Retrieving current server version.")
|
||||||
pmsconnect.PmsConnect().set_server_version()
|
pmsconnect.PmsConnect().set_server_version()
|
||||||
|
|
||||||
logger.debug(u"PlexPy PlexTV :: Plex update channel is %s." % plexpy.CONFIG.PMS_UPDATE_CHANNEL)
|
logger.debug(u"Tautulli PlexTV :: Plex update channel is %s." % plexpy.CONFIG.PMS_UPDATE_CHANNEL)
|
||||||
plex_downloads = self.get_plextv_downloads(plexpass=(plexpy.CONFIG.PMS_UPDATE_CHANNEL == 'plexpass'))
|
plex_downloads = self.get_plextv_downloads(plexpass=(plexpy.CONFIG.PMS_UPDATE_CHANNEL == 'plexpass'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
available_downloads = json.loads(plex_downloads)
|
available_downloads = json.loads(plex_downloads)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to load JSON for get_plex_updates.")
|
logger.warn(u"Tautulli PlexTV :: Unable to load JSON for get_plex_updates.")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# Get the updates for the platform
|
# Get the updates for the platform
|
||||||
|
@ -709,7 +709,7 @@ class PlexTV(object):
|
||||||
available_downloads.get('nas').get(pms_platform)
|
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"Tautulli PlexTV :: Unable to retrieve Plex updates: Could not match server platform: %s."
|
||||||
% pms_platform)
|
% pms_platform)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -717,11 +717,11 @@ class PlexTV(object):
|
||||||
v_new = helpers.cast_to_int("".join(v.zfill(4) for v in platform_downloads.get('version', '').split('-')[0].split('.')[:4]))
|
v_new = helpers.cast_to_int("".join(v.zfill(4) for v in platform_downloads.get('version', '').split('-')[0].split('.')[:4]))
|
||||||
|
|
||||||
if not v_old:
|
if not v_old:
|
||||||
logger.error(u"PlexPy PlexTV :: Unable to retrieve Plex updates: Invalid current server version: %s."
|
logger.error(u"Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid current server version: %s."
|
||||||
% plexpy.CONFIG.PMS_VERSION)
|
% plexpy.CONFIG.PMS_VERSION)
|
||||||
return {}
|
return {}
|
||||||
if not v_new:
|
if not v_new:
|
||||||
logger.error(u"PlexPy PlexTV :: Unable to retrieve Plex updates: Invalid new server version: %s."
|
logger.error(u"Tautulli PlexTV :: Unable to retrieve Plex updates: Invalid new server version: %s."
|
||||||
% platform_downloads.get('version'))
|
% platform_downloads.get('version'))
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@ -752,13 +752,13 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
subscription = account_data.getElementsByTagName('subscription')
|
subscription = account_data.getElementsByTagName('subscription')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_plexpass_status: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_plexpass_status: %s." % e)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if subscription and helpers.get_xml_attr(subscription[0], 'active') == '1':
|
if subscription and helpers.get_xml_attr(subscription[0], 'active') == '1':
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy PlexTV :: Plex Pass subscription not found.")
|
logger.debug(u"Tautulli PlexTV :: Plex Pass subscription not found.")
|
||||||
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
|
plexpy.CONFIG.__setattr__('PMS_PLEXPASS', 0)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
return False
|
return False
|
||||||
|
@ -769,7 +769,7 @@ class PlexTV(object):
|
||||||
try:
|
try:
|
||||||
xml_head = devices.getElementsByTagName('Device')
|
xml_head = devices.getElementsByTagName('Device')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy PlexTV :: Unable to parse XML for get_devices_list: %s." % e)
|
logger.warn(u"Tautulli PlexTV :: Unable to parse XML for get_devices_list: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
devices_list = []
|
devices_list = []
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
@ -32,12 +32,12 @@ def extract_plexwatch_xml(xml=None):
|
||||||
try:
|
try:
|
||||||
xml_parse = minidom.parseString(clean_xml)
|
xml_parse = minidom.parseString(clean_xml)
|
||||||
except:
|
except:
|
||||||
logger.warn(u"PlexPy Importer :: Error parsing XML for PlexWatch database.")
|
logger.warn(u"Tautulli Importer :: Error parsing XML for PlexWatch database.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
xml_head = xml_parse.getElementsByTagName('opt')
|
xml_head = xml_parse.getElementsByTagName('opt')
|
||||||
if not xml_head:
|
if not xml_head:
|
||||||
logger.warn(u"PlexPy Importer :: Error parsing XML for PlexWatch database.")
|
logger.warn(u"Tautulli Importer :: Error parsing XML for PlexWatch database.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -229,23 +229,23 @@ def validate_database(database=None, table_name=None):
|
||||||
try:
|
try:
|
||||||
connection = sqlite3.connect(database, timeout=20)
|
connection = sqlite3.connect(database, timeout=20)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except:
|
except:
|
||||||
logger.error(u"PlexPy Importer :: Uncaught exception.")
|
logger.error(u"Tautulli Importer :: Uncaught exception.")
|
||||||
return 'Uncaught exception.'
|
return 'Uncaught exception.'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.execute('SELECT ratingKey from %s' % table_name)
|
connection.execute('SELECT ratingKey from %s' % table_name)
|
||||||
connection.close()
|
connection.close()
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid database specified.")
|
logger.error(u"Tautulli Importer :: Invalid database specified.")
|
||||||
return 'Invalid database specified.'
|
return 'Invalid database specified.'
|
||||||
except:
|
except:
|
||||||
logger.error(u"PlexPy Importer :: Uncaught exception.")
|
logger.error(u"Tautulli Importer :: Uncaught exception.")
|
||||||
return 'Uncaught exception.'
|
return 'Uncaught exception.'
|
||||||
|
|
||||||
return 'success'
|
return 'success'
|
||||||
|
@ -256,19 +256,19 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
connection = sqlite3.connect(database, timeout=20)
|
connection = sqlite3.connect(database, timeout=20)
|
||||||
connection.row_factory = sqlite3.Row
|
connection.row_factory = sqlite3.Row
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid filename.")
|
logger.error(u"Tautulli Importer :: Invalid filename.")
|
||||||
return None
|
return None
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(u"PlexPy Importer :: Invalid filename.")
|
logger.error(u"Tautulli Importer :: Invalid filename.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection.execute('SELECT ratingKey from %s' % table_name)
|
connection.execute('SELECT ratingKey from %s' % table_name)
|
||||||
except sqlite3.OperationalError:
|
except sqlite3.OperationalError:
|
||||||
logger.error(u"PlexPy Importer :: Database specified does not contain the required fields.")
|
logger.error(u"Tautulli Importer :: Database specified does not contain the required fields.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
logger.debug(u"PlexPy Importer :: PlexWatch data import in progress...")
|
logger.debug(u"Tautulli Importer :: PlexWatch data import in progress...")
|
||||||
|
|
||||||
ap = activity_processor.ActivityProcessor()
|
ap = activity_processor.ActivityProcessor()
|
||||||
user_data = users.Users()
|
user_data = users.Users()
|
||||||
|
@ -277,7 +277,7 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
try:
|
try:
|
||||||
plextv.refresh_users()
|
plextv.refresh_users()
|
||||||
except:
|
except:
|
||||||
logger.debug(u"PlexPy Importer :: Unable to refresh the users list. Aborting import.")
|
logger.debug(u"Tautulli Importer :: Unable to refresh the users list. Aborting import.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
query = 'SELECT time AS started, ' \
|
query = 'SELECT time AS started, ' \
|
||||||
|
@ -312,13 +312,13 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
|
|
||||||
# If we get back None from our xml extractor skip over the record and log error.
|
# If we get back None from our xml extractor skip over the record and log error.
|
||||||
if not extracted_xml:
|
if not extracted_xml:
|
||||||
logger.error(u"PlexPy Importer :: Skipping record with ratingKey %s due to malformed xml."
|
logger.error(u"Tautulli Importer :: Skipping record with ratingKey %s due to malformed xml."
|
||||||
% str(row['rating_key']))
|
% str(row['rating_key']))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Skip line if we don't have a ratingKey to work with
|
# Skip line if we don't have a ratingKey to work with
|
||||||
if not row['rating_key']:
|
if not row['rating_key']:
|
||||||
logger.error(u"PlexPy Importer :: Skipping record due to null ratingKey.")
|
logger.error(u"Tautulli Importer :: Skipping record due to null ratingKey.")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If the user_id no longer exists in the friends list, pull it from the xml.
|
# If the user_id no longer exists in the friends list, pull it from the xml.
|
||||||
|
@ -420,13 +420,13 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
||||||
is_import=True,
|
is_import=True,
|
||||||
import_ignore_interval=import_ignore_interval)
|
import_ignore_interval=import_ignore_interval)
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key'])
|
logger.debug(u"Tautulli Importer :: Item has bad rating_key: %s" % session_history_metadata['rating_key'])
|
||||||
|
|
||||||
logger.debug(u"PlexPy Importer :: PlexWatch data import complete.")
|
logger.debug(u"Tautulli Importer :: PlexWatch data import complete.")
|
||||||
import_users()
|
import_users()
|
||||||
|
|
||||||
def import_users():
|
def import_users():
|
||||||
logger.debug(u"PlexPy Importer :: Importing PlexWatch Users...")
|
logger.debug(u"Tautulli Importer :: Importing PlexWatch Users...")
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
query = 'INSERT OR IGNORE INTO users (user_id, username) ' \
|
query = 'INSERT OR IGNORE INTO users (user_id, username) ' \
|
||||||
|
@ -435,6 +435,6 @@ def import_users():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
monitor_db.action(query)
|
monitor_db.action(query)
|
||||||
logger.debug(u"PlexPy Importer :: Users imported.")
|
logger.debug(u"Tautulli Importer :: Users imported.")
|
||||||
except:
|
except:
|
||||||
logger.debug(u"PlexPy Importer :: Failed to import users.")
|
logger.debug(u"Tautulli Importer :: Failed to import users.")
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import threading
|
import threading
|
||||||
import urllib
|
import urllib
|
||||||
|
@ -29,7 +29,7 @@ import users
|
||||||
|
|
||||||
|
|
||||||
def get_server_friendly_name():
|
def get_server_friendly_name():
|
||||||
logger.info(u"PlexPy Pmsconnect :: Requesting name from server...")
|
logger.info(u"Tautulli Pmsconnect :: Requesting name from server...")
|
||||||
server_name = PmsConnect().get_server_pref(pref='FriendlyName')
|
server_name = PmsConnect().get_server_pref(pref='FriendlyName')
|
||||||
|
|
||||||
# If friendly name is blank
|
# If friendly name is blank
|
||||||
|
@ -43,17 +43,17 @@ def get_server_friendly_name():
|
||||||
if server_name and server_name != plexpy.CONFIG.PMS_NAME:
|
if server_name and server_name != plexpy.CONFIG.PMS_NAME:
|
||||||
plexpy.CONFIG.__setattr__('PMS_NAME', server_name)
|
plexpy.CONFIG.__setattr__('PMS_NAME', server_name)
|
||||||
plexpy.CONFIG.write()
|
plexpy.CONFIG.write()
|
||||||
logger.info(u"PlexPy Pmsconnect :: Server name retrieved.")
|
logger.info(u"Tautulli Pmsconnect :: Server name retrieved.")
|
||||||
|
|
||||||
return server_name
|
return server_name
|
||||||
|
|
||||||
|
|
||||||
def refresh_libraries():
|
def refresh_libraries():
|
||||||
logger.info(u"PlexPy Pmsconnect :: Requesting libraries list refresh...")
|
logger.info(u"Tautulli Pmsconnect :: Requesting libraries list refresh...")
|
||||||
|
|
||||||
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
server_id = plexpy.CONFIG.PMS_IDENTIFIER
|
||||||
if not server_id:
|
if not server_id:
|
||||||
logger.error(u"PlexPy Pmsconnect :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
|
logger.error(u"Tautulli Pmsconnect :: No PMS identifier, cannot refresh libraries. Verify server in settings.")
|
||||||
return
|
return
|
||||||
|
|
||||||
library_sections = PmsConnect().get_library_details()
|
library_sections = PmsConnect().get_library_details()
|
||||||
|
@ -101,10 +101,10 @@ def refresh_libraries():
|
||||||
# # Start library labels update on it's own thread
|
# # Start library labels update on it's own thread
|
||||||
# threading.Thread(target=libraries.update_labels).start()
|
# threading.Thread(target=libraries.update_labels).start()
|
||||||
|
|
||||||
logger.info(u"PlexPy Pmsconnect :: Libraries list refreshed.")
|
logger.info(u"Tautulli Pmsconnect :: Libraries list refreshed.")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to refresh libraries list.")
|
logger.warn(u"Tautulli Pmsconnect :: Unable to refresh libraries list.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@ -527,7 +527,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = recent.getElementsByTagName('MediaContainer')
|
xml_head = recent.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_recently_added: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_recently_added: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
recents_list = []
|
recents_list = []
|
||||||
|
@ -601,7 +601,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = metadata.getElementsByTagName('MediaContainer')
|
xml_head = metadata.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_metadata: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_metadata: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
metadata = {}
|
metadata = {}
|
||||||
|
@ -626,7 +626,7 @@ class PmsConnect(object):
|
||||||
metadata_main = a.getElementsByTagName('Photo')[0]
|
metadata_main = a.getElementsByTagName('Photo')[0]
|
||||||
metadata_type = helpers.get_xml_attr(metadata_main, 'type')
|
metadata_type = helpers.get_xml_attr(metadata_main, 'type')
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Pmsconnect :: Metadata failed")
|
logger.debug(u"Tautulli Pmsconnect :: Metadata failed")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
section_id = helpers.get_xml_attr(a, 'librarySectionID')
|
section_id = helpers.get_xml_attr(a, 'librarySectionID')
|
||||||
|
@ -1167,7 +1167,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = metadata.getElementsByTagName('MediaContainer')
|
xml_head = metadata.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_metadata_children: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_metadata_children: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
metadata_list = []
|
metadata_list = []
|
||||||
|
@ -1217,7 +1217,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = libraries_data.getElementsByTagName('MediaContainer')
|
xml_head = libraries_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_library_metadata_details: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_library_metadata_details: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
metadata_list = []
|
metadata_list = []
|
||||||
|
@ -1262,7 +1262,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = session_data.getElementsByTagName('MediaContainer')
|
xml_head = session_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_current_activity: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_current_activity: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
session_list = []
|
session_list = []
|
||||||
|
@ -1739,7 +1739,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = children_data.getElementsByTagName('MediaContainer')
|
xml_head = children_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_children_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_children_list: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
children_list = []
|
children_list = []
|
||||||
|
@ -1747,7 +1747,7 @@ class PmsConnect(object):
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
if a.getAttribute('size'):
|
if a.getAttribute('size'):
|
||||||
if a.getAttribute('size') == '0':
|
if a.getAttribute('size') == '0':
|
||||||
logger.debug(u"PlexPy Pmsconnect :: No children data.")
|
logger.debug(u"Tautulli Pmsconnect :: No children data.")
|
||||||
children_list = {'children_count': '0',
|
children_list = {'children_count': '0',
|
||||||
'children_list': []
|
'children_list': []
|
||||||
}
|
}
|
||||||
|
@ -1795,7 +1795,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = recent.getElementsByTagName('Server')
|
xml_head = recent.getElementsByTagName('Server')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_server_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_server_list: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
server_info = []
|
server_info = []
|
||||||
|
@ -1822,7 +1822,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = identity.getElementsByTagName('MediaContainer')
|
xml_head = identity.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_identity: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_local_server_identity: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
server_identity = {}
|
server_identity = {}
|
||||||
|
@ -1847,7 +1847,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = prefs.getElementsByTagName('Setting')
|
xml_head = prefs.getElementsByTagName('Setting')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_local_server_name: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_local_server_name: %s." % e)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
pref_value = 'None'
|
pref_value = 'None'
|
||||||
|
@ -1858,7 +1858,7 @@ class PmsConnect(object):
|
||||||
|
|
||||||
return pref_value
|
return pref_value
|
||||||
else:
|
else:
|
||||||
logger.debug(u"PlexPy Pmsconnect :: Server preferences queried but no parameter received.")
|
logger.debug(u"Tautulli Pmsconnect :: Server preferences queried but no parameter received.")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_server_children(self):
|
def get_server_children(self):
|
||||||
|
@ -1872,7 +1872,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = libraries_data.getElementsByTagName('MediaContainer')
|
xml_head = libraries_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_libraries_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_libraries_list: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
libraries_list = []
|
libraries_list = []
|
||||||
|
@ -1880,7 +1880,7 @@ class PmsConnect(object):
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
if a.getAttribute('size'):
|
if a.getAttribute('size'):
|
||||||
if a.getAttribute('size') == '0':
|
if a.getAttribute('size') == '0':
|
||||||
logger.debug(u"PlexPy Pmsconnect :: No libraries data.")
|
logger.debug(u"Tautulli Pmsconnect :: No libraries data.")
|
||||||
libraries_list = {'libraries_count': '0',
|
libraries_list = {'libraries_count': '0',
|
||||||
'libraries_list': []
|
'libraries_list': []
|
||||||
}
|
}
|
||||||
|
@ -1943,13 +1943,13 @@ class PmsConnect(object):
|
||||||
elif str(rating_key).isdigit():
|
elif str(rating_key).isdigit():
|
||||||
library_data = self.get_children_list(str(rating_key), output_format='xml')
|
library_data = self.get_children_list(str(rating_key), output_format='xml')
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: get_library_children called by invalid section_id or rating_key provided.")
|
logger.warn(u"Tautulli Pmsconnect :: get_library_children called by invalid section_id or rating_key provided.")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
xml_head = library_data.getElementsByTagName('MediaContainer')
|
xml_head = library_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_library_children_details: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_library_children_details: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
childern_list = []
|
childern_list = []
|
||||||
|
@ -1957,7 +1957,7 @@ class PmsConnect(object):
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
if a.getAttribute('size'):
|
if a.getAttribute('size'):
|
||||||
if a.getAttribute('size') == '0':
|
if a.getAttribute('size') == '0':
|
||||||
logger.debug(u"PlexPy Pmsconnect :: No library data.")
|
logger.debug(u"Tautulli Pmsconnect :: No library data.")
|
||||||
childern_list = {'library_count': '0',
|
childern_list = {'library_count': '0',
|
||||||
'childern_list': []
|
'childern_list': []
|
||||||
}
|
}
|
||||||
|
@ -2092,7 +2092,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = labels_data.getElementsByTagName('MediaContainer')
|
xml_head = labels_data.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_library_label_details: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_library_label_details: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
labels_list = []
|
labels_list = []
|
||||||
|
@ -2100,7 +2100,7 @@ class PmsConnect(object):
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
if a.getAttribute('size'):
|
if a.getAttribute('size'):
|
||||||
if a.getAttribute('size') == '0':
|
if a.getAttribute('size') == '0':
|
||||||
logger.debug(u"PlexPy Pmsconnect :: No labels data.")
|
logger.debug(u"Tautulli Pmsconnect :: No labels data.")
|
||||||
return labels_list
|
return labels_list
|
||||||
|
|
||||||
if a.getElementsByTagName('Directory'):
|
if a.getElementsByTagName('Directory'):
|
||||||
|
@ -2146,7 +2146,7 @@ class PmsConnect(object):
|
||||||
return result[0], result[1]
|
return result[0], result[1]
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error(u"PlexPy Pmsconnect :: Image proxy queried but no input received.")
|
logger.error(u"Tautulli Pmsconnect :: Image proxy queried but no input received.")
|
||||||
|
|
||||||
def get_search_results(self, query='', limit=''):
|
def get_search_results(self, query='', limit=''):
|
||||||
"""
|
"""
|
||||||
|
@ -2159,7 +2159,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = search_results.getElementsByTagName('MediaContainer')
|
xml_head = search_results.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_search_result: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_search_result: %s." % e)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
search_results_list = {'movie': [],
|
search_results_list = {'movie': [],
|
||||||
|
@ -2241,7 +2241,7 @@ class PmsConnect(object):
|
||||||
section_id = metadata['section_id']
|
section_id = metadata['section_id']
|
||||||
library_name = metadata['library_name']
|
library_name = metadata['library_name']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to get parent_rating_key for get_rating_keys_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to get parent_rating_key for get_rating_keys_list: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
elif media_type == 'episode' or media_type == 'track':
|
elif media_type == 'episode' or media_type == 'track':
|
||||||
|
@ -2251,7 +2251,7 @@ class PmsConnect(object):
|
||||||
section_id = metadata['section_id']
|
section_id = metadata['section_id']
|
||||||
library_name = metadata['library_name']
|
library_name = metadata['library_name']
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to get grandparent_rating_key for get_rating_keys_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to get grandparent_rating_key for get_rating_keys_list: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
# get parent_rating_keys
|
# get parent_rating_keys
|
||||||
|
@ -2260,7 +2260,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = metadata.getElementsByTagName('MediaContainer')
|
xml_head = metadata.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -2288,7 +2288,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = metadata.getElementsByTagName('MediaContainer')
|
xml_head = metadata.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_rating_keys_list: %s." % e)
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
for a in xml_head:
|
for a in xml_head:
|
||||||
|
@ -2336,7 +2336,7 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = account_data.getElementsByTagName('MyPlex')
|
xml_head = account_data.getElementsByTagName('MyPlex')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_server_response: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_server_response: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
server_response = {}
|
server_response = {}
|
||||||
|
@ -2358,13 +2358,13 @@ class PmsConnect(object):
|
||||||
try:
|
try:
|
||||||
xml_head = updater_status.getElementsByTagName('MediaContainer')
|
xml_head = updater_status.getElementsByTagName('MediaContainer')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Pmsconnect :: Unable to parse XML for get_update_staus: %s." % e)
|
logger.warn(u"Tautulli Pmsconnect :: Unable to parse XML for get_update_staus: %s." % e)
|
||||||
|
|
||||||
# Catch the malformed XML on certain PMX version.
|
# Catch the malformed XML on certain PMX version.
|
||||||
# XML parser helper returns empty list if there is an error parsing XML
|
# XML parser helper returns empty list if there is an error parsing XML
|
||||||
if updater_status == []:
|
if updater_status == []:
|
||||||
logger.warn(u"Plex API updater XML is broken on the current PMS version. Please update your PMS manually.")
|
logger.warn(u"Plex API updater XML is broken on the current PMS version. Please update your PMS manually.")
|
||||||
logger.info(u"PlexPy is unable to check for Plex updates. Disabling check for Plex updates.")
|
logger.info(u"Tautulli is unable to check for Plex updates. Disabling check for Plex updates.")
|
||||||
|
|
||||||
# Disable check for Plex updates
|
# Disable check for Plex updates
|
||||||
plexpy.CONFIG.MONITOR_PMS_UPDATES = 0
|
plexpy.CONFIG.MONITOR_PMS_UPDATES = 0
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import httpagentparser
|
import httpagentparser
|
||||||
import time
|
import time
|
||||||
|
@ -93,7 +93,7 @@ class Users(object):
|
||||||
['session_history.id', 'session_history_media_info.id']],
|
['session_history.id', 'session_history_media_info.id']],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_list: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_list: %s." % e)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
users = query['result']
|
users = query['result']
|
||||||
|
@ -204,7 +204,7 @@ class Users(object):
|
||||||
['session_history.id', 'session_history_media_info.id']],
|
['session_history.id', 'session_history_media_info.id']],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_unique_ips: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_unique_ips: %s." % e)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
results = query['result']
|
results = query['result']
|
||||||
|
@ -264,7 +264,7 @@ class Users(object):
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert('users', value_dict, key_dict)
|
monitor_db.upsert('users', value_dict, key_dict)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for set_config: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for set_config: %s." % e)
|
||||||
|
|
||||||
def get_details(self, user_id=None, user=None, email=None):
|
def get_details(self, user_id=None, user=None, email=None):
|
||||||
default_return = {'user_id': 0,
|
default_return = {'user_id': 0,
|
||||||
|
@ -313,7 +313,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_details: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_details: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
user_details = {}
|
user_details = {}
|
||||||
|
@ -357,7 +357,7 @@ class Users(object):
|
||||||
return user_details
|
return user_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Requesting user list refresh."
|
logger.warn(u"Tautulli Users :: Unable to retrieve user %s from database. Requesting user list refresh."
|
||||||
% user_id if user_id else user)
|
% user_id if user_id else user)
|
||||||
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
|
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
|
||||||
plextv.refresh_users()
|
plextv.refresh_users()
|
||||||
|
@ -368,7 +368,7 @@ class Users(object):
|
||||||
return user_details
|
return user_details
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy Users :: Unable to retrieve user %s from database. Returning 'Local' user."
|
logger.warn(u"Tautulli Users :: Unable to retrieve user %s from database. Returning 'Local' user."
|
||||||
% user_id if user_id else user)
|
% user_id if user_id else user)
|
||||||
# If there is no user data we must return something
|
# If there is no user data we must return something
|
||||||
# Use "Local" user to retain compatibility with PlexWatch database value
|
# Use "Local" user to retain compatibility with PlexWatch database value
|
||||||
|
@ -407,7 +407,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_watch_time_stats: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_watch_time_stats: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -447,7 +447,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_player_stats: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_player_stats: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -492,7 +492,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
result = []
|
result = []
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_recently_watched: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_recently_watched: %s." % e)
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
for row in result:
|
for row in result:
|
||||||
|
@ -527,7 +527,7 @@ class Users(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if str(user_id).isdigit():
|
if str(user_id).isdigit():
|
||||||
logger.info(u"PlexPy Users :: Deleting all history for user id %s from database." % user_id)
|
logger.info(u"Tautulli Users :: Deleting all history for user id %s from database." % user_id)
|
||||||
session_history_media_info_del = \
|
session_history_media_info_del = \
|
||||||
monitor_db.action('DELETE FROM '
|
monitor_db.action('DELETE FROM '
|
||||||
'session_history_media_info '
|
'session_history_media_info '
|
||||||
|
@ -551,7 +551,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to delete items. Input user_id not valid.'
|
return 'Unable to delete items. Input user_id not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for delete_all_history: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for delete_all_history: %s." % e)
|
||||||
|
|
||||||
def delete(self, user_id=None):
|
def delete(self, user_id=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
@ -559,7 +559,7 @@ class Users(object):
|
||||||
try:
|
try:
|
||||||
if str(user_id).isdigit():
|
if str(user_id).isdigit():
|
||||||
self.delete_all_history(user_id)
|
self.delete_all_history(user_id)
|
||||||
logger.info(u"PlexPy Users :: Deleting user with id %s from database." % user_id)
|
logger.info(u"Tautulli Users :: Deleting user with id %s from database." % user_id)
|
||||||
monitor_db.action('UPDATE users SET deleted_user = 1 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET deleted_user = 1 WHERE user_id = ?', [user_id])
|
||||||
monitor_db.action('UPDATE users SET keep_history = 0 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET keep_history = 0 WHERE user_id = ?', [user_id])
|
||||||
monitor_db.action('UPDATE users SET do_notify = 0 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET do_notify = 0 WHERE user_id = ?', [user_id])
|
||||||
|
@ -568,21 +568,21 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to delete user, user_id not valid.'
|
return 'Unable to delete user, user_id not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for delete: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for delete: %s." % e)
|
||||||
|
|
||||||
def undelete(self, user_id=None, username=None):
|
def undelete(self, user_id=None, username=None):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if user_id and str(user_id).isdigit():
|
if user_id and str(user_id).isdigit():
|
||||||
logger.info(u"PlexPy Users :: Re-adding user with id %s to database." % user_id)
|
logger.info(u"Tautulli Users :: Re-adding user with id %s to database." % user_id)
|
||||||
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE user_id = ?', [user_id])
|
||||||
monitor_db.action('UPDATE users SET keep_history = 1 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET keep_history = 1 WHERE user_id = ?', [user_id])
|
||||||
monitor_db.action('UPDATE users SET do_notify = 1 WHERE user_id = ?', [user_id])
|
monitor_db.action('UPDATE users SET do_notify = 1 WHERE user_id = ?', [user_id])
|
||||||
|
|
||||||
return 'Re-added user with id %s.' % user_id
|
return 'Re-added user with id %s.' % user_id
|
||||||
elif username:
|
elif username:
|
||||||
logger.info(u"PlexPy Users :: Re-adding user with username %s to database." % username)
|
logger.info(u"Tautulli Users :: Re-adding user with username %s to database." % username)
|
||||||
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE username = ?', [username])
|
monitor_db.action('UPDATE users SET deleted_user = 0 WHERE username = ?', [username])
|
||||||
monitor_db.action('UPDATE users SET keep_history = 1 WHERE username = ?', [username])
|
monitor_db.action('UPDATE users SET keep_history = 1 WHERE username = ?', [username])
|
||||||
monitor_db.action('UPDATE users SET do_notify = 1 WHERE username = ?', [username])
|
monitor_db.action('UPDATE users SET do_notify = 1 WHERE username = ?', [username])
|
||||||
|
@ -591,7 +591,7 @@ class Users(object):
|
||||||
else:
|
else:
|
||||||
return 'Unable to re-add user, user_id or username not valid.'
|
return 'Unable to re-add user, user_id or username not valid.'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for undelete: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for undelete: %s." % e)
|
||||||
|
|
||||||
# Keep method for PlexWatch/Plexivity import
|
# Keep method for PlexWatch/Plexivity import
|
||||||
def get_user_id(self, user=None):
|
def get_user_id(self, user=None):
|
||||||
|
@ -625,7 +625,7 @@ class Users(object):
|
||||||
|
|
||||||
result = monitor_db.select(query)
|
result = monitor_db.select(query)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_user_names: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_user_names: %s." % e)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return session.friendly_name_to_username(result)
|
return session.friendly_name_to_username(result)
|
||||||
|
@ -662,7 +662,7 @@ class Users(object):
|
||||||
'WHERE user_id = ?'
|
'WHERE user_id = ?'
|
||||||
result = monitor_db.select_single(query, args=[user_id])
|
result = monitor_db.select_single(query, args=[user_id])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_filters: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_filters: %s." % e)
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
filters_list = {}
|
filters_list = {}
|
||||||
|
@ -698,7 +698,7 @@ class Users(object):
|
||||||
try:
|
try:
|
||||||
monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values)
|
monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for set_login_log: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for set_login_log: %s." % e)
|
||||||
|
|
||||||
def get_datatables_user_login(self, user_id=None, kwargs=None):
|
def get_datatables_user_login(self, user_id=None, kwargs=None):
|
||||||
default_return = {'recordsFiltered': 0,
|
default_return = {'recordsFiltered': 0,
|
||||||
|
@ -739,7 +739,7 @@ class Users(object):
|
||||||
join_evals=[['user_login.user_id', 'users.user_id']],
|
join_evals=[['user_login.user_id', 'users.user_id']],
|
||||||
kwargs=kwargs)
|
kwargs=kwargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for get_datatables_user_login: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for get_datatables_user_login: %s." % e)
|
||||||
return default_return
|
return default_return
|
||||||
|
|
||||||
results = query['result']
|
results = query['result']
|
||||||
|
@ -774,10 +774,10 @@ class Users(object):
|
||||||
monitor_db = database.MonitorDatabase()
|
monitor_db = database.MonitorDatabase()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(u"PlexPy Users :: Clearing login logs from database.")
|
logger.info(u"Tautulli Users :: Clearing login logs from database.")
|
||||||
monitor_db.action('DELETE FROM user_login')
|
monitor_db.action('DELETE FROM user_login')
|
||||||
monitor_db.action('VACUUM')
|
monitor_db.action('VACUUM')
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy Users :: Unable to execute database query for delete_login_log: %s." % e)
|
logger.warn(u"Tautulli Users :: Unable to execute database query for delete_login_log: %s." % e)
|
||||||
return False
|
return False
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
|
@ -149,11 +149,11 @@ def checkGithub(auto_update=False):
|
||||||
|
|
||||||
# See how many commits behind we are
|
# See how many commits behind we are
|
||||||
if not plexpy.CURRENT_VERSION:
|
if not plexpy.CURRENT_VERSION:
|
||||||
logger.info('You are running an unknown version of PlexPy. Run the updater to identify your version')
|
logger.info('You are running an unknown version of Tautulli. Run the updater to identify your version')
|
||||||
return plexpy.LATEST_VERSION
|
return plexpy.LATEST_VERSION
|
||||||
|
|
||||||
if plexpy.LATEST_VERSION == plexpy.CURRENT_VERSION:
|
if plexpy.LATEST_VERSION == plexpy.CURRENT_VERSION:
|
||||||
logger.info('PlexPy is up to date')
|
logger.info('Tautulli is up to date')
|
||||||
return plexpy.LATEST_VERSION
|
return plexpy.LATEST_VERSION
|
||||||
|
|
||||||
logger.info('Comparing currently installed version with latest GitHub version')
|
logger.info('Comparing currently installed version with latest GitHub version')
|
||||||
|
@ -185,7 +185,7 @@ def checkGithub(auto_update=False):
|
||||||
plexpy.shutdown(restart=True, update=True)
|
plexpy.shutdown(restart=True, update=True)
|
||||||
|
|
||||||
elif plexpy.COMMITS_BEHIND == 0:
|
elif plexpy.COMMITS_BEHIND == 0:
|
||||||
logger.info('PlexPy is up to date')
|
logger.info('Tautulli is up to date')
|
||||||
|
|
||||||
return plexpy.LATEST_VERSION
|
return plexpy.LATEST_VERSION
|
||||||
|
|
||||||
|
@ -338,5 +338,5 @@ def read_changelog(latest_only=False):
|
||||||
return output
|
return output
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error('PlexPy Version Checker :: Unable to open changelog file. %s' % e)
|
logger.error('Tautulli Version Checker :: Unable to open changelog file. %s' % e)
|
||||||
return '<h4>Unable to open changelog file</h4>'
|
return '<h4>Unable to open changelog file</h4>'
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
# Mostly borrowed from https://github.com/trakt/Plex-Trakt-Scrobbler
|
# Mostly borrowed from https://github.com/trakt/Plex-Trakt-Scrobbler
|
||||||
|
|
||||||
|
@ -75,26 +75,26 @@ def run():
|
||||||
# Try an open the websocket connection
|
# Try an open the websocket connection
|
||||||
while not plexpy.WS_CONNECTED and reconnects <= plexpy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
|
while not plexpy.WS_CONNECTED and reconnects <= plexpy.CONFIG.WEBSOCKET_CONNECTION_ATTEMPTS:
|
||||||
try:
|
try:
|
||||||
logger.info(u"PlexPy WebSocket :: Opening%s websocket, connection attempt %s." % (secure, str(reconnects + 1)))
|
logger.info(u"Tautulli WebSocket :: Opening%s websocket, connection attempt %s." % (secure, str(reconnects + 1)))
|
||||||
ws = create_connection(uri, header=header)
|
ws = create_connection(uri, header=header)
|
||||||
reconnects = 0
|
reconnects = 0
|
||||||
logger.info(u"PlexPy WebSocket :: Ready")
|
logger.info(u"Tautulli WebSocket :: Ready")
|
||||||
plexpy.WS_CONNECTED = True
|
plexpy.WS_CONNECTED = True
|
||||||
|
|
||||||
if not plexpy.PLEX_SERVER_UP:
|
if not plexpy.PLEX_SERVER_UP:
|
||||||
logger.info(u"PlexPy WebSocket :: The Plex Media Server is back up.")
|
logger.info(u"Tautulli WebSocket :: The Plex Media Server is back up.")
|
||||||
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intup'})
|
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intup'})
|
||||||
plexpy.PLEX_SERVER_UP = True
|
plexpy.PLEX_SERVER_UP = True
|
||||||
|
|
||||||
plexpy.initialize_scheduler()
|
plexpy.initialize_scheduler()
|
||||||
|
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.error(u"PlexPy WebSocket :: %s." % e)
|
logger.error(u"Tautulli WebSocket :: %s." % e)
|
||||||
reconnects += 1
|
reconnects += 1
|
||||||
time.sleep(plexpy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
|
time.sleep(plexpy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
|
||||||
|
|
||||||
except (websocket.WebSocketException, Exception) as e:
|
except (websocket.WebSocketException, Exception) as e:
|
||||||
logger.error(u"PlexPy WebSocket :: %s." % e)
|
logger.error(u"Tautulli WebSocket :: %s." % e)
|
||||||
plexpy.WS_CONNECTED = False
|
plexpy.WS_CONNECTED = False
|
||||||
ws_exception = True
|
ws_exception = True
|
||||||
break
|
break
|
||||||
|
@ -114,13 +114,13 @@ def run():
|
||||||
if reconnects > 1:
|
if reconnects > 1:
|
||||||
time.sleep(plexpy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
|
time.sleep(plexpy.CONFIG.WEBSOCKET_CONNECTION_TIMEOUT)
|
||||||
|
|
||||||
logger.warn(u"PlexPy WebSocket :: Connection has closed, reconnection attempt %s." % reconnects)
|
logger.warn(u"Tautulli WebSocket :: Connection has closed, reconnection attempt %s." % reconnects)
|
||||||
try:
|
try:
|
||||||
ws = create_connection(uri, header=header)
|
ws = create_connection(uri, header=header)
|
||||||
logger.info(u"PlexPy WebSocket :: Ready")
|
logger.info(u"Tautulli WebSocket :: Ready")
|
||||||
plexpy.WS_CONNECTED = True
|
plexpy.WS_CONNECTED = True
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
logger.info(u"PlexPy WebSocket :: %s." % e)
|
logger.info(u"Tautulli WebSocket :: %s." % e)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
ws.shutdown()
|
ws.shutdown()
|
||||||
|
@ -128,30 +128,30 @@ def run():
|
||||||
break
|
break
|
||||||
|
|
||||||
except (websocket.WebSocketException, Exception) as e:
|
except (websocket.WebSocketException, Exception) as e:
|
||||||
logger.error(u"PlexPy WebSocket :: %s." % e)
|
logger.error(u"Tautulli WebSocket :: %s." % e)
|
||||||
plexpy.WS_CONNECTED = False
|
plexpy.WS_CONNECTED = False
|
||||||
ws_exception = True
|
ws_exception = True
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check if we recieved a restart notification and close websocket connection cleanly
|
# Check if we recieved a restart notification and close websocket connection cleanly
|
||||||
if ws_reconnect:
|
if ws_reconnect:
|
||||||
logger.info(u"PlexPy WebSocket :: Reconnecting websocket...")
|
logger.info(u"Tautulli WebSocket :: Reconnecting websocket...")
|
||||||
ws.shutdown()
|
ws.shutdown()
|
||||||
plexpy.WS_CONNECTED = False
|
plexpy.WS_CONNECTED = False
|
||||||
start_thread()
|
start_thread()
|
||||||
|
|
||||||
if not plexpy.WS_CONNECTED and not ws_reconnect:
|
if not plexpy.WS_CONNECTED and not ws_reconnect:
|
||||||
logger.error(u"PlexPy WebSocket :: Connection unavailable.")
|
logger.error(u"Tautulli WebSocket :: Connection unavailable.")
|
||||||
|
|
||||||
if not ws_exception and plexpy.PLEX_SERVER_UP:
|
if not ws_exception and plexpy.PLEX_SERVER_UP:
|
||||||
logger.info(u"PlexPy WebSocket :: Unable to get an internal response from the server, Plex server is down.")
|
logger.info(u"Tautulli WebSocket :: Unable to get an internal response from the server, Plex server is down.")
|
||||||
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'})
|
plexpy.NOTIFY_QUEUE.put({'notify_action': 'on_intdown'})
|
||||||
plexpy.PLEX_SERVER_UP = False
|
plexpy.PLEX_SERVER_UP = False
|
||||||
on_disconnect()
|
on_disconnect()
|
||||||
|
|
||||||
plexpy.initialize_scheduler()
|
plexpy.initialize_scheduler()
|
||||||
|
|
||||||
logger.debug(u"PlexPy WebSocket :: Leaving thread.")
|
logger.debug(u"Tautulli WebSocket :: Leaving thread.")
|
||||||
|
|
||||||
|
|
||||||
def receive(ws):
|
def receive(ws):
|
||||||
|
@ -178,7 +178,7 @@ def process(opcode, data):
|
||||||
logger.websocket_debug(data)
|
logger.websocket_debug(data)
|
||||||
info = json.loads(data)
|
info = json.loads(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy WebSocket :: Error decoding message from websocket: %s" % e)
|
logger.warn(u"Tautulli WebSocket :: Error decoding message from websocket: %s" % e)
|
||||||
logger.debug(data)
|
logger.debug(data)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -192,26 +192,26 @@ def process(opcode, data):
|
||||||
time_line = info.get('PlaySessionStateNotification', info.get('_children', {}))
|
time_line = info.get('PlaySessionStateNotification', info.get('_children', {}))
|
||||||
|
|
||||||
if not time_line:
|
if not time_line:
|
||||||
logger.debug(u"PlexPy WebSocket :: Session found but unable to get timeline data.")
|
logger.debug(u"Tautulli WebSocket :: Session found but unable to get timeline data.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
activity = activity_handler.ActivityHandler(timeline=time_line[0])
|
activity = activity_handler.ActivityHandler(timeline=time_line[0])
|
||||||
activity.process()
|
activity.process()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy WebSocket :: Failed to process session data: %s." % e)
|
logger.error(u"Tautulli WebSocket :: Failed to process session data: %s." % e)
|
||||||
|
|
||||||
if type == 'timeline':
|
if type == 'timeline':
|
||||||
time_line = info.get('TimelineEntry', info.get('_children', {}))
|
time_line = info.get('TimelineEntry', info.get('_children', {}))
|
||||||
|
|
||||||
if not time_line:
|
if not time_line:
|
||||||
logger.debug(u"PlexPy WebSocket :: Timeline event found but unable to get timeline data.")
|
logger.debug(u"Tautulli WebSocket :: Timeline event found but unable to get timeline data.")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
activity = activity_handler.TimelineHandler(timeline=time_line[0])
|
activity = activity_handler.TimelineHandler(timeline=time_line[0])
|
||||||
activity.process()
|
activity.process()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(u"PlexPy WebSocket :: Failed to process timeline data: %s." % e)
|
logger.error(u"Tautulli WebSocket :: Failed to process timeline data: %s." % e)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
# http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
|
# http://tools.cherrypy.org/wiki/AuthenticationAndAccessRestrictions
|
||||||
|
@ -66,7 +66,7 @@ def user_login(username=None, password=None):
|
||||||
# Register the new user / update the access tokens.
|
# Register the new user / update the access tokens.
|
||||||
monitor_db = MonitorDatabase()
|
monitor_db = MonitorDatabase()
|
||||||
try:
|
try:
|
||||||
logger.debug(u"PlexPy WebAuth :: Regestering tokens for user '%s' in the database." % username)
|
logger.debug(u"Tautulli WebAuth :: Regestering tokens for user '%s' in the database." % username)
|
||||||
result = monitor_db.action('UPDATE users SET user_token = ?, server_token = ? WHERE user_id = ?',
|
result = monitor_db.action('UPDATE users SET user_token = ?, server_token = ? WHERE user_id = ?',
|
||||||
[user_token, server_token, user_id])
|
[user_token, server_token, user_id])
|
||||||
|
|
||||||
|
@ -76,16 +76,16 @@ def user_login(username=None, password=None):
|
||||||
# Successful login
|
# Successful login
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy WebAuth :: Unable to register user '%s' in database." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database." % username)
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warn(u"PlexPy WebAuth :: Unable to register user '%s' in database: %s." % (username, e))
|
logger.warn(u"Tautulli WebAuth :: Unable to register user '%s' in database: %s." % (username, e))
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy WebAuth :: Unable to retrieve Plex.tv server token for user '%s'." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv server token for user '%s'." % username)
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
logger.warn(u"PlexPy WebAuth :: Unable to retrieve Plex.tv user token for user '%s'." % username)
|
logger.warn(u"Tautulli WebAuth :: Unable to retrieve Plex.tv user token for user '%s'." % username)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
@ -193,11 +193,11 @@ class AuthController(object):
|
||||||
user_agent=user_agent,
|
user_agent=user_agent,
|
||||||
success=1)
|
success=1)
|
||||||
|
|
||||||
logger.debug(u"PlexPy WebAuth :: %s user '%s' logged into PlexPy." % (user_group.capitalize(), username))
|
logger.debug(u"Tautulli WebAuth :: %s user '%s' logged into Tautulli." % (user_group.capitalize(), username))
|
||||||
|
|
||||||
def on_logout(self, username, user_group):
|
def on_logout(self, username, user_group):
|
||||||
"""Called on logout"""
|
"""Called on logout"""
|
||||||
logger.debug(u"PlexPy WebAuth :: %s User '%s' logged out of PlexPy." % (user_group.capitalize(), username))
|
logger.debug(u"Tautulli WebAuth :: %s User '%s' logged out of Tautulli." % (user_group.capitalize(), username))
|
||||||
|
|
||||||
def on_login_failed(self, username):
|
def on_login_failed(self, username):
|
||||||
"""Called on failed login"""
|
"""Called on failed login"""
|
||||||
|
@ -256,11 +256,11 @@ class AuthController(object):
|
||||||
|
|
||||||
elif admin_login == '1':
|
elif admin_login == '1':
|
||||||
self.on_login_failed(username)
|
self.on_login_failed(username)
|
||||||
logger.debug(u"PlexPy WebAuth :: Invalid admin login attempt from '%s'." % username)
|
logger.debug(u"Tautulli WebAuth :: Invalid admin login attempt from '%s'." % username)
|
||||||
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
|
||||||
else:
|
else:
|
||||||
self.on_login_failed(username)
|
self.on_login_failed(username)
|
||||||
logger.debug(u"PlexPy WebAuth :: Invalid login attempt from '%s'." % username)
|
logger.debug(u"Tautulli WebAuth :: Invalid login attempt from '%s'." % username)
|
||||||
return self.get_loginform(username, u"Incorrect username/email or password.")
|
return self.get_loginform(username, u"Incorrect username/email or password.")
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
|
@ -192,7 +192,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_date_formats(self, **kwargs):
|
def get_date_formats(self, **kwargs):
|
||||||
""" Get the date and time formats used by PlexPy.
|
""" Get the date and time formats used by Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -400,7 +400,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi("get_libraries_table")
|
@addtoapi("get_libraries_table")
|
||||||
def get_library_list(self, **kwargs):
|
def get_library_list(self, **kwargs):
|
||||||
""" Get the data on the PlexPy libraries table.
|
""" Get the data on the Tautulli libraries table.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -553,7 +553,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def edit_library(self, section_id=None, **kwargs):
|
def edit_library(self, section_id=None, **kwargs):
|
||||||
""" Update a library section on PlexPy.
|
""" Update a library section on Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -664,7 +664,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_library_media_info(self, section_id=None, section_type=None, rating_key=None, refresh='', **kwargs):
|
def get_library_media_info(self, section_id=None, section_type=None, rating_key=None, refresh='', **kwargs):
|
||||||
""" Get the data on the PlexPy media info tables.
|
""" Get the data on the Tautulli media info tables.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -910,7 +910,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_all_library_history(self, section_id, **kwargs):
|
def delete_all_library_history(self, section_id, **kwargs):
|
||||||
""" Delete all PlexPy history for a specific library.
|
""" Delete all Tautulli history for a specific library.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -938,7 +938,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_library(self, section_id, **kwargs):
|
def delete_library(self, section_id, **kwargs):
|
||||||
""" Delete a library section from PlexPy. Also erases all history for the library.
|
""" Delete a library section from Tautulli. Also erases all history for the library.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -966,7 +966,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def undelete_library(self, section_id=None, section_name=None, **kwargs):
|
def undelete_library(self, section_id=None, section_name=None, **kwargs):
|
||||||
""" Restore a deleted library section to PlexPy.
|
""" Restore a deleted library section to Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1066,7 +1066,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi("get_users_table")
|
@addtoapi("get_users_table")
|
||||||
def get_user_list(self, **kwargs):
|
def get_user_list(self, **kwargs):
|
||||||
""" Get the data on PlexPy users table.
|
""" Get the data on Tautulli users table.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1179,7 +1179,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def edit_user(self, user_id=None, **kwargs):
|
def edit_user(self, user_id=None, **kwargs):
|
||||||
""" Update a user on PlexPy.
|
""" Update a user on Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1276,7 +1276,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_user_ips(self, user_id=None, **kwargs):
|
def get_user_ips(self, user_id=None, **kwargs):
|
||||||
""" Get the data on PlexPy users IP table.
|
""" Get the data on Tautulli users IP table.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1342,7 +1342,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_user_logins(self, user_id=None, **kwargs):
|
def get_user_logins(self, user_id=None, **kwargs):
|
||||||
""" Get the data on PlexPy user login table.
|
""" Get the data on Tautulli user login table.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1527,7 +1527,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_all_user_history(self, user_id, **kwargs):
|
def delete_all_user_history(self, user_id, **kwargs):
|
||||||
""" Delete all PlexPy history for a specific user.
|
""" Delete all Tautulli history for a specific user.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1553,7 +1553,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_user(self, user_id, **kwargs):
|
def delete_user(self, user_id, **kwargs):
|
||||||
""" Delete a user from PlexPy. Also erases all history for the user.
|
""" Delete a user from Tautulli. Also erases all history for the user.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1579,7 +1579,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def undelete_user(self, user_id=None, username=None, **kwargs):
|
def undelete_user(self, user_id=None, username=None, **kwargs):
|
||||||
""" Restore a deleted user to PlexPy.
|
""" Restore a deleted user to Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -1619,7 +1619,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_history(self, user=None, user_id=None, grouping=None, **kwargs):
|
def get_history(self, user=None, user_id=None, grouping=None, **kwargs):
|
||||||
""" Get the PlexPy history.
|
""" Get the Tautulli history.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -2401,7 +2401,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_notification_log(self, **kwargs):
|
def get_notification_log(self, **kwargs):
|
||||||
""" Get the data on the PlexPy notification logs table.
|
""" Get the data on the Tautulli notification logs table.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -2430,7 +2430,7 @@ class WebInterface(object):
|
||||||
"rating_key": 153037,
|
"rating_key": 153037,
|
||||||
"script_args": "[]",
|
"script_args": "[]",
|
||||||
"session_key": 147,
|
"session_key": 147,
|
||||||
"subject_text": "PlexPy (Winterfell-Server)",
|
"subject_text": "Tautulli (Winterfell-Server)",
|
||||||
"timestamp": 1462253821,
|
"timestamp": 1462253821,
|
||||||
"user": "DanyKhaleesi69",
|
"user": "DanyKhaleesi69",
|
||||||
"user_id": 8008135
|
"user_id": 8008135
|
||||||
|
@ -2463,7 +2463,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_notification_log(self, **kwargs):
|
def delete_notification_log(self, **kwargs):
|
||||||
""" Delete the PlexPy notification logs.
|
""" Delete the Tautulli notification logs.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required paramters:
|
Required paramters:
|
||||||
|
@ -2488,7 +2488,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def delete_login_log(self, **kwargs):
|
def delete_login_log(self, **kwargs):
|
||||||
""" Delete the PlexPy login logs.
|
""" Delete the Tautulli login logs.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required paramters:
|
Required paramters:
|
||||||
|
@ -3128,8 +3128,8 @@ class WebInterface(object):
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi("notify")
|
@addtoapi("notify")
|
||||||
def send_notification(self, notifier_id=None, subject='PlexPy', body='Test notification', notify_action='', **kwargs):
|
def send_notification(self, notifier_id=None, subject='Tautulli', body='Test notification', notify_action='', **kwargs):
|
||||||
""" Send a notification using PlexPy.
|
""" Send a notification using Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -3210,11 +3210,11 @@ class WebInterface(object):
|
||||||
access_token = facebook._get_credentials(code)
|
access_token = facebook._get_credentials(code)
|
||||||
|
|
||||||
if access_token:
|
if access_token:
|
||||||
return "Facebook authorization successful. PlexPy can send notification to Facebook. " \
|
return "Facebook authorization successful. Tautulli can send notification to Facebook. " \
|
||||||
"Your Facebook access token is:" \
|
"Your Facebook access token is:" \
|
||||||
"<pre>{0}</pre>You may close this page.".format(access_token)
|
"<pre>{0}</pre>You may close this page.".format(access_token)
|
||||||
else:
|
else:
|
||||||
return "Failed to request authorization from Facebook. Check the PlexPy logs for details.<br />You may close this page."
|
return "Failed to request authorization from Facebook. Check the Tautulli logs for details.<br />You may close this page."
|
||||||
|
|
||||||
@cherrypy.expose
|
@cherrypy.expose
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
|
@ -3342,7 +3342,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def import_database(self, app=None, database_path=None, table_name=None, import_ignore_interval=0, **kwargs):
|
def import_database(self, app=None, database_path=None, table_name=None, import_ignore_interval=0, **kwargs):
|
||||||
""" Import a PlexWatch or Plexivity database into PlexPy.
|
""" Import a PlexWatch or Plexivity database into Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -3368,7 +3368,7 @@ class WebInterface(object):
|
||||||
kwargs={'database': database_path,
|
kwargs={'database': database_path,
|
||||||
'table_name': table_name,
|
'table_name': table_name,
|
||||||
'import_ignore_interval': import_ignore_interval}).start()
|
'import_ignore_interval': import_ignore_interval}).start()
|
||||||
return 'Import has started. Check the PlexPy logs to monitor any problems.'
|
return 'Import has started. Check the Tautulli logs to monitor any problems.'
|
||||||
else:
|
else:
|
||||||
return db_check_msg
|
return db_check_msg
|
||||||
elif app.lower() == 'plexivity':
|
elif app.lower() == 'plexivity':
|
||||||
|
@ -3379,7 +3379,7 @@ class WebInterface(object):
|
||||||
kwargs={'database': database_path,
|
kwargs={'database': database_path,
|
||||||
'table_name': table_name,
|
'table_name': table_name,
|
||||||
'import_ignore_interval': import_ignore_interval}).start()
|
'import_ignore_interval': import_ignore_interval}).start()
|
||||||
return 'Import has started. Check the PlexPy logs to monitor any problems.'
|
return 'Import has started. Check the Tautulli logs to monitor any problems.'
|
||||||
else:
|
else:
|
||||||
return db_check_msg
|
return db_check_msg
|
||||||
else:
|
else:
|
||||||
|
@ -3401,7 +3401,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_pms_token(self, username=None, password=None, **kwargs):
|
def get_pms_token(self, username=None, password=None, **kwargs):
|
||||||
""" Get the user's Plex token used for PlexPy.
|
""" Get the user's Plex token used for Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -3412,7 +3412,7 @@ class WebInterface(object):
|
||||||
None
|
None
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
string: The Plex token used for PlexPy
|
string: The Plex token used for Tautulli
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
if not username and not password:
|
if not username and not password:
|
||||||
|
@ -3431,7 +3431,7 @@ class WebInterface(object):
|
||||||
@cherrypy.tools.json_out()
|
@cherrypy.tools.json_out()
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
def get_plexpy_pms_token(self, username=None, password=None, force=False, **kwargs):
|
def get_plexpy_pms_token(self, username=None, password=None, force=False, **kwargs):
|
||||||
""" Fetch a new Plex.tv token for PlexPy """
|
""" Fetch a new Plex.tv token for Tautulli """
|
||||||
if not username and not password:
|
if not username and not password:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -3656,7 +3656,7 @@ class WebInterface(object):
|
||||||
@requireAuth()
|
@requireAuth()
|
||||||
@addtoapi('notify_recently_added')
|
@addtoapi('notify_recently_added')
|
||||||
def send_manual_on_created(self, notifier_id='', rating_key='', **kwargs):
|
def send_manual_on_created(self, notifier_id='', rating_key='', **kwargs):
|
||||||
""" Send a recently added notification using PlexPy.
|
""" Send a recently added notification using Tautulli.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
@ -3786,7 +3786,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def download_config(self, **kwargs):
|
def download_config(self, **kwargs):
|
||||||
""" Download the PlexPy configuration file. """
|
""" Download the Tautulli configuration file. """
|
||||||
config_file = config.FILENAME
|
config_file = config.FILENAME
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -3800,7 +3800,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def download_database(self, **kwargs):
|
def download_database(self, **kwargs):
|
||||||
""" Download the PlexPy database file. """
|
""" Download the Tautulli database file. """
|
||||||
database_file = database.FILENAME
|
database_file = database.FILENAME
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -3817,7 +3817,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def download_log(self, logfile='', **kwargs):
|
def download_log(self, logfile='', **kwargs):
|
||||||
""" Download the PlexPy log file. """
|
""" Download the Tautulli log file. """
|
||||||
if logfile == "plexpy_api":
|
if logfile == "plexpy_api":
|
||||||
filename = logger.FILENAME_API
|
filename = logger.FILENAME_API
|
||||||
log = logger.logger_api
|
log = logger.logger_api
|
||||||
|
@ -4000,7 +4000,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def update_metadata_details(self, old_rating_key, new_rating_key, media_type, **kwargs):
|
def update_metadata_details(self, old_rating_key, new_rating_key, media_type, **kwargs):
|
||||||
""" Update the metadata in the PlexPy database by matching rating keys.
|
""" Update the metadata in the Tautulli database by matching rating keys.
|
||||||
Also updates all parents or children of the media item if it is a show/season/episode
|
Also updates all parents or children of the media item if it is a show/season/episode
|
||||||
or artist/album/track.
|
or artist/album/track.
|
||||||
|
|
||||||
|
@ -4068,7 +4068,7 @@ class WebInterface(object):
|
||||||
@requireAuth(member_of("admin"))
|
@requireAuth(member_of("admin"))
|
||||||
@addtoapi()
|
@addtoapi()
|
||||||
def get_old_rating_keys(self, rating_key='', media_type='', **kwargs):
|
def get_old_rating_keys(self, rating_key='', media_type='', **kwargs):
|
||||||
""" Get a list of old rating keys from the PlexPy database for all of the item's parent/children.
|
""" Get a list of old rating keys from the Tautulli database for all of the item's parent/children.
|
||||||
|
|
||||||
```
|
```
|
||||||
Required parameters:
|
Required parameters:
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
# This file is part of PlexPy.
|
# This file is part of Tautulli.
|
||||||
#
|
#
|
||||||
# PlexPy is free software: you can redistribute it and/or modify
|
# Tautulli is free software: you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
# (at your option) any later version.
|
# (at your option) any later version.
|
||||||
#
|
#
|
||||||
# PlexPy is distributed in the hope that it will be useful,
|
# Tautulli is distributed in the hope that it will be useful,
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
# GNU General Public License for more details.
|
# GNU General Public License for more details.
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
|
# along with Tautulli. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -37,11 +37,11 @@ def initialize(options):
|
||||||
if plexpy.CONFIG.HTTPS_CREATE_CERT and \
|
if plexpy.CONFIG.HTTPS_CREATE_CERT and \
|
||||||
(not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key))):
|
(not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key))):
|
||||||
if not create_https_certificates(https_cert, https_key):
|
if not create_https_certificates(https_cert, https_key):
|
||||||
logger.warn(u"PlexPy WebStart :: Unable to create certificate and key. Disabling HTTPS")
|
logger.warn(u"Tautulli WebStart :: Unable to create certificate and key. Disabling HTTPS")
|
||||||
enable_https = False
|
enable_https = False
|
||||||
|
|
||||||
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
|
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
|
||||||
logger.warn(u"PlexPy WebStart :: Disabled HTTPS because of missing certificate and key.")
|
logger.warn(u"Tautulli WebStart :: Disabled HTTPS because of missing certificate and key.")
|
||||||
enable_https = False
|
enable_https = False
|
||||||
|
|
||||||
options_dict = {
|
options_dict = {
|
||||||
|
@ -67,7 +67,7 @@ def initialize(options):
|
||||||
protocol = "http"
|
protocol = "http"
|
||||||
|
|
||||||
if options['http_password']:
|
if options['http_password']:
|
||||||
logger.info(u"PlexPy WebStart :: Web server authentication is enabled, username is '%s'", options['http_username'])
|
logger.info(u"Tautulli WebStart :: Web server authentication is enabled, username is '%s'", options['http_username'])
|
||||||
if options['http_basic_auth']:
|
if options['http_basic_auth']:
|
||||||
auth_enabled = session_enabled = False
|
auth_enabled = session_enabled = False
|
||||||
basic_auth_enabled = True
|
basic_auth_enabled = True
|
||||||
|
@ -97,7 +97,7 @@ def initialize(options):
|
||||||
'tools.sessions.on': session_enabled,
|
'tools.sessions.on': session_enabled,
|
||||||
'tools.sessions.timeout': 30 * 24 * 60, # 30 days
|
'tools.sessions.timeout': 30 * 24 * 60, # 30 days
|
||||||
'tools.auth_basic.on': basic_auth_enabled,
|
'tools.auth_basic.on': basic_auth_enabled,
|
||||||
'tools.auth_basic.realm': 'PlexPy web server',
|
'tools.auth_basic.realm': 'Tautulli web server',
|
||||||
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict({
|
'tools.auth_basic.checkpassword': cherrypy.lib.auth_basic.checkpassword_dict({
|
||||||
options['http_username']: options['http_password']})
|
options['http_username']: options['http_password']})
|
||||||
},
|
},
|
||||||
|
@ -221,7 +221,7 @@ def initialize(options):
|
||||||
cherrypy.tree.mount(WebInterface(), options['http_root'], config=conf)
|
cherrypy.tree.mount(WebInterface(), options['http_root'], config=conf)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info(u"PlexPy WebStart :: Starting PlexPy web server on %s://%s:%d%s", protocol,
|
logger.info(u"Tautulli WebStart :: Starting Tautulli web server on %s://%s:%d%s", protocol,
|
||||||
options['http_host'], options['http_port'], options['http_root'])
|
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:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue