Compare commits

..

5 Commits

Author SHA1 Message Date
JonnyWong16
8e4aba7ed4 v2.1.9 2018-05-21 09:07:12 -07:00
JonnyWong16
8c0ef75d4c Fix typos and some cleanup 2018-05-21 09:07:01 -07:00
JonnyWong16
76c4b3bb71 Add Live to notification parameter 2018-05-21 08:49:35 -07:00
JonnyWong16
112b1c7984 Refactor css pointer class 2018-05-20 17:04:55 -07:00
JonnyWong16
c22a2513e3 Update CONTRIBUTING.md 2018-05-19 09:12:13 -07:00
13 changed files with 59 additions and 56 deletions

View File

@@ -1,5 +1,11 @@
# Changelog
## v2.1.9 (2018-05-21)
* Notifications:
* New: Added "live" to notification parameters.
## v2.1.8-beta (2018-05-19)
* Newsletters:

View File

@@ -4,12 +4,12 @@
If you think you can contribute code to the Tautulli repository, do not hesitate to submit a pull request.
### Branches
All pull requests should be based on the `dev` branch, to minimize cross merges. When you want to develop a new feature, clone the repository with `git clone origin/dev -b FEATURE_NAME`. Use meaningful commit messages.
All pull requests should be based on the `nightly` branch, to minimize cross merges. When you want to develop a new feature, clone the repository with `git clone origin/nightly -b FEATURE_NAME`. Use meaningful commit messages.
### Python Code
#### Compatibility
The code should work with Python 2.7. Note that Tautulli runs on different platforms, including Network Attached Storage devices such as Synology.
The code should work with Python 2.7. Note that Tautulli runs on many different platforms.
Re-use existing code. Do not hesitate to add logging in your code. You can the logger module `plexpy.logger.*` for this. Web requests are invoked via `plexpy.request.*` and derived ones. Use these methods to automatically add proper and meaningful error handling.
@@ -29,13 +29,10 @@ Although Tautulli did not adapt a code convention in the past, we try to follow
#### Documentation
Document your code. Use docstrings See [PEP-257](https://www.python.org/dev/peps/pep-0257/) for more information.
#### Continuous Integration
Tautulli has a configuration file for [travis-ci](https://travis-ci.org/). You can add your forked repo to Travis to have it check your code against PEP8, PyLint, and PyFlakes for you. Your pull request will show a green check mark or a red cross on each tested commit, depending on if linting passes.
### HTML/Template code
#### Compatibility
HTML5 compatible browsers are targetted. There is no specific mobile version of Tautulli yet.
HTML5 compatible browsers are targeted.
#### Conventions
* 4 space indentation

View File

@@ -2935,6 +2935,7 @@ a .home-platforms-list-cover-face:hover
}
.stacked-configs > li > span > a.toggle-left,
.stacked-configs > li > span > span.toggle-left {
float: left;
color: #444;
padding-right: 8px;
}
@@ -2945,16 +2946,6 @@ a .home-platforms-list-cover-face:hover
.stacked-configs > li > span > span.active {
color: #f9be03;
}
.stacked-configs > li.new-notification-agent,
.stacked-configs > li.notification-agent,
.stacked-configs > li.add-notification-agent,
.stacked-configs > li.new-newsletter-agent,
.stacked-configs > li.newsletter-agent,
.stacked-configs > li.add-newsletter-agent,
.stacked-configs > li.mobile-device,
.stacked-configs > li.add-mobile-device {
cursor: pointer;
}
.stacked-configs > li.mobile-device > span > a.toggle-left,
.stacked-configs > li.mobile-device > span > span.toggle-left {
color: #999;
@@ -4102,3 +4093,6 @@ a[data-tab-destination] {
margin: 0 auto 50px auto;
text-align: center;
}
.pointer {
cursor: pointer;
}

View File

@@ -11,12 +11,11 @@ DOCUMENTATION :: END
<ul class="stacked-configs list-unstyled">
% for device in sorted(devices_list, key=lambda k: k['device_name']):
<li class="mobile-device" data-id="${device['id']}" data-name="${device['device_name']}">
<li class="mobile-device pointer" data-id="${device['id']}" data-name="${device['device_name']}">
<span>
<!--<span class="toggle-right mobile-device-tooltip edit-mobile-device" data-toggle="tooltip" data-placement="top" title="Edit Device"><i class="fa fa-lg fa-pencil"></i></span>-->
<span class="toggle-left"><i class="fa fa-lg fa-mobile"></i></span>
<span class="toggle-left"><i class="fa fa-lg fa-fw fa-mobile"></i></span>
${device['friendly_name'] or device['device_name']} &nbsp;<span class="friendly_name">(${device['id']})</span>
<span class="toggle-right"><i class="fa fa-lg fa-cog"></i></span>
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-cog"></i></span>
<span class="toggle-right friendly_name" id="device-last_seen-${device['id']}">
% if device['last_seen']:
<script>
@@ -26,14 +25,13 @@ DOCUMENTATION :: END
never
% endif
</span>
<!--<span class="toggle-right delete-mobile-device" data-toggle="tooltip" data-placement="top" title="Remove Device"><i class="fa fa-lg fa-times"></i></span>-->
</span>
</li>
% endfor
<li class="add-mobile-device" id="register-mobile-device" data-target="#api-qr-modal" data-toggle="modal">
<li class="add-mobile-device pointer" id="register-mobile-device" data-target="#api-qr-modal" data-toggle="modal">
<span>
<span class="toggle-left"><i class="fa fa-lg fa-mobile"></i></span> Register a new device
<span class="toggle-right"><i class="fa fa-lg fa-plus"></i></span>
<span class="toggle-left"><i class="fa fa-lg fa-fw fa-mobile"></i></span> Register a new device
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-plus"></i></span>
</span>
</li>
</ul>

View File

@@ -12,15 +12,15 @@ DOCUMENTATION :: END
<% from plexpy.newsletter_handler import NEWSLETTER_SCHED %>
<ul class="stacked-configs list-unstyled">
% for newsletter in sorted(newsletters_list, key=lambda k: (k['agent_label'], k['friendly_name'], k['id'])):
<li class="newsletter-agent" data-id="${newsletter['id']}">
<li class="newsletter-agent pointer" data-id="${newsletter['id']}">
<span>
<span class="toggle-left trigger-tooltip ${'active' if newsletter['active'] else ''}" data-toggle="tooltip" data-placement="top" title="Newsletter ${'active' if newsletter['active'] else 'inactive'}"><i class="fa fa-lg fa-newspaper-o"></i></span>
<span class="toggle-left trigger-tooltip ${'active' if newsletter['active'] else ''}" data-toggle="tooltip" data-placement="top" title="Newsletter ${'active' if newsletter['active'] else 'inactive'}"><i class="fa fa-lg fa-fw fa-newspaper-o"></i></span>
% if newsletter['friendly_name']:
${newsletter['agent_label']} &nbsp;<span class="friendly_name">(${newsletter['id']} - ${newsletter['friendly_name']})</span>
% else:
${newsletter['agent_label']} &nbsp;<span class="friendly_name">(${newsletter['id']})</span>
% endif
<span class="toggle-right"><i class="fa fa-lg fa-cog"></i></span>
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-cog"></i></span>
<span class="toggle-right friendly_name" id="newsletter-next_run-${newsletter['id']}">
% if NEWSLETTER_SCHED.get_job('newsletter-{}'.format(newsletter['id'])):
<% job = NEWSLETTER_SCHED.get_job('newsletter-{}'.format(newsletter['id'])) %>
@@ -32,10 +32,10 @@ DOCUMENTATION :: END
</span>
</li>
% endfor
<li class="add-newsletter-agent" id="add-newsletter-agent" data-target="#add-newsletter-modal" data-toggle="modal">
<li class="add-newsletter-agent pointer" id="add-newsletter-agent" data-target="#add-newsletter-modal" data-toggle="modal">
<span>
<span class="toggle-left"><i class="fa fa-lg fa-newspaper-o"></i></span> Add a new newsletter agent
<span class="toggle-right"><i class="fa fa-lg fa-plus"></i></span>
<span class="toggle-left"><i class="fa fa-lg fa-fw fa-newspaper-o"></i></span> Add a new newsletter agent
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-plus"></i></span>
</span>
</li>
</ul>

View File

@@ -1,7 +1,8 @@
% if notifier:
<%!
import json
from plexpy import helpers, notifiers, users
from plexpy import notifiers, users
from plexpy.helpers import checked
available_notification_actions = notifiers.available_notification_actions()
user_emails = [{'user': u['friendly_name'] or u['username'], 'email': u['email']} for u in users.Users().get_users() if u['email']]
@@ -70,7 +71,7 @@
% elif item['input_type'] == 'checkbox':
<div class="checkbox">
<label>
<input type="checkbox" data-id="${item['name']}" class="checkboxes" value="1" ${helpers.checked(item['value'])}> ${item['label']}
<input type="checkbox" data-id="${item['name']}" class="checkboxes" value="1" ${checked(item['value'])}> ${item['label']}
</label>
<p class="help-block">${item['description'] | n}</p>
<input type="hidden" id="${item['name']}" name="${item['name']}" value="${item['value']}">
@@ -146,7 +147,7 @@
% for action in available_notification_actions:
<div class="checkbox">
<label>
<input type="checkbox" data-id="${action['name']}" class="checkboxes" value="1" ${helpers.checked(notifier['actions'][action['name']])}> ${action['label']}
<input type="checkbox" data-id="${action['name']}" class="checkboxes" value="1" ${checked(notifier['actions'][action['name']])}> ${action['label']}
</label>
<p class="help-block">${action['description'] | n}</p>
<input type="hidden" id="${action['name']}" name="${action['name']}" value="${notifier['actions'][action['name']]}">

View File

@@ -11,22 +11,22 @@ DOCUMENTATION :: END
<ul class="stacked-configs list-unstyled">
% for notifier in sorted(notifiers_list, key=lambda k: (k['agent_label'].lower(), k['friendly_name'], k['id'])):
<li class="notification-agent" data-id="${notifier['id']}">
<li class="notification-agent pointer" data-id="${notifier['id']}">
<span>
<span class="toggle-left trigger-tooltip ${'active' if notifier['active'] else ''}" data-toggle="tooltip" data-placement="top" title="Triggers ${'active' if notifier['active'] else 'inactive'}"><i class="fa fa-lg fa-bell"></i></span>
<span class="toggle-left trigger-tooltip ${'active' if notifier['active'] else ''}" data-toggle="tooltip" data-placement="top" title="Triggers ${'active' if notifier['active'] else 'inactive'}"><i class="fa fa-lg fa-fw fa-bell"></i></span>
% if notifier['friendly_name']:
${notifier['agent_label']} &nbsp;<span class="friendly_name">(${notifier['id']} - ${notifier['friendly_name']})</span>
% else:
${notifier['agent_label']} &nbsp;<span class="friendly_name">(${notifier['id']})</span>
% endif
<span class="toggle-right"><i class="fa fa-lg fa-cog"></i></span>
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-cog"></i></span>
</span>
</li>
% endfor
<li class="add-notification-agent" id="add-notification-agent" data-target="#add-notifier-modal" data-toggle="modal">
<li class="add-notification-agent pointer" id="add-notification-agent" data-target="#add-notifier-modal" data-toggle="modal">
<span>
<span class="toggle-left"><i class="fa fa-lg fa-bell"></i></span> Add a new notification agent
<span class="toggle-right"><i class="fa fa-lg fa-plus"></i></span>
<span class="toggle-left"><i class="fa fa-lg fa-fw fa-bell"></i></span> Add a new notification agent
<span class="toggle-right"><i class="fa fa-lg fa-fw fa-plus"></i></span>
</span>
</li>
</ul>

View File

@@ -650,7 +650,7 @@
</div>
<div class="form-group has-feedback" id="pms_ip_group">
<label for="pms_ip">Plex IP or Hostname</label>
<label for="pms_ip">Plex IP Address or Hostname</label>
<div class="row">
<div class="col-md-9" id="selectize-pms-ip-container">
<div class="input-group">
@@ -1423,7 +1423,7 @@
<div class="col-md-12">
<ul class="stacked-configs list-unstyled">
% for agent in sorted(available_notification_agents, key=lambda k: k['label'].lower()):
<li class="new-notification-agent" data-id="${agent['id']}">
<li class="new-notification-agent pointer" data-id="${agent['id']}">
<span>${agent['label']}</span>
</li>
% endfor
@@ -1451,7 +1451,7 @@
<div class="col-md-12">
<ul class="stacked-configs list-unstyled">
% for agent in available_newsletter_agents:
<li class="new-newsletter-agent" data-id="${agent['id']}">
<li class="new-newsletter-agent pointer" data-id="${agent['id']}">
<span>${agent['label']}</span>
</li>
% endfor
@@ -1793,6 +1793,7 @@
}
function loadNotifierConfig(notifier_id) {
showMsg('<i class="fa fa-refresh fa-spin"></i>&nbsp; Loading Configuration', false);
$.ajax({
url: 'get_notifier_config_modal',
data: { notifier_id: notifier_id },
@@ -1800,6 +1801,7 @@
async: true,
complete: function (xhr, status) {
$("#notifier-config-modal").html(xhr.responseText).modal('show');
showMsg('<i class="fa fa-check"></i> Configuration Loaded', false, true, 2000);
}
});
}
@@ -1816,6 +1818,7 @@
}
function loadNewsletterConfig(newsletter_id) {
showMsg('<i class="fa fa-refresh fa-spin"></i>&nbsp; Loading Configuration', false);
$.ajax({
url: 'get_newsletter_config_modal',
data: { newsletter_id: newsletter_id },
@@ -1823,6 +1826,7 @@
async: true,
complete: function (xhr, status) {
$("#newsletter-config-modal").html(xhr.responseText).modal('show');
showMsg('<i class="fa fa-check"></i> Configuration Loaded', false, true, 2000);
}
});
}
@@ -1839,6 +1843,7 @@
}
function loadMobileDeviceConfig(mobile_device_id) {
showMsg('<i class="fa fa-refresh fa-spin"></i>&nbsp; Loading Configuration', false);
$.ajax({
url: 'get_mobile_device_config_modal',
data: { mobile_device_id: mobile_device_id },
@@ -1846,6 +1851,7 @@
async: true,
complete: function (xhr, status) {
$("#mobile-device-config-modal").html(xhr.responseText).modal('show');
showMsg('<i class="fa fa-check"></i> Configuration Loaded', false, true, 2000);
}
});
}
@@ -2591,7 +2597,7 @@ $(document).ready(function() {
var result = $.parseJSON(xhr.responseText);
var msg = result.message;
$('#add-notifier-modal').modal('hide');
if (result.result == 'success') {
if (result.result === 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000);
loadNotifierConfig(result.notifier_id);
} else {
@@ -2613,7 +2619,7 @@ $(document).ready(function() {
var result = $.parseJSON(xhr.responseText);
var msg = result.message;
$('#add-newsletter-modal').modal('hide');
if (result.result == 'success') {
if (result.result === 'success') {
showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000);
loadNewsletterConfig(result.newsletter_id);
} else {

View File

@@ -339,6 +339,7 @@ NOTIFICATION_PARAMETERS = [
{'name': 'Optimized Version', 'type': 'int', 'value': 'optimized_version', 'description': 'If the stream is an optimized version.', 'example': '0 or 1'},
{'name': 'Optimized Version Profile', 'type': 'str', 'value': 'optimized_version_profile', 'description': 'The optimized version profile of the stream.'},
{'name': 'Synced Version', 'type': 'int', 'value': 'synced_version', 'description': 'If the stream is an synced version.', 'example': '0 or 1'},
{'name': 'Live', 'type': 'int', 'value': 'live', 'description': 'If the stream is live TV.', 'example': '0 or 1'},
{'name': 'Stream Local', 'type': 'int', 'value': 'stream_local', 'description': 'If the stream is local.', 'example': '0 or 1'},
{'name': 'Stream Location', 'type': 'str', 'value': 'stream_location', 'description': 'The network location of the stream.', 'example': 'lan or wan'},
{'name': 'Stream Bandwidth', 'type': 'int', 'value': 'stream_bandwidth', 'description': 'The required bandwidth (in kbps) of the stream.', 'help_text': 'not the used bandwidth'},

View File

@@ -206,7 +206,7 @@ def set_newsletter_config(newsletter_id=None, agent_id=None, **kwargs):
if str(agent_id).isdigit():
agent_id = int(agent_id)
else:
logger.error(u"Tautulli Newsletters :: Unable to set exisiting newsletter: invalid agent_id %s."
logger.error(u"Tautulli Newsletters :: Unable to set existing newsletter: invalid agent_id %s."
% agent_id)
return False

View File

@@ -509,7 +509,7 @@ def add_notifier_config(agent_id=None, **kwargs):
'agent_name': agent['name'],
'agent_label': agent['label'],
'friendly_name': '',
'notifier_config': json.dumps(get_agent_class(agent_id=agent['id']).config),
'notifier_config': json.dumps(agent_class.config),
'custom_conditions': json.dumps(DEFAULT_CUSTOM_CONDITIONS),
'custom_conditions_logic': ''
}
@@ -540,7 +540,7 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
if str(agent_id).isdigit():
agent_id = int(agent_id)
else:
logger.error(u"Tautulli Notifiers :: Unable to set exisiting notifier: invalid agent_id %s."
logger.error(u"Tautulli Notifiers :: Unable to set existing notifier: invalid agent_id %s."
% agent_id)
return False
@@ -570,7 +570,7 @@ def set_notifier_config(notifier_id=None, agent_id=None, **kwargs):
'agent_name': agent['name'],
'agent_label': agent['label'],
'friendly_name': kwargs.get('friendly_name', ''),
'notifier_config': json.dumps(notifier_config),
'notifier_config': json.dumps(agent_class.config),
'custom_conditions': kwargs.get('custom_conditions', json.dumps(DEFAULT_CUSTOM_CONDITIONS)),
'custom_conditions_logic': kwargs.get('custom_conditions_logic', ''),
}
@@ -807,7 +807,7 @@ class Notifier(object):
if response is not None and response.status_code >= 400 and response.status_code < 500:
verify_msg = " Verify you notification agent settings are correct."
logger.error(u"Tautulli Notifiers :: {name} notification failed.{}".format(verify_msg, name=self.NAME))
logger.error(u"Tautulli Notifiers :: {name} notification failed.{msg}".format(msg=verify_msg, name=self.NAME))
if err_msg:
logger.error(u"Tautulli Notifiers :: {}".format(err_msg))

View File

@@ -1,2 +1,2 @@
PLEXPY_BRANCH = "beta"
PLEXPY_RELEASE_VERSION = "v2.1.8-beta"
PLEXPY_BRANCH = "master"
PLEXPY_RELEASE_VERSION = "v2.1.9"

View File

@@ -3222,7 +3222,7 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
@addtoapi()
def set_notifier_config(self, notifier_id=None, agent_id=None, **kwargs):
""" Configure an exisitng notificaiton agent.
""" Configure an existing notification agent.
```
Required parameters:
@@ -3341,10 +3341,10 @@ class WebInterface(object):
return {'result': 'success', 'message': 'Notification queued.'}
else:
logger.debug(u"Unable to send %snotification, invalid notifier_id %s." % (test, notifier_id))
return {'result': 'success', 'message': 'Invalid notifier id %s.' % notifier_id}
return {'result': 'error', 'message': 'Invalid notifier id %s.' % notifier_id}
else:
logger.debug(u"Unable to send %snotification, no notifier_id received." % test)
return {'result': 'success', 'message': 'No notifier id received.'}
return {'result': 'error', 'message': 'No notifier id received.'}
@cherrypy.expose
@cherrypy.tools.json_out()
@@ -3481,7 +3481,7 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
@addtoapi()
def set_mobile_device_config(self, mobile_device_id=None, **kwargs):
""" Configure an exisitng notificaiton agent.
""" Configure an existing notification agent.
```
Required parameters:
@@ -5678,7 +5678,7 @@ class WebInterface(object):
@requireAuth(member_of("admin"))
@addtoapi()
def set_newsletter_config(self, newsletter_id=None, agent_id=None, **kwargs):
""" Configure an exisitng newsletter agent.
""" Configure an existing newsletter agent.
```
Required parameters: