Rename PlexPy to Tautulli

This commit is contained in:
JonnyWong16 2017-12-10 23:07:32 -08:00
parent 55bdde808b
commit 19f029cff0
50 changed files with 867 additions and 870 deletions

View file

@ -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)

View file

@ -1,8 +1,8 @@
# PlexPy # Tautulli
[![Discord](https://img.shields.io/badge/Discord-PlexPy-738bd7.svg?style=flat-square)](https://discord.gg/36ggawe) [![Discord](https://img.shields.io/badge/Discord-Tautulli-7289DA.svg?style=flat-square)](https://discord.gg/36ggawe)
[![Gitter](https://img.shields.io/badge/Gitter-PlexPy-ed1965.svg?style=flat-square)](https://gitter.im/plexpy/general) [![Reddit](https://img.shields.io/badge/Reddit-Tautulli-FF5700.svg?style=flat-square)](https://discord.gg/36ggawe)
[![Plex Forums](https://img.shields.io/badge/Plex%20Forums-PlexPy-E5A00D.svg?style=flat-square)](https://forums.plex.tv/discussion/169591/plexpy-another-plex-monitoring-program) [![Plex Forums](https://img.shields.io/badge/Plex%20Forums-Tautulli-E5A00D.svg?style=flat-square)](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)
![PlexPy Homepage](https://i.imgur.com/0D0uFJg.jpg) ![Tautulli Homepage](https://i.imgur.com/0D0uFJg.jpg)
## 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.

View file

@ -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&currency_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&currency_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";

View file

@ -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);
}); });

View file

@ -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>

View file

@ -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">

View file

@ -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>

View file

@ -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);

View file

@ -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>

View file

@ -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({

View file

@ -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);
}); });

View file

@ -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>

View file

@ -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>&nbsp;')
$('#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 () {

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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()

View file

@ -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)

View file

@ -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))

View file

@ -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.")

View file

@ -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

View file

@ -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

View file

@ -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 ##

View file

@ -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.'},

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
""" """

View file

@ -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 = []

View file

@ -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):

View file

@ -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:

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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.")

View file

@ -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 = []

View file

@ -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.")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>'

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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: