mirror of
https://github.com/Tautulli/Tautulli.git
synced 2025-07-10 23:42:37 -07:00
commit
aa75cf2b73
15 changed files with 489 additions and 162 deletions
|
@ -11,7 +11,7 @@ data :: Usable parameters (if not applicable for media type, blank value will be
|
|||
|
||||
== Global keys ==
|
||||
rating_key Returns the unique identifier for the media item.
|
||||
type Returns the type of media. Either 'movie', 'show', 'season', 'episode', 'artist', 'album', or 'track'.
|
||||
media_type Returns the type of media. Either 'movie', 'show', 'season', 'episode', 'artist', 'album', or 'track'.
|
||||
art Returns the location of the item's artwork
|
||||
title Returns the name of the movie, show, episode, artist, album, or track.
|
||||
duration Returns the standard runtime of the media.
|
||||
|
@ -60,7 +60,7 @@ DOCUMENTATION :: END
|
|||
% if data:
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
% if data['type'] != 'library':
|
||||
% if data['media_type'] != 'library':
|
||||
<div class="art-face" style="background-image:url(pms_image_proxy?img=${data['art']}&width=1920&height=1080)"></div>
|
||||
% endif
|
||||
<div class="summary-container">
|
||||
|
@ -68,7 +68,7 @@ DOCUMENTATION :: END
|
|||
<div class="col-md-12">
|
||||
<div class="summary-navbar-list">
|
||||
<ul class="list-unstyled breadcrumb">
|
||||
% if data['type'] == 'library':
|
||||
% if data['media_type'] == 'library':
|
||||
% if data['library'] == 'movie':
|
||||
<li class="active">Movies</li>
|
||||
% elif data['library'] == 'show':
|
||||
|
@ -76,29 +76,29 @@ DOCUMENTATION :: END
|
|||
% elif data['library'] == 'artist':
|
||||
<li class="active">Music</li>
|
||||
% endif
|
||||
% elif data['type'] == 'movie':
|
||||
% elif data['media_type'] == 'movie':
|
||||
<li><a href="info?item_id=movie">Movies</a></li>
|
||||
<li class="active">${data['title']}</li>
|
||||
% elif data['type'] == 'show':
|
||||
% elif data['media_type'] == 'show':
|
||||
<li><a href="info?item_id=show">TV Shows</a></li>
|
||||
<li class="active">${data['title']}</li>
|
||||
% elif data['type'] == 'season':
|
||||
% elif data['media_type'] == 'season':
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=show">TV Shows</a></li>
|
||||
<li><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
<li class="active">Season ${data['index']}</li>
|
||||
% elif data['type'] == 'episode':
|
||||
% elif data['media_type'] == 'episode':
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=show">TV Shows</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
||||
<li><a href="info?item_id=${data['parent_rating_key']}">Season ${data['parent_index']}</a></li>
|
||||
<li class="active">Episode ${data['index']} - ${data['title']}</li>
|
||||
% elif data['type'] == 'artist':
|
||||
% elif data['media_type'] == 'artist':
|
||||
<li><a href="info?item_id=artist">Music</a></li>
|
||||
<li class="active">${data['title']}</li>
|
||||
% elif data['type'] == 'album':
|
||||
% elif data['media_type'] == 'album':
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=artist">Music</a></li>
|
||||
<li><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
<li class="active">${data['title']}</li>
|
||||
% elif data['type'] == 'track':
|
||||
% elif data['media_type'] == 'track':
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=artist">Music</a></li>
|
||||
<li class="hidden-xs hidden-sm"><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></li>
|
||||
<li><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></li>
|
||||
|
@ -108,28 +108,28 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% if data['type'] != 'library':
|
||||
% if data['media_type'] != 'library':
|
||||
<div class="summary-content-title-wrapper">
|
||||
<div class="col-md-9">
|
||||
<div class="summary-content-poster hidden-xs hidden-sm">
|
||||
% if data['type'] == 'track':
|
||||
% if data['media_type'] == 'track':
|
||||
<a href="http://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['parent_rating_key']}" target="Plex/Web" title="View in Plex/Web">
|
||||
% elif data['type'] != 'library':
|
||||
% elif data['media_type'] != 'library':
|
||||
<a href="http://app.plex.tv/web/app#!/server/${config['pms_identifier']}/details/%2Flibrary%2Fmetadata%2F${data['rating_key']}" target="Plex/Web" title="View in Plex/Web">
|
||||
% endif
|
||||
% if data['type'] == 'episode':
|
||||
% if data['media_type'] == 'episode':
|
||||
<div class="summary-poster-face-episode" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=280&fallback=poster);">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['type'] == 'artist' or data['type'] == 'album' or data['type'] == 'track':
|
||||
% elif data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
<div class="summary-poster-face-track" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=500&height=500&fallback=poster);">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['type'] != 'library':
|
||||
% elif data['media_type'] != 'library':
|
||||
<div class="summary-poster-face" style="background-image: url(pms_image_proxy?img=${data['thumb']}&width=300&height=450&fallback=poster);">
|
||||
<div class="summary-poster-face-overlay">
|
||||
<span></span>
|
||||
|
@ -139,19 +139,19 @@ DOCUMENTATION :: END
|
|||
</a>
|
||||
</div>
|
||||
<div class="summary-content-title">
|
||||
% if data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'artist':
|
||||
% if data['media_type'] == 'movie' or data['media_type'] == 'show' or data['media_type'] == 'artist':
|
||||
<h1> </h1><h1>${data['title']}</h1>
|
||||
% elif data['type'] == 'season':
|
||||
% elif data['media_type'] == 'season':
|
||||
<h1> </h1><h1><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
||||
<h3 class="hidden-xs">S${data['index']}</h3>
|
||||
% elif data['type'] == 'episode':
|
||||
% elif data['media_type'] == 'episode':
|
||||
<h1><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
|
||||
<h2>${data['title']}</h2>
|
||||
<h3 class="hidden-xs">S${data['parent_index']} · E${data['index']}</h3>
|
||||
% elif data['type'] == 'album':
|
||||
% elif data['media_type'] == 'album':
|
||||
<h1><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a></h1>
|
||||
<h2>${data['title']}</h2>
|
||||
% elif data['type'] == 'track':
|
||||
% elif data['media_type'] == 'track':
|
||||
<h1><a href="info?item_id=${data['grandparent_rating_key']}">${data['grandparent_title']}</a></h1>
|
||||
<h2><a href="info?item_id=${data['parent_rating_key']}">${data['parent_title']}</a> - ${data['title']}</h2>
|
||||
<h3 class="hidden-xs">T${data['index']}</h3>
|
||||
|
@ -161,13 +161,13 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
% endif
|
||||
<div class="summary-content-wrapper">
|
||||
% if data['type'] != 'library':
|
||||
% if data['media_type'] != 'library':
|
||||
<div class="col-md-9">
|
||||
% if data['type'] == 'movie' or data['type'] == 'show' or data['type'] == 'season':
|
||||
% if data['media_type'] == 'movie' or data['media_type'] == 'show' or data['media_type'] == 'season':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 275px;"></div>
|
||||
% elif data['type'] == 'episode':
|
||||
% elif data['media_type'] == 'episode':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 40px;"></div>
|
||||
% elif data['type'] == 'artist' or data['type'] == 'album' or data['type'] == 'track':
|
||||
% elif data['media_type'] == 'artist' or data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
<div class="summary-content-padding hidden-xs hidden-sm" style="height: 150px;"></div>
|
||||
% else:
|
||||
<div class="summary-content-padding hidden-xs hidden-sm"></div>
|
||||
|
@ -189,13 +189,13 @@ DOCUMENTATION :: END
|
|||
% endif
|
||||
</div>
|
||||
<div class="summary-content-details-tag">
|
||||
% if data['type'] == 'movie':
|
||||
% if data['media_type'] == 'movie':
|
||||
Year <strong> ${data['year']}</strong>
|
||||
% elif data['type'] == 'show':
|
||||
% elif data['media_type'] == 'show':
|
||||
Aired <strong> ${data['year']}</strong>
|
||||
% elif data['type'] == 'episode':
|
||||
% elif data['media_type'] == 'episode':
|
||||
Aired <strong> <span id="airdate">${data['originally_available_at']}</span></strong>
|
||||
% elif data['type'] == 'album' or data['type'] == 'track':
|
||||
% elif data['media_type'] == 'album' or data['media_type'] == 'track':
|
||||
Released <strong> ${data['year']}</strong>
|
||||
% endif
|
||||
</div>
|
||||
|
@ -268,7 +268,7 @@ DOCUMENTATION :: END
|
|||
% endif
|
||||
</div>
|
||||
</div>
|
||||
% if data['type'] == 'show':
|
||||
% if data['media_type'] == 'show':
|
||||
<div class='col-md-12'>
|
||||
<div class='table-card-header'>
|
||||
<div class="header-bar">
|
||||
|
@ -279,7 +279,7 @@ DOCUMENTATION :: END
|
|||
<div id="children-list"><i class="fa fa-refresh fa-spin"></i> Loading season list...</div>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['type'] == 'season':
|
||||
% elif data['media_type'] == 'season':
|
||||
<div class='col-md-12'>
|
||||
<div class='table-card-header'>
|
||||
<div class="header-bar">
|
||||
|
@ -290,7 +290,7 @@ DOCUMENTATION :: END
|
|||
<div id="children-list"><i class="fa fa-refresh fa-spin"></i> Loading episode list...</div>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['type'] == 'artist':
|
||||
% elif data['media_type'] == 'artist':
|
||||
<div class='col-md-12'>
|
||||
<div class='table-card-header'>
|
||||
<div class="header-bar">
|
||||
|
@ -301,7 +301,7 @@ DOCUMENTATION :: END
|
|||
<div id="children-list"><i class="fa fa-refresh fa-spin"></i> Loading album list...</div>
|
||||
</div>
|
||||
</div>
|
||||
% elif data['type'] == 'album':
|
||||
% elif data['media_type'] == 'album':
|
||||
<div class='col-md-12'>
|
||||
<div class='table-card-header'>
|
||||
<div class="header-bar">
|
||||
|
@ -499,7 +499,7 @@ DOCUMENTATION :: END
|
|||
|
||||
% if data:
|
||||
<script src="interfaces/default/js/tables/history_table.js"></script>
|
||||
% if data['type'] == 'library':
|
||||
% if data['media_type'] == 'library':
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
|
@ -507,12 +507,12 @@ DOCUMENTATION :: END
|
|||
type: 'post',
|
||||
data: function ( d ) {
|
||||
return { 'json_data': JSON.stringify( d ),
|
||||
'media_type': "${data['media_type']}" };
|
||||
'media_type': "${data['media_type_filter']}" };
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
% elif data['type'] == 'show' or data['type'] == 'artist':
|
||||
% elif data['media_type'] == 'show' or data['media_type'] == 'artist':
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
|
@ -525,7 +525,7 @@ DOCUMENTATION :: END
|
|||
}
|
||||
}
|
||||
</script>
|
||||
% elif data['type'] == 'season' or data['type'] == 'album':
|
||||
% elif data['media_type'] == 'season' or data['media_type'] == 'album':
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
|
@ -538,7 +538,7 @@ DOCUMENTATION :: END
|
|||
}
|
||||
}
|
||||
</script>
|
||||
% elif data['type'] == 'episode' or data['type'] == 'track' or data['type'] == 'movie':
|
||||
% elif data['media_type'] == 'episode' or data['media_type'] == 'track' or data['media_type'] == 'movie':
|
||||
<script>
|
||||
function get_history() {
|
||||
history_table_options.ajax = {
|
||||
|
@ -599,7 +599,7 @@ DOCUMENTATION :: END
|
|||
});
|
||||
});
|
||||
</script>
|
||||
% if data['type'] == 'show' or data['type'] == 'season' or data['type'] == 'artist' or data['type'] == 'album':
|
||||
% if data['media_type'] == 'show' or data['media_type'] == 'season' or data['media_type'] == 'artist' or data['media_type'] == 'album':
|
||||
<script>
|
||||
$.ajax({
|
||||
url: 'get_item_children',
|
||||
|
@ -611,14 +611,14 @@ DOCUMENTATION :: END
|
|||
});
|
||||
</script>
|
||||
% endif
|
||||
% if data['type'] != 'library':
|
||||
% if data['media_type'] != 'library':
|
||||
<script>
|
||||
$('#row-edit-mode').after('<a href="info?item_id=${data['rating_key']}" class="btn btn-danger btn-edit" id="fix-metadata" \
|
||||
data-toggle="tooltip" data-placement="left" title="Fix metadata if the item was moved in Plex"><i class="fa fa-wrench"></i> Fix Metadata</a>');
|
||||
$('#fix-metadata').tooltip();
|
||||
</script>
|
||||
% endif
|
||||
% if data['type'] != 'library' and data['rating']:
|
||||
% if data['media_type'] != 'library' and data['rating']:
|
||||
<script>
|
||||
// Convert rating to 5 star rating type
|
||||
var starRating = Math.round(${data['rating']} / 2);
|
||||
|
|
|
@ -57,6 +57,13 @@ from plexpy import helpers
|
|||
</label>
|
||||
<p class="help-block">Trigger notification when a media item triggers the defined buffer threshold.</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" data-size="small" data-id="${data['id']}" data-config-name="${data['config_prefix']}_on_created" ${helpers.checked(data['on_created'])} class="toggle-switches">
|
||||
Notify on recently added
|
||||
</label>
|
||||
<p class="help-block">Trigger notification when a media item is added to the Plex Media Server.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -81,6 +88,7 @@ from plexpy import helpers
|
|||
console.log('success');
|
||||
}
|
||||
});
|
||||
$('.toggle-notification-triggers-modal[data-id=' + configToggle + ']').addClass('active');
|
||||
} else {
|
||||
var data = {};
|
||||
data[$(this).data('config-name')] = 0;
|
||||
|
@ -92,6 +100,9 @@ from plexpy import helpers
|
|||
console.log('success');
|
||||
}
|
||||
});
|
||||
if (!($('.toggle-switches').is(":checked"))) {
|
||||
$('.toggle-notification-triggers-modal[data-id=' + configToggle + ']').removeClass('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -11,13 +11,13 @@ data[array_index] :: Usable parameters
|
|||
|
||||
== Global keys ==
|
||||
rating_key Returns the unique identifier for the media item.
|
||||
type Returns the type of media. Either 'movie' or 'season'.
|
||||
media_type Returns the media type of media. Either 'movie' or 'season' or 'album'.
|
||||
thumb Returns the location of the item's thumbnail. Use with pms_image_proxy.
|
||||
added_at Returns the time when the media was added to the library.
|
||||
title Returns the name of the movie or season.
|
||||
parent_title Returns the name of the TV Show a season belongs too.
|
||||
|
||||
== Only if 'type' is 'movie' ==
|
||||
== Only if 'media_type' is 'movie' ==
|
||||
year Returns the movie release year.
|
||||
|
||||
DOCUMENTATION :: END
|
||||
|
@ -29,7 +29,7 @@ DOCUMENTATION :: END
|
|||
% for item in data:
|
||||
<div class="dashboard-recent-media-instance">
|
||||
<li>
|
||||
% if item['type'] == 'season' or item['type'] == 'movie':
|
||||
% if item['media_type'] == 'season' or item['media_type'] == 'movie':
|
||||
<a href="info?item_id=${item['rating_key']}">
|
||||
<div class="dashboard-recent-media-poster">
|
||||
<div class="dashboard-recent-media-poster-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=450&fallback=poster);">
|
||||
|
@ -43,16 +43,16 @@ DOCUMENTATION :: END
|
|||
</div>
|
||||
</div>
|
||||
<div class="dashboard-recent-media-metacontainer">
|
||||
% if item['type'] == 'season':
|
||||
% if item['media_type'] == 'season':
|
||||
<h3 title="${item['parent_title']}">${item['parent_title']}</h3>
|
||||
<h3 class="text-muted">${item['title']}</h3>
|
||||
% elif item['type'] == 'movie':
|
||||
% elif item['media_type'] == 'movie':
|
||||
<h3 title="${item['title']}">${item['title']}</h3>
|
||||
<h3 class="text-muted">${item['year']}</h3>
|
||||
% endif
|
||||
</div>
|
||||
</a>
|
||||
% elif item['type'] == 'album':
|
||||
% elif item['media_type'] == 'album':
|
||||
<a href="info?item_id=${item['rating_key']}">
|
||||
<div class="dashboard-recent-media-cover">
|
||||
<div class="dashboard-recent-media-cover-face" style="background-image: url(pms_image_proxy?img=${item['thumb']}&width=300&height=300&fallback=cover);">
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import plexpy
|
||||
from plexpy import notifiers, common, versioncheck
|
||||
|
||||
available_notification_agents = notifiers.available_notification_agents()
|
||||
available_notification_agents = sorted(notifiers.available_notification_agents(), key=lambda k: k['name'])
|
||||
%>
|
||||
<%def name="headIncludes()">
|
||||
</%def>
|
||||
|
@ -502,6 +502,12 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
</label>
|
||||
<p class="help-block">Disable to prevent consecutive notifications (i.e. both watched & stopped notifications).</p>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="notify_recently_added_grandparent" id="notify_recently_added_grandparent" value="1" ${config['notify_recently_added_grandparent']}> Group notifications for recently added TV Shows or Music
|
||||
</label>
|
||||
<p class="help-block">Enable to only get one notification for recently added Episodes or Tracks. Movies are unaffected.</p>
|
||||
</div>
|
||||
|
||||
<div class="padded-header">
|
||||
<h3>Custom Notification Messages</h3>
|
||||
|
@ -515,7 +521,7 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
<a href="#notify-text-tags-modal" data-toggle="modal">here</a> to view usage information.
|
||||
</p>
|
||||
<br/>
|
||||
<ul id="accordion" class="accordion list-unstyled">
|
||||
<ul id="accordion-session" class="accordion list-unstyled">
|
||||
<li>
|
||||
<div class="link"><i class="fa fa-play"></i>Playback Start<i class="fa fa-chevron-down"></i></div>
|
||||
<ul class="submenu">
|
||||
|
@ -619,6 +625,25 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul id="accordion-timeline" class="accordion list-unstyled">
|
||||
<li>
|
||||
<div class="link"><i class="fa fa-download"></i>Recently Added<i class="fa fa-chevron-down"></i></div>
|
||||
<ul class="submenu">
|
||||
<li>
|
||||
<div class="form-group">
|
||||
<label for="notify_on_created_subject_text">Subject Line</label>
|
||||
<input class="form-control" type="text" id="notify_on_created_subject_text" name="notify_on_created_subject_text" value="${config['notify_on_created_subject_text']}" data-parsley-trigger="change" required>
|
||||
<p class="help-block">Set a custom subject line.</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="notify_on_created_body_text">Message Body</label>
|
||||
<input class="form-control" type="text" id="notify_on_created_body_text" name="notify_on_created_body_text" value="${config['notify_on_created_body_text']}" data-parsley-trigger="change" required>
|
||||
<p class="help-block">Set a custom body.</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p><input type="button" class="btn btn-bright save-button" value="Save" data-success="Changes saved successfully"></p>
|
||||
</div>
|
||||
|
@ -635,7 +660,7 @@ available_notification_agents = notifiers.available_notification_agents()
|
|||
% for agent in available_notification_agents:
|
||||
<li>
|
||||
<span>
|
||||
% if agent['on_play'] or agent['on_stop'] or agent['on_pause'] or agent['on_resume'] or agent['on_buffer'] or agent['on_watched']:
|
||||
% if agent['on_play'] or agent['on_stop'] or agent['on_pause'] or agent['on_resume'] or agent['on_buffer'] or agent['on_watched'] or agent['on_created']:
|
||||
<a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left active" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a>
|
||||
% else:
|
||||
<a href="javascript:void(0)" data-target="#notification-triggers-modal" data-id="${agent['id']}" class="toggle-notification-triggers-modal toggle-left" data-toggle="modal"><i class="fa fa-lg fa-bell"></i></a>
|
||||
|
@ -1292,7 +1317,8 @@ $(document).ready(function() {
|
|||
}
|
||||
}
|
||||
|
||||
var accordion = new Accordion($('#accordion'), false);
|
||||
var accordion_session = new Accordion($('#accordion-session'), false);
|
||||
var accordion_timeline = new Accordion($('#accordion-timeline'), false);
|
||||
|
||||
var cards = "${config['home_stats_cards']}".split(/[\s,]+/);
|
||||
cards.forEach(function (item) {
|
||||
|
|
|
@ -286,6 +286,8 @@ def initialize_scheduler():
|
|||
if not CONFIG.MONITORING_USE_WEBSOCKET or POLLING_FAILOVER:
|
||||
schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions',
|
||||
hours=0, minutes=0, seconds=seconds)
|
||||
schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
||||
hours=0, minutes=0, seconds=seconds)
|
||||
|
||||
# Refresh the users list
|
||||
if CONFIG.REFRESH_USERS_INTERVAL:
|
||||
|
@ -552,7 +554,7 @@ def dbcheck():
|
|||
'CREATE TABLE IF NOT EXISTS notify_log (id INTEGER PRIMARY KEY AUTOINCREMENT, '
|
||||
'session_key INTEGER, rating_key INTEGER, user_id INTEGER, user TEXT, '
|
||||
'agent_id INTEGER, agent_name TEXT, on_play INTEGER, on_stop INTEGER, on_watched INTEGER, '
|
||||
'on_pause INTEGER, on_resume INTEGER, on_buffer INTEGER)'
|
||||
'on_pause INTEGER, on_resume INTEGER, on_buffer INTEGER, on_created INTEGER)'
|
||||
)
|
||||
|
||||
# Upgrade users table from earlier versions
|
||||
|
@ -588,6 +590,15 @@ def dbcheck():
|
|||
'ALTER TABLE notify_log ADD COLUMN on_buffer INTEGER'
|
||||
)
|
||||
|
||||
# Upgrade notify_log table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT on_created from notify_log')
|
||||
except sqlite3.OperationalError:
|
||||
logger.debug(u"Altering database. Updating database table notify_log.")
|
||||
c_db.execute(
|
||||
'ALTER TABLE notify_log ADD COLUMN on_created INTEGER'
|
||||
)
|
||||
|
||||
# Upgrade sessions table from earlier versions
|
||||
try:
|
||||
c_db.execute('SELECT buffer_count from sessions')
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This file is part of PlexPy.
|
||||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -213,3 +213,53 @@ class ActivityHandler(object):
|
|||
# We don't have this session in our table yet, start a new one.
|
||||
if this_state != 'buffering':
|
||||
self.on_start()
|
||||
|
||||
class TimelineHandler(object):
|
||||
|
||||
def __init__(self, timeline):
|
||||
self.timeline = timeline
|
||||
# print timeline
|
||||
|
||||
def is_item(self):
|
||||
if 'itemID' in self.timeline:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_rating_key(self):
|
||||
if self.is_item():
|
||||
return int(self.timeline['itemID'])
|
||||
|
||||
return None
|
||||
|
||||
def get_metadata(self):
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
metadata_list = pms_connect.get_metadata_details(self.get_rating_key())
|
||||
|
||||
if metadata_list:
|
||||
return metadata_list['metadata']
|
||||
|
||||
return None
|
||||
|
||||
def on_created(self):
|
||||
if self.is_item():
|
||||
logger.debug(u"PlexPy TimelineHandler :: Library item %s has been added to Plex." % str(self.get_rating_key()))
|
||||
|
||||
# Fire off notifications
|
||||
threading.Thread(target=notification_handler.notify_timeline,
|
||||
kwargs=dict(timeline_data=self.get_metadata(), notify_action='created')).start()
|
||||
|
||||
# This function receives events from our websocket connection
|
||||
def process(self):
|
||||
if self.is_item():
|
||||
|
||||
this_state = self.timeline['state']
|
||||
this_type = self.timeline['type']
|
||||
this_metadataState = self.timeline.get('metadataState', None)
|
||||
this_mediaState = self.timeline.get('mediaState', None)
|
||||
|
||||
# state: 5: done processing metadata
|
||||
# type: 1: movie, 2: tv show, 4: episode, 8: artist, 10: track
|
||||
types = [1, 2, 4, 8, 10]
|
||||
if this_state == 5 and this_type in types and this_metadataState == None and this_mediaState == None:
|
||||
self.on_created()
|
|
@ -1,4 +1,4 @@
|
|||
# This file is part of PlexPy.
|
||||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -162,3 +162,50 @@ def check_active_sessions(ws_request=False):
|
|||
monitor_process.write_session(session)
|
||||
else:
|
||||
logger.debug(u"PlexPy Monitor :: Unable to read session list.")
|
||||
|
||||
|
||||
def check_recently_added():
|
||||
|
||||
with monitor_lock:
|
||||
current_time = int(time.time())
|
||||
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
recently_added_list = pms_connect.get_recently_added_details(count='10')
|
||||
|
||||
if recently_added_list:
|
||||
recently_added = recently_added_list['recently_added']
|
||||
|
||||
for item in recently_added:
|
||||
if int(item['added_at']) >= current_time - plexpy.CONFIG.MONITORING_INTERVAL:
|
||||
if item['media_type'] == 'movie':
|
||||
metadata_list = pms_connect.get_metadata_details(item['rating_key'])
|
||||
if metadata_list:
|
||||
metadata = [metadata_list['metadata']]
|
||||
else:
|
||||
logger.error(u"PlexPy Monitor :: Unable to retrieve metadata for rating_key %s" % str(item['rating_key']))
|
||||
|
||||
elif plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT:
|
||||
metadata_list = pms_connect.get_metadata_details(item['parent_rating_key'])
|
||||
if metadata_list:
|
||||
metadata = [metadata_list['metadata']]
|
||||
else:
|
||||
logger.error(u"PlexPy Monitor :: Unable to retrieve metadata for parent_rating_key %s" % str(item['parent_rating_key']))
|
||||
|
||||
else:
|
||||
metadata_list = pms_connect.get_metadata_children_details(item['rating_key'])
|
||||
if metadata_list:
|
||||
metadata = metadata_list['metadata']
|
||||
else:
|
||||
logger.error(u"PlexPy Monitor :: Unable to retrieve children metadata for rating_key" % str(item['rating_key']))
|
||||
|
||||
if metadata:
|
||||
for item in metadata:
|
||||
if (plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT \
|
||||
and int(item['updated_at']) >= current_time - plexpy.CONFIG.MONITORING_INTERVAL) \
|
||||
or (not plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT \
|
||||
and int(item['added_at']) >= current_time - plexpy.CONFIG.MONITORING_INTERVAL):
|
||||
logger.debug(u"PlexPy Monitor :: Library item %s has been added to Plex." % str(item['rating_key']))
|
||||
|
||||
# Fire off notifications
|
||||
threading.Thread(target=notification_handler.notify_timeline,
|
||||
kwargs=dict(timeline_data=item, notify_action='created')).start()
|
||||
|
|
|
@ -44,6 +44,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'BOXCAR_ON_RESUME': (int, 'Boxcar', 0),
|
||||
'BOXCAR_ON_BUFFER': (int, 'Boxcar', 0),
|
||||
'BOXCAR_ON_WATCHED': (int, 'Boxcar', 0),
|
||||
'BOXCAR_ON_CREATED': (int, 'Boxcar', 0),
|
||||
'BUFFER_THRESHOLD': (int, 'Monitoring', 3),
|
||||
'BUFFER_WAIT': (int, 'Monitoring', 900),
|
||||
'CACHE_DIR': (str, 'General', ''),
|
||||
|
@ -68,6 +69,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'EMAIL_ON_RESUME': (int, 'Email', 0),
|
||||
'EMAIL_ON_BUFFER': (int, 'Email', 0),
|
||||
'EMAIL_ON_WATCHED': (int, 'Email', 0),
|
||||
'EMAIL_ON_CREATED': (int, 'Email', 0),
|
||||
'ENABLE_HTTPS': (int, 'General', 0),
|
||||
'FIRST_RUN_COMPLETE': (int, 'General', 0),
|
||||
'FREEZE_DB': (int, 'General', 0),
|
||||
|
@ -84,6 +86,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'GROWL_ON_RESUME': (int, 'Growl', 0),
|
||||
'GROWL_ON_BUFFER': (int, 'Growl', 0),
|
||||
'GROWL_ON_WATCHED': (int, 'Growl', 0),
|
||||
'GROWL_ON_CREATED': (int, 'Growl', 0),
|
||||
'HOME_LIBRARY_CARDS': (str, 'General', 'library_statistics_first'),
|
||||
'HOME_STATS_LENGTH': (int, 'General', 30),
|
||||
'HOME_STATS_TYPE': (int, 'General', 0),
|
||||
|
@ -108,6 +111,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'IFTTT_ON_RESUME': (int, 'IFTTT', 0),
|
||||
'IFTTT_ON_BUFFER': (int, 'IFTTT', 0),
|
||||
'IFTTT_ON_WATCHED': (int, 'IFTTT', 0),
|
||||
'IFTTT_ON_CREATED': (int, 'IFTTT', 0),
|
||||
'JOURNAL_MODE': (str, 'Advanced', 'wal'),
|
||||
'LAUNCH_BROWSER': (int, 'General', 1),
|
||||
'LOG_DIR': (str, 'General', ''),
|
||||
|
@ -132,7 +136,9 @@ _CONFIG_DEFINITIONS = {
|
|||
'NMA_ON_RESUME': (int, 'NMA', 0),
|
||||
'NMA_ON_BUFFER': (int, 'NMA', 0),
|
||||
'NMA_ON_WATCHED': (int, 'NMA', 0),
|
||||
'NMA_ON_CREATED': (int, 'NMA', 0),
|
||||
'NOTIFY_CONSECUTIVE': (int, 'Monitoring', 1),
|
||||
'NOTIFY_RECENTLY_ADDED_GRANDPARENT': (int, 'Monitoring', 0),
|
||||
'NOTIFY_WATCHED_PERCENT': (int, 'Monitoring', 85),
|
||||
'NOTIFY_ON_START_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'),
|
||||
'NOTIFY_ON_START_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) started playing {title}.'),
|
||||
|
@ -146,6 +152,8 @@ _CONFIG_DEFINITIONS = {
|
|||
'NOTIFY_ON_BUFFER_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) is buffering {title}.'),
|
||||
'NOTIFY_ON_WATCHED_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'),
|
||||
'NOTIFY_ON_WATCHED_BODY_TEXT': (str, 'Monitoring', '{user} ({player}) has watched {title}.'),
|
||||
'NOTIFY_ON_CREATED_SUBJECT_TEXT': (str, 'Monitoring', 'PlexPy ({server_name})'),
|
||||
'NOTIFY_ON_CREATED_BODY_TEXT': (str, 'Monitoring', '{title} was recently added to Plex.'),
|
||||
'OSX_NOTIFY_APP': (str, 'OSX_Notify', '/Applications/PlexPy'),
|
||||
'OSX_NOTIFY_ENABLED': (int, 'OSX_Notify', 0),
|
||||
'OSX_NOTIFY_ON_PLAY': (int, 'OSX_Notify', 0),
|
||||
|
@ -154,6 +162,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'OSX_NOTIFY_ON_RESUME': (int, 'OSX_Notify', 0),
|
||||
'OSX_NOTIFY_ON_BUFFER': (int, 'OSX_Notify', 0),
|
||||
'OSX_NOTIFY_ON_WATCHED': (int, 'OSX_Notify', 0),
|
||||
'OSX_NOTIFY_ON_CREATED': (int, 'OSX_Notify', 0),
|
||||
'PLEX_CLIENT_HOST': (str, 'Plex', ''),
|
||||
'PLEX_ENABLED': (int, 'Plex', 0),
|
||||
'PLEX_PASSWORD': (str, 'Plex', ''),
|
||||
|
@ -164,6 +173,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'PLEX_ON_RESUME': (int, 'Plex', 0),
|
||||
'PLEX_ON_BUFFER': (int, 'Plex', 0),
|
||||
'PLEX_ON_WATCHED': (int, 'Plex', 0),
|
||||
'PLEX_ON_CREATED': (int, 'Plex', 0),
|
||||
'PROWL_ENABLED': (int, 'Prowl', 0),
|
||||
'PROWL_KEYS': (str, 'Prowl', ''),
|
||||
'PROWL_PRIORITY': (int, 'Prowl', 0),
|
||||
|
@ -173,6 +183,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'PROWL_ON_RESUME': (int, 'Prowl', 0),
|
||||
'PROWL_ON_BUFFER': (int, 'Prowl', 0),
|
||||
'PROWL_ON_WATCHED': (int, 'Prowl', 0),
|
||||
'PROWL_ON_CREATED': (int, 'Prowl', 0),
|
||||
'PUSHALOT_APIKEY': (str, 'Pushalot', ''),
|
||||
'PUSHALOT_ENABLED': (int, 'Pushalot', 0),
|
||||
'PUSHALOT_ON_PLAY': (int, 'Pushalot', 0),
|
||||
|
@ -181,6 +192,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'PUSHALOT_ON_RESUME': (int, 'Pushalot', 0),
|
||||
'PUSHALOT_ON_BUFFER': (int, 'Pushalot', 0),
|
||||
'PUSHALOT_ON_WATCHED': (int, 'Pushalot', 0),
|
||||
'PUSHALOT_ON_CREATED': (int, 'Pushalot', 0),
|
||||
'PUSHBULLET_APIKEY': (str, 'PushBullet', ''),
|
||||
'PUSHBULLET_DEVICEID': (str, 'PushBullet', ''),
|
||||
'PUSHBULLET_CHANNEL_TAG': (str, 'PushBullet', ''),
|
||||
|
@ -191,6 +203,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'PUSHBULLET_ON_RESUME': (int, 'PushBullet', 0),
|
||||
'PUSHBULLET_ON_BUFFER': (int, 'PushBullet', 0),
|
||||
'PUSHBULLET_ON_WATCHED': (int, 'PushBullet', 0),
|
||||
'PUSHBULLET_ON_CREATED': (int, 'PushBullet', 0),
|
||||
'PUSHOVER_APITOKEN': (str, 'Pushover', ''),
|
||||
'PUSHOVER_ENABLED': (int, 'Pushover', 0),
|
||||
'PUSHOVER_KEYS': (str, 'Pushover', ''),
|
||||
|
@ -202,6 +215,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'PUSHOVER_ON_RESUME': (int, 'Pushover', 0),
|
||||
'PUSHOVER_ON_BUFFER': (int, 'Pushover', 0),
|
||||
'PUSHOVER_ON_WATCHED': (int, 'Pushover', 0),
|
||||
'PUSHOVER_ON_CREATED': (int, 'Pushover', 0),
|
||||
'REFRESH_USERS_INTERVAL': (int, 'Monitoring', 12),
|
||||
'REFRESH_USERS_ON_STARTUP': (int, 'Monitoring', 1),
|
||||
'TV_NOTIFY_ENABLE': (int, 'Monitoring', 0),
|
||||
|
@ -218,6 +232,7 @@ _CONFIG_DEFINITIONS = {
|
|||
'TWITTER_ON_RESUME': (int, 'Twitter', 0),
|
||||
'TWITTER_ON_BUFFER': (int, 'Twitter', 0),
|
||||
'TWITTER_ON_WATCHED': (int, 'Twitter', 0),
|
||||
'TWITTER_ON_CREATED': (int, 'Twitter', 0),
|
||||
'UPDATE_DB_INTERVAL': (int, 'General', 24),
|
||||
'VERIFY_SSL_CERT': (bool_int, 'Advanced', 1),
|
||||
'VIDEO_LOGGING_ENABLE': (int, 'Monitoring', 1),
|
||||
|
@ -230,7 +245,8 @@ _CONFIG_DEFINITIONS = {
|
|||
'XBMC_ON_PAUSE': (int, 'XBMC', 0),
|
||||
'XBMC_ON_RESUME': (int, 'XBMC', 0),
|
||||
'XBMC_ON_BUFFER': (int, 'XBMC', 0),
|
||||
'XBMC_ON_WATCHED': (int, 'XBMC', 0)
|
||||
'XBMC_ON_WATCHED': (int, 'XBMC', 0),
|
||||
'XBMC_ON_CREATED': (int, 'XBMC', 0)
|
||||
}
|
||||
# pylint:disable=R0902
|
||||
# it might be nice to refactor for fewer instance variables
|
||||
|
|
|
@ -723,7 +723,7 @@ class DataFactory(object):
|
|||
actors = item['actors'].split(';') if item['actors'] else []
|
||||
genres = item['genres'].split(';') if item['genres'] else []
|
||||
|
||||
metadata = {'type': item['media_type'],
|
||||
metadata = {'media_type': item['media_type'],
|
||||
'rating_key': item['rating_key'],
|
||||
'parent_rating_key': item['parent_rating_key'],
|
||||
'grandparent_rating_key': item['grandparent_rating_key'],
|
||||
|
|
|
@ -43,7 +43,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='play', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_stop'] and notify_action == 'stop' \
|
||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < plexpy.CONFIG.NOTIFY_WATCHED_PERCENT):
|
||||
|
@ -53,7 +53,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
|
||||
set_notify_state(session=stream_data, state='stop', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_pause'] and notify_action == 'pause' \
|
||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
||||
|
@ -63,7 +63,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
|
||||
set_notify_state(session=stream_data, state='pause', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_resume'] and notify_action == 'resume' \
|
||||
and (plexpy.CONFIG.NOTIFY_CONSECUTIVE or progress_percent < 99):
|
||||
|
@ -73,7 +73,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
|
||||
set_notify_state(session=stream_data, state='resume', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_buffer'] and notify_action == 'buffer':
|
||||
# Build and send notification
|
||||
|
@ -82,7 +82,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
|
||||
set_notify_state(session=stream_data, state='buffer', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_watched'] and notify_action == 'watched':
|
||||
# Get the current states for notifications from our db
|
||||
|
@ -96,7 +96,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='watched', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
else:
|
||||
# Check in our notify log if the notification has already been sent
|
||||
|
@ -108,7 +108,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='watched', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif stream_data['media_type'] == 'track':
|
||||
if plexpy.CONFIG.MUSIC_NOTIFY_ENABLE:
|
||||
|
@ -121,7 +121,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='play', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_stop'] and notify_action == 'stop':
|
||||
# Build and send notification
|
||||
|
@ -130,7 +130,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='stop', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_pause'] and notify_action == 'pause':
|
||||
# Build and send notification
|
||||
|
@ -139,7 +139,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='pause', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_resume'] and notify_action == 'resume':
|
||||
# Build and send notification
|
||||
|
@ -148,7 +148,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='resume', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif agent['on_buffer'] and notify_action == 'buffer':
|
||||
# Build and send notification
|
||||
|
@ -157,7 +157,7 @@ def notify(stream_data=None, notify_action=None):
|
|||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=stream_data, state='buffer', agent_info=agent)
|
||||
set_notify_state(session=stream_data, state=notify_action, agent_info=agent)
|
||||
|
||||
elif stream_data['media_type'] == 'clip':
|
||||
pass
|
||||
|
@ -168,6 +168,25 @@ def notify(stream_data=None, notify_action=None):
|
|||
logger.debug(u"PlexPy Notifier :: Notify called but incomplete data received.")
|
||||
|
||||
|
||||
def notify_timeline(timeline_data=None, notify_action=None):
|
||||
if timeline_data and notify_action:
|
||||
for agent in notifiers.available_notification_agents():
|
||||
if agent['on_created'] and notify_action == 'created':
|
||||
if (plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT \
|
||||
and (timeline_data['media_type'] == 'movie' or timeline_data['media_type'] == 'show' or timeline_data['media_type'] == 'artist')) \
|
||||
or (not plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT \
|
||||
and (timeline_data['media_type'] == 'movie' or timeline_data['media_type'] == 'episode' or timeline_data['media_type'] == 'track')):
|
||||
# Build and send notification
|
||||
notify_strings = build_notify_text(timeline=timeline_data, state=notify_action)
|
||||
notifiers.send_notification(config_id=agent['id'],
|
||||
subject=notify_strings[0],
|
||||
body=notify_strings[1])
|
||||
# Set the notification state in the db
|
||||
set_notify_state(session=timeline_data, state=notify_action, agent_info=agent)
|
||||
else:
|
||||
logger.debug(u"PlexPy Notifier :: Notify timeline called but incomplete data received.")
|
||||
|
||||
|
||||
def get_notify_state(session):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
result = monitor_db.select('SELECT on_play, on_stop, on_pause, on_resume, on_buffer, on_watched, agent_id '
|
||||
|
@ -190,6 +209,21 @@ def get_notify_state(session):
|
|||
|
||||
return notify_states
|
||||
|
||||
def get_notify_state_timeline(timeline):
|
||||
monitor_db = database.MonitorDatabase()
|
||||
result = monitor_db.select('SELECT on_created, agent_id '
|
||||
'FROM notify_log '
|
||||
'WHERE rating_key = ? '
|
||||
'ORDER BY id DESC',
|
||||
args=[timeline['rating_key']])
|
||||
notify_states = []
|
||||
for item in result:
|
||||
notify_state = {'on_created': item[0],
|
||||
'agent_id': item[1]}
|
||||
notify_states.append(notify_state)
|
||||
|
||||
return notify_states
|
||||
|
||||
|
||||
def set_notify_state(session, state, agent_info):
|
||||
|
||||
|
@ -208,9 +242,16 @@ def set_notify_state(session, state, agent_info):
|
|||
values = {'on_buffer': int(time.time())}
|
||||
elif state == 'watched':
|
||||
values = {'on_watched': int(time.time())}
|
||||
elif state == 'created':
|
||||
values = {'on_created': int(time.time())}
|
||||
else:
|
||||
return
|
||||
|
||||
if state == 'created':
|
||||
keys = {'rating_key': session['rating_key'],
|
||||
'agent_id': agent_info['id'],
|
||||
'agent_name': agent_info['name']}
|
||||
else:
|
||||
keys = {'session_key': session['session_key'],
|
||||
'rating_key': session['rating_key'],
|
||||
'user_id': session['user_id'],
|
||||
|
@ -223,37 +264,49 @@ def set_notify_state(session, state, agent_info):
|
|||
logger.error('PlexPy Notifier :: Unable to set notify state.')
|
||||
|
||||
|
||||
def build_notify_text(session, state):
|
||||
def build_notify_text(session=None, timeline=None, state=None):
|
||||
from plexpy import pmsconnect, helpers
|
||||
import re
|
||||
|
||||
# Get the server name
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
server_name = pms_connect.get_server_pref(pref='FriendlyName')
|
||||
# If friendly name is blank
|
||||
if not server_name:
|
||||
servers_info = pms_connect.get_servers_info()
|
||||
for server in servers_info:
|
||||
if server['machine_identifier'] == plexpy.CONFIG.PMS_IDENTIFIER:
|
||||
server_name = server['name']
|
||||
break
|
||||
|
||||
# Get metadata feed for item
|
||||
metadata = pms_connect.get_metadata_details(rating_key=session['rating_key'])
|
||||
if session:
|
||||
rating_key = session['rating_key']
|
||||
elif timeline:
|
||||
rating_key = timeline['rating_key']
|
||||
|
||||
if metadata:
|
||||
item_metadata = metadata['metadata']
|
||||
metadata_list = pms_connect.get_metadata_details(rating_key=rating_key)
|
||||
|
||||
if metadata_list:
|
||||
metadata = metadata_list['metadata']
|
||||
else:
|
||||
logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(session['rating_key']))
|
||||
logger.error(u"PlexPy Notifier :: Unable to retrieve metadata for rating_key %s" % str(rating_key))
|
||||
return []
|
||||
|
||||
# Check for exclusion tags
|
||||
if session['media_type'] == 'episode':
|
||||
if metadata['media_type'] == 'episode':
|
||||
# Regex pattern to remove the text in the tags we don't want
|
||||
pattern = re.compile('<movie>[^>]+.</movie>|<music>[^>]+.</music>', re.IGNORECASE)
|
||||
elif session['media_type'] == 'movie':
|
||||
elif metadata['media_type'] == 'movie':
|
||||
# Regex pattern to remove the text in the tags we don't want
|
||||
pattern = re.compile('<tv>[^>]+.</tv>|<music>[^>]+.</music>', re.IGNORECASE)
|
||||
elif session['media_type'] == 'track':
|
||||
elif metadata['media_type'] == 'track':
|
||||
# Regex pattern to remove the text in the tags we don't want
|
||||
pattern = re.compile('<tv>[^>]+.</tv>|<movie>[^>]+.</movie>', re.IGNORECASE)
|
||||
else:
|
||||
pattern = None
|
||||
|
||||
if session['media_type'] == 'episode' or session['media_type'] == 'movie' or session['media_type'] == 'track' \
|
||||
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'movie' or metadata['media_type'] == 'track' \
|
||||
and pattern:
|
||||
# Remove the unwanted tags and strip any unmatch tags too.
|
||||
on_start_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT))
|
||||
|
@ -268,6 +321,8 @@ def build_notify_text(session, state):
|
|||
on_buffer_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT))
|
||||
on_watched_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT))
|
||||
on_watched_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT))
|
||||
on_created_subject = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT))
|
||||
on_created_body = strip_tag(re.sub(pattern, '', plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT))
|
||||
else:
|
||||
on_start_subject = plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT
|
||||
on_start_body = plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT
|
||||
|
@ -281,17 +336,28 @@ def build_notify_text(session, state):
|
|||
on_buffer_body = plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT
|
||||
on_watched_subject = plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT
|
||||
on_watched_body = plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT
|
||||
on_created_subject = plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT
|
||||
on_created_body = plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT
|
||||
|
||||
# Create a title
|
||||
if session['media_type'] == 'episode':
|
||||
full_title = '%s - %s' % (session['grandparent_title'],
|
||||
session['title'])
|
||||
elif session['media_type'] == 'track':
|
||||
full_title = '%s - %s' % (session['grandparent_title'],
|
||||
session['title'])
|
||||
if metadata['media_type'] == 'episode' or metadata['media_type'] == 'track':
|
||||
full_title = '%s - %s' % (metadata['grandparent_title'],
|
||||
metadata['title'])
|
||||
else:
|
||||
full_title = session['title']
|
||||
full_title = metadata['title']
|
||||
|
||||
duration = helpers.convert_milliseconds_to_minutes(metadata['duration'])
|
||||
|
||||
# Default values
|
||||
transcode_decision = ''
|
||||
stream_duration = 0
|
||||
view_offset = 0
|
||||
user = ''
|
||||
platform = ''
|
||||
player = ''
|
||||
|
||||
# Session values
|
||||
if session:
|
||||
# Generate a combined transcode decision value
|
||||
if session['video_decision']:
|
||||
if session['video_decision'] == 'transcode':
|
||||
|
@ -300,15 +366,12 @@ def build_notify_text(session, state):
|
|||
transcode_decision = 'Direct Stream'
|
||||
else:
|
||||
transcode_decision = 'Direct Play'
|
||||
else:
|
||||
elif session['audio_decision']:
|
||||
if session['audio_decision'] == 'transcode':
|
||||
transcode_decision = 'Transcode'
|
||||
else:
|
||||
transcode_decision = 'Direct Play'
|
||||
|
||||
duration = helpers.convert_milliseconds_to_minutes(item_metadata['duration'])
|
||||
view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
|
||||
stream_duration = 0
|
||||
if state != 'play':
|
||||
if session['paused_counter']:
|
||||
stream_duration = int((time.time() - helpers.cast_to_float(session['started']) -
|
||||
|
@ -316,28 +379,33 @@ def build_notify_text(session, state):
|
|||
else:
|
||||
stream_duration = int((time.time() - helpers.cast_to_float(session['started'])) / 60)
|
||||
|
||||
view_offset = helpers.convert_milliseconds_to_minutes(session['view_offset'])
|
||||
user = session['friendly_name']
|
||||
platform = session['platform']
|
||||
player = session['player']
|
||||
|
||||
progress_percent = helpers.get_percent(view_offset, duration)
|
||||
|
||||
available_params = {'server_name': server_name,
|
||||
'user': session['friendly_name'],
|
||||
'platform': session['platform'],
|
||||
'player': session['player'],
|
||||
'media_type': session['media_type'],
|
||||
'user': user,
|
||||
'platform': platform,
|
||||
'player': player,
|
||||
'media_type': metadata['media_type'],
|
||||
'title': full_title,
|
||||
'show_name': item_metadata['grandparent_title'],
|
||||
'episode_name': item_metadata['title'],
|
||||
'artist_name': item_metadata['grandparent_title'],
|
||||
'album_name': item_metadata['parent_title'],
|
||||
'season_num': item_metadata['parent_index'],
|
||||
'season_num00': item_metadata['parent_index'].zfill(2),
|
||||
'episode_num': item_metadata['index'],
|
||||
'episode_num00': item_metadata['index'].zfill(2),
|
||||
'show_name': metadata['grandparent_title'],
|
||||
'episode_name': metadata['title'],
|
||||
'artist_name': metadata['grandparent_title'],
|
||||
'album_name': metadata['parent_title'],
|
||||
'season_num': metadata['parent_index'],
|
||||
'season_num00': metadata['parent_index'].zfill(2),
|
||||
'episode_num': metadata['index'],
|
||||
'episode_num00': metadata['index'].zfill(2),
|
||||
'transcode_decision': transcode_decision,
|
||||
'year': item_metadata['year'],
|
||||
'studio': item_metadata['studio'],
|
||||
'content_rating': item_metadata['content_rating'],
|
||||
'summary': item_metadata['summary'],
|
||||
'rating': item_metadata['rating'],
|
||||
'year': metadata['year'],
|
||||
'studio': metadata['studio'],
|
||||
'content_rating': metadata['content_rating'],
|
||||
'summary': metadata['summary'],
|
||||
'rating': metadata['rating'],
|
||||
'duration': duration,
|
||||
'stream_duration': stream_duration,
|
||||
'remaining_duration': duration - view_offset,
|
||||
|
@ -489,6 +557,28 @@ def build_notify_text(session, state):
|
|||
except:
|
||||
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
|
||||
|
||||
return [subject_text, body_text]
|
||||
else:
|
||||
return [subject_text, body_text]
|
||||
elif state == 'created':
|
||||
# Default body text
|
||||
body_text = '%s was recently added to Plex.' % full_title
|
||||
|
||||
if on_created_subject and on_created_body:
|
||||
try:
|
||||
subject_text = unicode(on_created_subject).format(**available_params)
|
||||
except LookupError, e:
|
||||
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification subject. Using fallback." % e)
|
||||
except:
|
||||
logger.error(u"PlexPy Notifier :: Unable to parse custom notification subject. Using fallback.")
|
||||
|
||||
try:
|
||||
body_text = unicode(on_created_body).format(**available_params)
|
||||
except LookupError, e:
|
||||
logger.error(u"PlexPy Notifier :: Unable to parse field %s in notification body. Using fallback." % e)
|
||||
except:
|
||||
logger.error(u"PlexPy Notifier :: Unable to parse custom notification body. Using fallback.")
|
||||
|
||||
return [subject_text, body_text]
|
||||
else:
|
||||
return [subject_text, body_text]
|
||||
|
|
|
@ -64,7 +64,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.GROWL_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.GROWL_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.GROWL_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.GROWL_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.GROWL_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.GROWL_ON_CREATED
|
||||
},
|
||||
{'name': 'Prowl',
|
||||
'id': AGENT_IDS['Prowl'],
|
||||
|
@ -76,7 +77,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.PROWL_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.PROWL_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.PROWL_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.PROWL_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.PROWL_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.PROWL_ON_CREATED
|
||||
},
|
||||
{'name': 'XBMC',
|
||||
'id': AGENT_IDS['XBMC'],
|
||||
|
@ -88,7 +90,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.XBMC_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.XBMC_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.XBMC_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.XBMC_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.XBMC_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.XBMC_ON_CREATED
|
||||
},
|
||||
{'name': 'Plex',
|
||||
'id': AGENT_IDS['Plex'],
|
||||
|
@ -100,7 +103,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.PLEX_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.PLEX_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.PLEX_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.PLEX_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.PLEX_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.PLEX_ON_CREATED
|
||||
},
|
||||
{'name': 'NotifyMyAndroid',
|
||||
'id': AGENT_IDS['NMA'],
|
||||
|
@ -112,7 +116,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.NMA_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.NMA_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.NMA_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.NMA_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.NMA_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.NMA_ON_CREATED
|
||||
},
|
||||
{'name': 'Pushalot',
|
||||
'id': AGENT_IDS['Pushalot'],
|
||||
|
@ -124,7 +129,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.PUSHALOT_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.PUSHALOT_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.PUSHALOT_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.PUSHALOT_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.PUSHALOT_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.PUSHALOT_ON_CREATED
|
||||
},
|
||||
{'name': 'Pushbullet',
|
||||
'id': AGENT_IDS['Pushbullet'],
|
||||
|
@ -136,7 +142,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.PUSHBULLET_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.PUSHBULLET_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.PUSHBULLET_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.PUSHBULLET_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.PUSHBULLET_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.PUSHBULLET_ON_CREATED
|
||||
},
|
||||
{'name': 'Pushover',
|
||||
'id': AGENT_IDS['Pushover'],
|
||||
|
@ -148,7 +155,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.PUSHOVER_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.PUSHOVER_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.PUSHOVER_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.PUSHOVER_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.PUSHOVER_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.PUSHOVER_ON_CREATED
|
||||
},
|
||||
{'name': 'Boxcar2',
|
||||
'id': AGENT_IDS['Boxcar2'],
|
||||
|
@ -160,7 +168,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.BOXCAR_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.BOXCAR_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.BOXCAR_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.BOXCAR_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.BOXCAR_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.BOXCAR_ON_CREATED
|
||||
},
|
||||
{'name': 'E-mail',
|
||||
'id': AGENT_IDS['Email'],
|
||||
|
@ -172,7 +181,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.EMAIL_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.EMAIL_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.EMAIL_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.EMAIL_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.EMAIL_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.EMAIL_ON_CREATED
|
||||
},
|
||||
{'name': 'Twitter',
|
||||
'id': AGENT_IDS['Twitter'],
|
||||
|
@ -184,7 +194,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.TWITTER_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.TWITTER_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.TWITTER_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.TWITTER_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.TWITTER_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.TWITTER_ON_CREATED
|
||||
},
|
||||
{'name': 'IFTTT',
|
||||
'id': AGENT_IDS['IFTTT'],
|
||||
|
@ -196,7 +207,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.IFTTT_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.IFTTT_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.IFTTT_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.IFTTT_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.IFTTT_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.IFTTT_ON_CREATED
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -213,7 +225,8 @@ def available_notification_agents():
|
|||
'on_pause': plexpy.CONFIG.OSX_NOTIFY_ON_PAUSE,
|
||||
'on_resume': plexpy.CONFIG.OSX_NOTIFY_ON_RESUME,
|
||||
'on_buffer': plexpy.CONFIG.OSX_NOTIFY_ON_BUFFER,
|
||||
'on_watched': plexpy.CONFIG.OSX_NOTIFY_ON_WATCHED
|
||||
'on_watched': plexpy.CONFIG.OSX_NOTIFY_ON_WATCHED,
|
||||
'on_created': plexpy.CONFIG.OSX_NOTIFY_ON_CREATED
|
||||
})
|
||||
|
||||
return agents
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This file is part of PlexPy.
|
||||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -247,6 +247,8 @@ def import_from_plexwatch(database=None, table_name=None, import_ignore_interval
|
|||
logger.debug(u"PlexPy Importer :: Disabling monitoring while import in progress.")
|
||||
plexpy.schedule_job(activity_pinger.check_active_sessions, 'Check for active sessions',
|
||||
hours=0, minutes=0, seconds=0)
|
||||
plexpy.schedule_job(activity_pinger.check_recently_added, 'Check for recently added items',
|
||||
hours=0, minutes=0, seconds=0)
|
||||
|
||||
ap = activity_processor.ActivityProcessor()
|
||||
user_data = users.Users()
|
||||
|
|
|
@ -281,10 +281,13 @@ class PmsConnect(object):
|
|||
recents_main = a.getElementsByTagName('Directory')
|
||||
for item in recents_main:
|
||||
recent_type = helpers.get_xml_attr(item, 'type')
|
||||
recent_items = {'type': recent_type,
|
||||
recent_items = {'media_type': recent_type,
|
||||
'rating_key': helpers.get_xml_attr(item, 'ratingKey'),
|
||||
'parent_rating_key': helpers.get_xml_attr(item, 'parentRatingKey'),
|
||||
'title': helpers.get_xml_attr(item, 'title'),
|
||||
'parent_title': helpers.get_xml_attr(item, 'parentTitle'),
|
||||
'library_id': helpers.get_xml_attr(item, 'librarySectionID'),
|
||||
'library_title': helpers.get_xml_attr(item, 'librarySectionTitle'),
|
||||
'thumb': helpers.get_xml_attr(item, 'thumb'),
|
||||
'added_at': helpers.get_xml_attr(item, 'addedAt')
|
||||
}
|
||||
|
@ -296,10 +299,12 @@ class PmsConnect(object):
|
|||
recent_type = helpers.get_xml_attr(item, 'type')
|
||||
|
||||
if recent_type == 'movie':
|
||||
recent_items = {'type': recent_type,
|
||||
recent_items = {'media_type': recent_type,
|
||||
'rating_key': helpers.get_xml_attr(item, 'ratingKey'),
|
||||
'title': helpers.get_xml_attr(item, 'title'),
|
||||
'parent_title': helpers.get_xml_attr(item, 'parentTitle'),
|
||||
'library_id': helpers.get_xml_attr(item, 'librarySectionID'),
|
||||
'library_title': helpers.get_xml_attr(item, 'librarySectionTitle'),
|
||||
'year': helpers.get_xml_attr(item, 'year'),
|
||||
'thumb': helpers.get_xml_attr(item, 'thumb'),
|
||||
'added_at': helpers.get_xml_attr(item, 'addedAt')
|
||||
|
@ -369,7 +374,7 @@ class PmsConnect(object):
|
|||
directors.append(helpers.get_xml_attr(director, 'tag'))
|
||||
|
||||
if metadata_type == 'show':
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
||||
|
@ -401,7 +406,7 @@ class PmsConnect(object):
|
|||
elif metadata_type == 'season':
|
||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||
show_details = self.get_metadata_details(parent_rating_key)
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
|
||||
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||
|
@ -432,7 +437,7 @@ class PmsConnect(object):
|
|||
}
|
||||
metadata_list = {'metadata': metadata}
|
||||
elif metadata_type == 'episode':
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
|
||||
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
|
||||
|
@ -464,7 +469,7 @@ class PmsConnect(object):
|
|||
}
|
||||
metadata_list = {'metadata': metadata}
|
||||
elif metadata_type == 'movie':
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
||||
|
@ -494,7 +499,7 @@ class PmsConnect(object):
|
|||
}
|
||||
metadata_list = {'metadata': metadata}
|
||||
elif metadata_type == 'artist':
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||
'parent_index': helpers.get_xml_attr(metadata_main, 'parentIndex'),
|
||||
|
@ -526,7 +531,7 @@ class PmsConnect(object):
|
|||
elif metadata_type == 'album':
|
||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||
artist_details = self.get_metadata_details(parent_rating_key)
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
|
||||
'grandparent_title': helpers.get_xml_attr(metadata_main, 'grandparentTitle'),
|
||||
|
@ -559,7 +564,7 @@ class PmsConnect(object):
|
|||
elif metadata_type == 'track':
|
||||
parent_rating_key = helpers.get_xml_attr(metadata_main, 'parentRatingKey')
|
||||
album_details = self.get_metadata_details(parent_rating_key)
|
||||
metadata = {'type': metadata_type,
|
||||
metadata = {'media_type': metadata_type,
|
||||
'rating_key': helpers.get_xml_attr(metadata_main, 'ratingKey'),
|
||||
'parent_rating_key': helpers.get_xml_attr(metadata_main, 'parentRatingKey'),
|
||||
'grandparent_rating_key': helpers.get_xml_attr(metadata_main, 'grandparentRatingKey'),
|
||||
|
@ -595,6 +600,49 @@ class PmsConnect(object):
|
|||
|
||||
return metadata_list
|
||||
|
||||
"""
|
||||
Return processed and validated metadata list for all children of requested item.
|
||||
|
||||
Parameters required: rating_key { Plex ratingKey }
|
||||
|
||||
Output: array
|
||||
"""
|
||||
def get_metadata_children_details(self, rating_key=''):
|
||||
metadata = self.get_metadata_children(str(rating_key), output_format='xml')
|
||||
|
||||
try:
|
||||
xml_head = metadata.getElementsByTagName('MediaContainer')
|
||||
except:
|
||||
logger.warn("Unable to parse XML for get_metadata_children.")
|
||||
return []
|
||||
|
||||
metadata_list = []
|
||||
|
||||
for a in xml_head:
|
||||
if a.getAttribute('size'):
|
||||
if a.getAttribute('size') == '0':
|
||||
metadata_list = {'metadata': None}
|
||||
return metadata_list
|
||||
|
||||
if a.getElementsByTagName('Video'):
|
||||
metadata_main = a.getElementsByTagName('Video')
|
||||
for item in metadata_main:
|
||||
child_rating_key = helpers.get_xml_attr(item, 'ratingKey')
|
||||
metadata = self.get_metadata_details(str(child_rating_key))
|
||||
if metadata:
|
||||
metadata_list.append(metadata['metadata'])
|
||||
|
||||
elif a.getElementsByTagName('Track'):
|
||||
metadata_main = a.getElementsByTagName('Track')
|
||||
for item in metadata_main:
|
||||
child_rating_key = helpers.get_xml_attr(item, 'ratingKey')
|
||||
metadata = self.get_metadata_details(str(child_rating_key))
|
||||
if metadata:
|
||||
metadata_list.append(metadata['metadata'])
|
||||
|
||||
output = {'metadata': metadata_list}
|
||||
return output
|
||||
|
||||
"""
|
||||
Return processed and validated session list.
|
||||
|
||||
|
@ -1429,9 +1477,9 @@ class PmsConnect(object):
|
|||
for result in result_data:
|
||||
rating_key = helpers.get_xml_attr(result, 'ratingKey')
|
||||
metadata = self.get_metadata_details(rating_key=rating_key)
|
||||
if metadata['metadata']['type'] == 'movie':
|
||||
if metadata['metadata']['media_type'] == 'movie':
|
||||
search_results_list['movie'].append(metadata['metadata'])
|
||||
elif metadata['metadata']['type'] == 'episode':
|
||||
elif metadata['metadata']['media_type'] == 'episode':
|
||||
search_results_list['episode'].append(metadata['metadata'])
|
||||
search_results_count += 1
|
||||
|
||||
|
@ -1440,7 +1488,7 @@ class PmsConnect(object):
|
|||
for result in result_data:
|
||||
rating_key = helpers.get_xml_attr(result, 'ratingKey')
|
||||
metadata = self.get_metadata_details(rating_key=rating_key)
|
||||
if metadata['metadata']['type'] == 'show':
|
||||
if metadata['metadata']['media_type'] == 'show':
|
||||
search_results_list['show'].append(metadata['metadata'])
|
||||
|
||||
show_seasons = self.get_item_children(rating_key=metadata['metadata']['rating_key'])
|
||||
|
@ -1452,9 +1500,9 @@ class PmsConnect(object):
|
|||
search_results_list['season'].append(metadata['metadata'])
|
||||
search_results_count += 1
|
||||
|
||||
elif metadata['metadata']['type'] == 'artist':
|
||||
elif metadata['metadata']['media_type'] == 'artist':
|
||||
search_results_list['artist'].append(metadata['metadata'])
|
||||
elif metadata['metadata']['type'] == 'album':
|
||||
elif metadata['metadata']['media_type'] == 'album':
|
||||
search_results_list['album'].append(metadata['metadata'])
|
||||
search_results_count += 1
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# This file is part of PlexPy.
|
||||
# This file is part of PlexPy.
|
||||
#
|
||||
# PlexPy is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
|
@ -139,4 +139,14 @@ def process(opcode, data):
|
|||
activity = activity_handler.ActivityHandler(timeline=time_line[0])
|
||||
activity.process()
|
||||
|
||||
if type == 'timeline':
|
||||
try:
|
||||
time_line = info.get('_children')
|
||||
except:
|
||||
logger.debug(u"PlexPy WebSocket :: Timeline event found but unable to get timeline data.")
|
||||
return False
|
||||
|
||||
activity = activity_handler.TimelineHandler(timeline=time_line[0])
|
||||
activity.process()
|
||||
|
||||
return True
|
||||
|
|
|
@ -442,6 +442,7 @@ class WebInterface(object):
|
|||
"logging_ignore_interval": plexpy.CONFIG.LOGGING_IGNORE_INTERVAL,
|
||||
"pms_is_remote": checked(plexpy.CONFIG.PMS_IS_REMOTE),
|
||||
"notify_consecutive": checked(plexpy.CONFIG.NOTIFY_CONSECUTIVE),
|
||||
"notify_recently_added_grandparent": checked(plexpy.CONFIG.NOTIFY_RECENTLY_ADDED_GRANDPARENT),
|
||||
"notify_watched_percent": plexpy.CONFIG.NOTIFY_WATCHED_PERCENT,
|
||||
"notify_on_start_subject_text": plexpy.CONFIG.NOTIFY_ON_START_SUBJECT_TEXT,
|
||||
"notify_on_start_body_text": plexpy.CONFIG.NOTIFY_ON_START_BODY_TEXT,
|
||||
|
@ -455,6 +456,8 @@ class WebInterface(object):
|
|||
"notify_on_buffer_body_text": plexpy.CONFIG.NOTIFY_ON_BUFFER_BODY_TEXT,
|
||||
"notify_on_watched_subject_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_SUBJECT_TEXT,
|
||||
"notify_on_watched_body_text": plexpy.CONFIG.NOTIFY_ON_WATCHED_BODY_TEXT,
|
||||
"notify_on_created_subject_text": plexpy.CONFIG.NOTIFY_ON_CREATED_SUBJECT_TEXT,
|
||||
"notify_on_created_body_text": plexpy.CONFIG.NOTIFY_ON_CREATED_BODY_TEXT,
|
||||
"home_stats_length": plexpy.CONFIG.HOME_STATS_LENGTH,
|
||||
"home_stats_type": checked(plexpy.CONFIG.HOME_STATS_TYPE),
|
||||
"home_stats_count": plexpy.CONFIG.HOME_STATS_COUNT,
|
||||
|
@ -479,7 +482,7 @@ class WebInterface(object):
|
|||
"tv_notify_on_stop", "movie_notify_on_stop", "music_notify_on_stop",
|
||||
"tv_notify_on_pause", "movie_notify_on_pause", "music_notify_on_pause", "refresh_users_on_startup",
|
||||
"ip_logging_enable", "video_logging_enable", "music_logging_enable", "pms_is_remote", "home_stats_type",
|
||||
"group_history_tables", "notify_consecutive"
|
||||
"group_history_tables", "notify_consecutive", "notify_recently_added_grandparent"
|
||||
]
|
||||
for checked_config in checked_configs:
|
||||
if checked_config not in kwargs:
|
||||
|
@ -788,11 +791,11 @@ class WebInterface(object):
|
|||
data_factory = datafactory.DataFactory()
|
||||
metadata = data_factory.get_metadata_details(row_id=item_id)
|
||||
elif item_id == 'movie':
|
||||
metadata = {'type': 'library', 'library': 'movie', 'media_type': 'movie', 'title': 'Movies'}
|
||||
metadata = {'media_type': 'library', 'library': 'movie', 'media_type_filter': 'movie', 'title': 'Movies'}
|
||||
elif item_id == 'show':
|
||||
metadata = {'type': 'library', 'library': 'show', 'media_type': 'episode', 'title': 'TV Shows'}
|
||||
metadata = {'media_type': 'library', 'library': 'show', 'media_type_filter': 'episode', 'title': 'TV Shows'}
|
||||
elif item_id == 'artist':
|
||||
metadata = {'type': 'library', 'library': 'artist', 'media_type': 'track', 'title': 'Music'}
|
||||
metadata = {'media_type': 'library', 'library': 'artist', 'media_type_filter': 'track', 'title': 'Music'}
|
||||
else:
|
||||
pms_connect = pmsconnect.PmsConnect()
|
||||
result = pms_connect.get_metadata_details(rating_key=item_id)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue